def __bytes__(self): # Write the header self.pointer_data = {'headers': list(), 'data': list()} self._bytes = BytesIO(b'') # Write each of the sections self._write_header() self._write_map_layout_pointer() self._write_moving_platform_data_pointers() self._write_pushblocks_pointers() self._write_map_layers_pointer() self._write_gimmick_data_pointer() p = Pointer(self._bytes) p.assign_data(lambda _data: write_int32(_data, 0)) self.pointer_data['headers'].append(p) write_int32(self._bytes, 0) self._write_event_data_pointer() # write all the pointer data. Do all headers then do data # swap entries 30 and 32 for some reason?!? self.pointer_data['headers'] = swap(self.pointer_data['headers'], 30, 32) for pointer in self.pointer_data['headers']: pointer.write() for pointer in self.pointer_data['data']: pointer.write() # write the final file size self._bytes.seek(0x8) _bytes = self._bytes.getvalue() write_int32(self._bytes, len(_bytes)) del _bytes return self._bytes.getvalue()
def _write_pushblocks_pointers(self): for pb in self.pushblocks: p = Pointer(self._bytes) p.assign_data( lambda _data, pb=pb: self._write_pushblocks(_data, pb)) self.pointer_data['headers'].append(p) write_int32(self._bytes, 0)
def _read_event_data(self, fobj): self.events = list() with Pointer(fobj): count = read_int32(fobj) for _ in range(count): with Pointer(fobj): self.events.append(EventSequenceData(fobj))
def _write_map_layer_info(self, data, layer_data): write_int32(data, self.height * self.width) p = Pointer(self._bytes) p.assign_data( lambda _data: self._write_map_layer(_data, layer_data)) self.pointer_data['data'].append(p) write_int32(data, 0)
def _write_moving_platform_data_pointers(self): for mp in self.moving_platforms: p = Pointer(self._bytes) p.assign_data( lambda _data, mp=mp: self._write_moving_platform_data( _data, mp)) self.pointer_data['headers'].append(p) write_int32(self._bytes, 0)
def _write_map_layout_info(self, data): write_int32(data, self.width) write_int32(data, self.height) write_int32(data, self.height * self.width) p = Pointer(self._bytes) p.assign_data(self._write_map_layout) self.pointer_data['data'].append(p) write_int32(data, 0)
def _write_map_layers_pointer(self): for i in range(0x7): p = Pointer(self._bytes) layer_data = getattr(self, 'layer{0}_data'.format(str(i))) p.assign_data( lambda _data, layer_data=layer_data: self._write_map_layer_info( # noqa _data, layer_data)) self.pointer_data['headers'].append(p) write_int32(self._bytes, 0)
def _write_event_data_info(self, data): write_int32(data, len(self.events)) for event in self.events: p = Pointer(self._bytes) p.assign_data( lambda _data, event=event: self._write_event_data( _data, event)) self.pointer_data['headers'].append(p) write_int32(data, 0)
def _read_data(self, fobj): fobj.seek(0x1C) count = read_int32(fobj) with Pointer(fobj): for _ in range(count): with Pointer(fobj): name = read_name(fobj).decode('utf') print(name) with Pointer(fobj): self._extract_xbin(fobj, name)
def _read_map_layers(self, fobj): """ Read all of the map layers into variables """ for i in range(0x7): data = list() with Pointer(fobj): # skip the size fobj.seek(0x4, 1) with Pointer(fobj): for y in range(self.height): data.append(list()) for _ in range(self.width): data[y].append(read_int32(fobj)) # flip the data verically data = data[::-1] # assign to a variable setattr(self, 'layer{0}_data'.format(str(i)), data)
def _read_gimmick_data(self, fobj): self.gimmick_data = list() with Pointer(fobj): count = read_int32(fobj) for _ in range(count): gimmick_bytes = BytesIO(fobj.read(0x30)) self.gimmick_data.append(gimmick_factory(gimmick_bytes))
def _read_map_layout(self, fobj): """ Load the map layout. """ with Pointer(fobj): self.width, self.height = struct.unpack('<II', fobj.read(0x8)) # ignore the number of entries as it is simply width * height _, offset = struct.unpack('<II', fobj.read(0x8)) fobj.seek(offset) self.map_layout = list() for y in range(self.height): self.map_layout.append(list()) for _ in range(self.width): self.map_layout[y].append(read_int32(fobj)) self.map_layout = self.map_layout[::-1]
def _read_data(self, fobj): # print('reading data at {0}'.format(hex(fobj.tell()))) dtype = read_int32(fobj) if dtype == 1: # read an int data = read_int32(fobj) # maybe different dtypes? elif dtype == 2: # read a float data = read_float32(fobj) elif dtype == 3: # read a boolean values data = bool(read_byte(fobj)) elif dtype == 4: # Pointer to byte array? data = list() with Pointer(fobj): data = self._read_name(fobj).decode('utf') elif dtype == 5: data = list() count = read_int32(fobj) for _ in range(count): with Pointer(fobj): name = self._read_name(fobj).decode('utf') with Pointer(fobj): new_data = self._read_data(fobj) data.append({name: new_data}) elif dtype == 6: data = list() count = read_int32(fobj) for _ in range(count): with Pointer(fobj): data.append(self._read_data(fobj)) else: print(dtype, hex(fobj.tell())) data = None return data
def _read_header(self, fobj): data = '' self.magic = struct.unpack('4s', fobj.read(0x4))[0] # 0x00 if not self.magic == b'XBIN': raise ValueError('Provided file is not a valid BoxBoy map file') self.version = read_int32(fobj) # 0x04 self.filesize = read_int32(fobj) # 0x08 self.unknown_value0 = read_int32(fobj) # 0x0C with Pointer(fobj): # 0x10 self.filename = read_name(fobj) self.unknown_value1 = read_int32(fobj) # 0x14 with Pointer(fobj): # 0x18 count = read_int32(fobj) self.unknown_bytes = fobj.read(count * 4) with Pointer(fobj): # 0x1C count = read_int32(fobj) for _ in range(count): with Pointer(fobj): with Pointer(fobj): attribute = read_name(fobj) data += attribute.decode('utf') + '\n' read_int32(fobj) read_int32(fobj) read_int32(fobj) with Pointer(fobj): count = read_int32(fobj) for _ in range(count): with Pointer(fobj): with Pointer(fobj): enum_name = read_name(fobj).decode('utf') enum_value = read_int32(fobj) data += (str(enum_name) + '\t' + str(enum_value) + '\n') if len(data) != 0: with open(self.fpath.replace('xbin', 'txt'), 'w') as f: f.write(data)
def _read_moving_platform_data(self, fobj): self.moving_platforms = list() for _ in range(0x14): with Pointer(fobj): self.moving_platforms.append(MovingPlatform(fobj))
def _read_pushblocks(self, fobj): self.pushblocks = list() for _ in range(0x8): with Pointer(fobj): self.pushblocks.append(PushBlock(fobj))
def _write_map_layout_pointer(self): p = Pointer(self._bytes) p.assign_data(self._write_map_layout_info) self.pointer_data['headers'].append(p) write_int32(self._bytes, 0)
def _write_event_data_pointer(self): p = Pointer(self._bytes) p.assign_data(lambda _data: self._write_event_data_info(_data)) self.pointer_data['headers'].append(p) write_int32(self._bytes, 0)