def load(data: ScnDataReader) -> List[ColorTable]: """ Read in all of the colors """ data.mark(name='colors') num_color_tables = data.uint16(debug='num_color_tables') return [ColorTable.read(data) for _ in range(0, num_color_tables)]
def load(data: ScnDataReader) -> List[Effect]: """ Read all effects from here """ data.mark("effects") num_effects = data.uint32() return [Effect.read(data) for _ in range(0, num_effects)]
def read(data: ScnDataReader): id = data.uint16(debug='sound_id') play_delay = data.uint16(debug='sound_play_delay') num_items = data.uint16(debug='sound_num_items') cache_time = data.uint32() items = [SoundItem.read(data) for _ in range(0, num_items)] return Sound(id, play_delay, cache_time, items)
def load(data: ScnDataReader) -> List[Technology]: """ Read all technologies from here """ data.mark('technologies') num_techs = data.int16(debug='num_techs') return [Technology.read(data) for _ in range(0, num_techs)]
def read(data: ScnDataReader): field1 = data.string16(debug='player_name_repeated') field2 = data.float32(debug='unknown field 1') field3 = data.float32(debug='unknown field 2') field4 = data.uint16(debug='unknown field 3') field5 = data.uint16(debug='unknown field 4') field6 = data.uint8(debug='unknown field 5') field7 = data.uint16(debug='unknown field 6') field8 = [] for j in range(0, 9): something = data.uint8(debug='unknown field {}'.format(j)) field8.append(something) field9 = [] for j in range(0, 9): something = data.uint32(debug='unknown field {}'.format(j)) field9.append(something) field10 = data.float32(debug="unknown field") # 1.00 field11 = data.float32( debug="unknown field" ) # only seen 0. guess this could be float as well ? field12 = [] for j in range( 0, 9 ): # all 0's. guessing it could hold another list of 9 values? something = data.uint8(debug='unknown field {}'.format(j)) field12.append(something) return UnknownPlayerDataStructure(field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12)
def discard_extra_map_stuff(data: ScnDataReader): data.mark("Extra map stuff") # NB: Values from genie-rs skip way past random map data in AOE1 files. # data.int32(debug='_map_row_offset') # data.float32(debug='_map_min_x') # data.float32(debug='_map_min_y') # data.float32(debug='_map_max_x') # data.float32(debug='_map_max_y') # data.float32(debug='_map_max_x') # data.float32(debug='_map_max_y') # data.uint16(debug='_additional_terrain_count') # data.uint16(debug='_borders_used') # data.uint16(debug='_max_terrain') # data.uint16(debug='_tile_width') # data.uint16(debug='_tile_height') # data.uint16(debug='_tile_half_width') # data.uint16(debug='_tile_half_height') # data.uint16(debug='_elev_height') # data.uint16(debug='_current_row') # data.uint16(debug='_current_column') # data.uint16(debug='_block_begin_row') # data.uint16(debug='_block_end_row') # data.uint16(debug='_block_begin_column') # data.uint16(debug='_block_end_column') # data.int32(debug='_seach_map_pointer') # data.int32(debug='_seach_map_rows_pointer') # data.uint8(debug='_any_frame_change') # data.uint8(debug='_map_visible') # data.uint8(debug='_map_fog_of_war') # data.read(21 + 157 * 4) data.read(68)
def read(data: ScnDataReader): width = data.uint32() height = data.uint32() tiles = [] for i in range(0, height * width): tiles.append(ScnMapTile.read(data)) return ScnMap(width, height, tiles)
def read(data: ScnDataReader): color_table_name = data.string_fixed(30, debug='color_table_name') color_table_id = data.uint16(debug='color_table_id') drs_res = data.uint16(debug='color_table_drs_res') # All blanks? minimap_color = data.uint8(debug='color_table_minimap_color') # Possibly a minimap color? color_table_type = data.uint8(debug='color_table_type') # All 1's except the last one, which is 2. return ColorTable(color_table_name, color_table_id, drs_res, minimap_color, color_table_type)
def read(data: ScnDataReader): random_map_num_objects = data.uint32(debug='random_map_num_objects') pointer = data.uint32() items = [RandomMapObject.read(data) for _ in range(0, random_map_num_objects)] return RandomMapObjectListWrapper( pointer, items )
def read(data: ScnDataReader): random_map_num_terrains = data.int32(debug='random_map_terrain_count') # could be land ID?? pointer = data.uint32(debug='random_map_terrain_pointer') items = [RandomMapTerrain.read(data) for _ in range(0, random_map_num_terrains)] return RandomMapTerrainListWrapper( pointer, items )
def read(data: ScnDataReader): random_map_num_lands = data.int32(debug='random_map_land_count') pointer = data.uint32(debug='random_map_land_pointer') items = [RandomMapLand.read(data) for _ in range(0, random_map_num_lands)] return RandomMapLandListWrapper( pointer, items )
def read(data: ScnDataReader): # Not present in AOE1 data file, a bit of a guess random_map_num_elevations = data.uint32(debug='random_map_num_elevations') pointer = data.uint32(debug='random_map_elevation_pointer') items = [RandomMapElevation.read(data) for _ in range(0, random_map_num_elevations)] return RandomMapElevationListWrapper( pointer, items )
def read(data: ScnDataReader): effect_comamnd_type = data.uint8() effect_params = ( data.int16(), data.int16(), data.int16(), data.float32() ) return EffectCommand(effect_comamnd_type, effect_params)
def read_classic(data: ScnDataReader, player_version: float): return WorldPlayer( data.float32() if player_version > 1.06 else 200.0, data.float32() if player_version > 1.06 else 200.0, data.float32() if player_version > 1.06 else 50.0, data.float32() if player_version > 1.06 else 100.0, data.float32() if player_version > 1.12 else 100.0, data.float32() if player_version > 1.12 else 0.0, data.float32() if player_version > 1.14 else 75.0, )
def read(data: ScnDataReader, version: float): return ScnPlayerStartResources( gold=data.uint32(), wood=data.uint32(), food=data.uint32(), stone=data.uint32(), ore=data.uint32() if version >= 1.17 else 0, goods=data.uint32() if version >= 1.17 else 0, color=data.uint32() if version >= 1.24 else 0, )
def read(data: ScnDataReader): data.mark('random maps') num_random_maps = data.uint32(debug='num_random_maps') random_maps_pointer = data.uint32(debug='random_maps_pointer') # 39845000 in empires_up.dat random_map_meta = [RandomMapMeta.read(data) for _ in range(0, num_random_maps)] # Data from random_map_meta repeats here random_maps = [RandomMap.read(data) for _ in range(0, num_random_maps)] return RandomMapListWrapper( num_random_maps, random_maps_pointer, random_map_meta, random_maps )
def read_classic(data: ScnDataReader, file_version: float): return ScenarioObject( (data.float32(), data.float32(), data.float32()), data.uint32(), data.uint16(), data.uint8(), data.float32(), # Not used in AOE1 -1 if file_version < 1.15 else data.uint16(), -1 if file_version < 1.13 else data.uint32())
def read(data: ScnDataReader): # Not sure how to walk through this trailing data yet. # Fails on both of the Multiplayer Border Patrol maps bundled with ROR and DE. # This data seems to be either 1320 or 708 bytes long. # Some kind of per-player data structure here player_count = data.uint32(debug="unknown field") # Only seen 9. player_unknown_structure_list = [] for i in range(1, 9): player_unknown_structure = UnknownPlayerDataStructure.read(data) player_unknown_structure_list.append(player_unknown_structure) data.done() return UnknownDataStructure(player_count, player_unknown_structure_list)
def load(data: ScnDataReader) -> List[Sprite]: """ Read all the sprites """ data.mark(name='sprites') num_sprites = data.uint16(debug='num_sprites') sprites_exist = [data.uint32() for _ in range(0, num_sprites)] sprites = [] for sprite_id in range(0, num_sprites): if sprites_exist[sprite_id] == 0: continue sprite = Sprite.read(data, sprite_id) sprites.append(sprite) return sprites
def read(data: ScnDataReader): percent = data.uint32() height = data.int32() clumps = data.int32() spacing = data.int32() base_terrain_type = data.int32() base_elevation_type = data.int32() return RandomMapElevation( percent, height, clumps, spacing, base_terrain_type, base_elevation_type )
def read_unit(data: ScnDataReader): # next data structure to read depends on the unit type! unit_type = data.uint8(debug='unit type'.format()) if unit_type == 10: # base read_decorative_unit(data) elif unit_type == 15: # tree raise Exception("Not implemented") elif unit_type == 20: # animated read_animated_unit(data) elif unit_type == 25: # doppleganger read_doppleganger_unit(data) elif unit_type == 30: # moving read_moving_unit(data) elif unit_type == 40: # action read_action_unit(data) elif unit_type == 50: # base raise Exception("Not implemented") elif unit_type == 60: # missile read_missile_unit(data) elif unit_type == 70: read_combat_unit(data) elif unit_type == 80: read_building_unit(data) elif unit_type == 90: read_tree(data) else: raise Exception("Dont know how to read unit type {}".format(unit_type))
def debug_count_until(byte: int, data: ScnDataReader): for i in range(0, 500): if data.uint8() == byte: print("Need to skip {} bytes".format(i)) return logging.info("Value not found") exit(1)
def read(data: ScnDataReader): random_map_borders = ( data.uint32(debug='random_map_border_1'), data.uint32(debug='random_map_border_2'), data.uint32(debug='random_map_border_3'), data.uint32(debug='random_map_border_4') ) border_usage = data.uint32(debug='random_map_border_usage') water_shape = data.uint32(debug='random_map_water_shape') base_terrain = data.uint32(debug='random_map_base_terrain') land_cover = data.uint32(debug='random_map_land_cover') unused_id = data.uint32(debug='random_map_border_unused_id') lands = RandomMapLandListWrapper.read(data) terrains = RandomMapTerrainListWrapper.read(data) objects = RandomMapObjectListWrapper.read(data) elevations = RandomMapElevationListWrapper.read(data) return RandomMap( random_map_borders, border_usage, water_shape, base_terrain, land_cover, unused_id, lands, terrains, objects, elevations )
def _reader_for(file_name): if not (file_name.lower().endswith(".scn") or file_name.lower().endswith(".scx") or file_name.lower().endswith(".aoescn")): raise Exception("Scenario file must end with .scn, .scx or .aoescn") with open(file_name, 'rb') as f: # Read entire file data = ScnDataReader(f.read()) return data
def test_read_write_one_player(): """ Read/rewrite info for an individual player """ original_data = b'\t\x00Player 1\x00\x00\x00\xaaB\x00\x00lBH\x00H\x00\x00\t\x00\x01\x01\x03\x03\x03\x03\x03\x03\x03\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' reader = ScnDataReader(original_data) structure = UnknownPlayerDataStructure.read(reader) # try to write it back writer = ScnDataWriter() structure.write(writer) new_data = writer.done() assert original_data == new_data
def test_default(): """ Write then read back the default version of this data """ writer = ScnDataWriter() scn_unknown_data_structure.default().write(writer) default_structure_binary = writer.done() assert len(default_structure_binary) == 708 # try to read it back reader = ScnDataReader(default_structure_binary) structure = UnknownDataStructure.read(reader) assert structure.player_count == 9 assert structure.unknown_player_data_structure[7].field1 == 'Player 8'
def read_missile_unit(data: ScnDataReader): base_props = read_base_unit_props(data) animated_props = read_animated_unit_props(data) moving_unit_props = read_moving_unit_props(data) action_unit_props = read_action_unit_props(data) base_combat_unit_props = read_base_combat_unit_props(data) data.int8(debug='unknown') data.int32(debug='unknown') data.float32(debug='unknown')
def load(file_name: str): if not (file_name.endswith(".slp")): raise Exception("SLP file must end with .slp") with open(file_name, 'rb') as f: all_data = f.read() data = ScnDataReader(all_data) header = SlpHeader.read(data) frames = [] for i in range(0, header.frames): data.mark('frame {}'.format(i)) frame_info = SlpFrameInfo.read(data) # Sub-reader for outline data (identified by offset) outline_region_start = frame_info.outline_table_offset outline_region_end = outline_region_start + frame_info.height * 4 outline_reader = ScnDataReader( all_data[outline_region_start:outline_region_end]) frame_outline = SlpOutline.read(outline_reader, frame_info.height) # Sub-reader for pixel offsets command_offset_region_start = frame_info.command_table_offset command_offset_region_end = command_offset_region_start + frame_info.height * 4 command_offset_reader = ScnDataReader( all_data[command_offset_region_start:command_offset_region_end]) command_offset = SlpCommandOffset.read(command_offset_reader, frame_info.height) # Sub-reader for pixel data (very inefficient..) command_data_reader = ScnDataReader(all_data) command_data_reader.read( command_offset.row[0] ) # read and discard so that we don't need to do maths to find in-file offset rows = [] for y in range(0, frame_info.height): row = SlpRow.read(command_data_reader, frame_outline.row[y]) rows.append(row) frames.append(SlpFrame(frame_info, rows)) return SlpFile(header, frames)
def test_read_write(): """ Read/write entire 508 byte data structure found at the end of a blank scenario file. """ original_data = b'\t\x00\x00\x00\t\x00Player 1\x00\x00\x00\xaaB\x00\x00lBH\x00H\x00\x00\t\x00\x01\x01\x03\x03\x03\x03\x03\x03\x03\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00Player 2\x00\x00\x00\x90B\x00\x00\x90BH\x00H\x00\x00\t\x00\x01\x03\x01\x03\x03\x03\x03\x03\x03\x00\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00Player 3\x00\x00\x00\x90B\x00\x00\x90BH\x00H\x00\x00\t\x00\x01\x03\x03\x01\x03\x03\x03\x03\x03\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00Player 4\x00\x00\x00\x90B\x00\x00\x90BH\x00H\x00\x00\t\x00\x01\x03\x03\x03\x01\x03\x03\x03\x03\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00Player 5\x00\x00\x00\x90B\x00\x00\x90BH\x00H\x00\x00\t\x00\x01\x03\x03\x03\x03\x01\x03\x03\x03\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00Player 6\x00\x00\x00\x90B\x00\x00\x90BH\x00H\x00\x00\t\x00\x01\x03\x03\x03\x03\x03\x01\x03\x03\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00Player 7\x00\x00\x00\x90B\x00\x00\x90BH\x00H\x00\x00\t\x00\x01\x03\x03\x03\x03\x03\x03\x01\x03\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00Player 8\x00\x00\x00\x90B\x00\x00\x90BH\x00H\x00\x00\t\x00\x01\x03\x03\x03\x03\x03\x03\x03\x01\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # try to read it reader = ScnDataReader(original_data) structure = UnknownDataStructure.read(reader) assert structure.player_count == 9 assert structure.unknown_player_data_structure[7].field1 == 'Player 8' # try to write it back writer = ScnDataWriter() structure.write(writer) # check it was the same new_data = writer.done() assert original_data == new_data
def load(filename: str) -> GameDataFile: with open(filename, 'rb') as f: # Read entire file data = ScnDataReader(f.read()) data.decompress() # Decompress only! # open("Empires_uncompressed.dat", 'wb').write(data.read()) # exit(0) game_data_file = GameDataFile.read(data) data.done() return game_data_file