if name: res.append(name) if bt.param != 0: res.append('parameters') return ' '.join(res) Parameter = Struct( 'Name' / FixedSizeCString(4), # 4 bytes, 3 chars + null 'Type' / Enum(Int16ul, INT32=0, REAL64=1, STRING=2, ENUM=3, SENUM=4), 'ReservedSpace' / Int16ul, # Only look for a Value if this isn't the END pseudo-parameter. 'Value' / If( this.Name != b'END', Switch(this.Type, { 'INT32': Int32ul, 'REAL64': Float64l }, default=FixedSizeCString(this.ReservedSpace * 2)))) def is_ParameterList(block): return block.BlockType.param != 0 ParameterList = RepeatUntil(obj_.Name == b'END', Parameter) FloatData = Array(this.BlockLength, Float32l) StringData = Bytes(this.BlockLength * 4) DirectoryEntry = Struct( 'BlockType' / BlockType, 'BlockLength' / Int32ul, 'DataPtr' / Int32ul,
"ConsoleDataBlock" / If( this.BlockSignature == 0xA0000002, Struct( "FileAttributes" / Enum(Int16ul, FOREGROUND_BLUE=0x001, FOREGROUND_GREEN=0x002, FOREGROUND_RED=0x004, FOREGROUND_INTENSITY=0x008, BACKGROUND_BLUE=0x010, BACKGROUND_GREEN=0x020, BACKGROUND_RED=0x040, BACKGROUND_INTENSITY=0x0080), "PopupFillAttributes" / Enum(Int16ul, FOREGROUND_BLUE=0x001, FOREGROUND_GREEN=0x002, FOREGROUND_RED=0x004, FOREGROUND_INTENSITY=0x008, BACKGROUND_BLUE=0x010, BACKGROUND_GREEN=0x020, BACKGROUND_RED=0x040, BACKGROUND_INTENSITY=0x0080), "ScreenBufferSizeX" / Int16ul, "ScreenBufferSizeY" / Int16ul, "WindowSizeX" / Int16ul, "WindowSizeY" / Int16ul, "WindowOriginX" / Int16ul, "WindowOriginY" / Int16ul, "Unused1" / Bytes(4), "Unused2" / Bytes(4), "FontSize" / Int32ul, "FontFamily" / Enum(Int32ul, FF_DONTCARE=0x0000, FF_ROMAN=0x0010, FF_SWISS=0x0020, FF_MODERN=0x0030, FF_SCRIPT=0x0040, FF_DECORATIVE=0x0050, TMPF_NONE=0x0000, TMPF_FIXED_PITCH=0x0001, TMPF_VECTOR=0x0002, TMPF_TRUETYPE=0x0004, TMPF_DEVICE=0x0004), "FontWeight" / Int32ul, "FaceName" / Bytes(64), "CursorSize" / Int32ul, "FullScreen" / Int32ul, "QuickEdit" / Int32ul, "InsertMode" / Int32ul, "AutoPosition" / Int32ul, "HistoryBufferSize" / Int32ul, "NumberOfHistoryBuffers" / Int32ul, "HistoryNoDup" / Int32ul, "ColorTable" / Bytes(64))),
from mgz.util import Find, Version, find_version, find_save_version from mgz.header.unit_type import unit_type # pylint: disable=invalid-name active_sprite = "active_sprite" / Struct("id" / Int16ul, "x" / Int32ul, "y" / Int32ul, "frame" / Int16ul, "invisible" / Byte) animated_sprite = "animated_sprite" / Struct( "animate_interval" / Int32ul, "animate_last" / Int32ul, "last_frame" / Int16ul, "frame_changed" / Byte, "frame_looped" / Byte, "animate_flag" / Byte, "last_speed" / Float32l) sprite_list = "sprite_list" / Struct( "type" / Byte, "active" / If(lambda ctx: ctx.type != 0, active_sprite), "animated" / If(lambda ctx: ctx.type == 2, animated_sprite), Embedded( If(lambda ctx: ctx.type != 0, Struct("order" / Byte, "flag" / Byte, "count" / Byte)))) static = "static" / Struct( "object_type" / Int16ul, "sprite" / Int16ul, "garrisoned_in_id" / Int32sl, "hitpoints" / Float32l, "object_state" / Byte, "sleep" / Flag, "doppleganger" / Flag, "go_to_sleep" / Flag, "object_id" / Int32ul, "facet" / Byte, "x" / Float32l, "y" / Float32l, "z" / Float32l, "screen_offset_x" / Int16ul, "screen_offset_y" / Int16ul, "shadow_offset_x" / Int16ul, "shadow_offset_y" / Int16ul, "selected_group" / If(lambda ctx: find_version(ctx) == Version.AOK, Byte), ResourceEnum("resource_type" / Int16sl), "amount" / Float32l, "worker_count" / Byte, "current_damage" / Byte, "damaged_lately_timer" /
"invisible"/Byte ) animated_sprite = "animated_sprite"/Struct( "animate_interval"/Int32ul, "animate_last"/Int32ul, "last_frame"/Int16ul, "frame_changed"/Byte, "frame_looped"/Byte, "animate_flag"/Byte, "last_speed"/Float32l ) sprite_list = "sprite_list"/Struct( "type"/Byte, "active"/If(lambda ctx: ctx.type != 0, active_sprite), "animated"/If(lambda ctx: ctx.type == 2, animated_sprite), Embedded(If(lambda ctx: ctx.type != 0, Struct( "order"/Byte, "flag"/Byte, "count"/Byte ))) ) particle = "particle"/Struct( "type"/Int16ul, Embedded(If(lambda ctx: ctx.type == 1, Struct( "name"/de_string, "x"/Float32l, "y"/Float32l, Bytes(26)
scenario_header = "scenario_header"/Struct( "next_uid"/Int32ul, "constant"/Bytes(4), Array(16, "names"/String(256)), Array(16, "player_ids"/Int32ul), Array(16, "player_data"/Struct( "active"/Int32ul, "human"/Int32ul, "civilization"/Int32ul, "constant"/Int32ul, # 0x04 0x00 0x00 0x00 )), Padding(5), "elapsed_time"/Float32l, "scenario_filename"/PascalString(lengthfield="scenario_filename_length"/Int16ul), If(lambda ctx: ctx._._.version == Version.DE, Struct( Padding(64), If(lambda ctx: find_save_version(ctx) >= 13.34, Padding(64)) )) ) # Scenarios have intro text, a bitmap, and cinematics. messages = "messages"/Struct( "instruction_id"/Int32ul, "hints_id"/Int32ul, "victory_id"/Int32ul, "defeat_id"/Int32ul, "history_id"/Int32ul, "scouts_id"/If(lambda ctx: ctx._._.version != Version.AOK, Int32ul), "instructions_length"/Int16ul, "instructions"/Bytes(lambda ctx: ctx.instructions_length), "hints"/PascalString(lengthfield="hints_length"/Int16ul), "victory"/PascalString(lengthfield="victory_length"/Int16ul),
"damaged_lately_timer"/Byte, "under_attack"/Byte, "pathing_group_len"/Int32ul, "pathing_group"/Array(lambda ctx: ctx.pathing_group_len, Int32ul), "group_id"/Byte, "already_called"/Byte, ) # Other - seems to be items under Units > Other in the scenario editor animated = "animated"/Struct( Embedded(additional_header), # The following sections can be refined with further research. # There are clearly some patterns. "has_extra"/Byte, If(lambda ctx: ctx.has_extra == 2, Padding( 34 )), "turn_speed"/Float32l ) # Units - typically villagers, scout, and any sheep within LOS combat = "combat"/Struct( Embedded(additional_header), # Not pretty, but we don't know how to parse a unit yet. # Also, this only works on non-restored games. # This isn't a constant footer, these are actually initial values of some sort. "end_of_unit"/Find(b'\xff\xff\xff\xff\x00\x00\x80\xbf\x00\x00\x80\xbf\xff\xff\xff' \ b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00', None) ) # Buildings - ID doesn't match Build action ID - buildings can have multiple parts
EventHeader = Struct("marker" / wmi_trace_marker(EventHeaderType), "flags" / EventHeaderFlag, "event_property" / EventHeaderPropertyFlag, "thread_id" / Int32ul, "process_id" / Int32ul, "timestamp" / Int64ul, "provider_id" / Guid, "event_descriptor" / EventDescriptor, "processor_time" / Int64ul, "activity_id" / Guid) EventHeaderExtendedDataItem = Struct( "reserved1" / Int16ul, "ext_type" / Int16ul, "reserved2" / Int16ul, "data_size" / Int16ul, "data_item" / Bytes(lambda this: this.data_size)) EventRecord = AlignedStruct( 8, "mark1" / Computed(lambda this: this._io.tell()), "event_header" / EventHeader, "extended_data" / If( lambda this: this.event_header.flags.EVENT_HEADER_FLAG_EXTENDED_INFO, RepeatUntil(lambda el, lst, this: not lst[-1].reserved2 & 0x1, Aligned(8, EventHeaderExtendedDataItem))), "mark2" / Computed(lambda this: this._io.tell()), "user_data" / Bytes(lambda this: this.event_header.marker.version - (this.mark2 - this.mark1))) class Event: """ This is a python wrapper around construct struct to access interesting fields """ def __init__(self, source): self.source = source def get_process_id(self): """
Terminated, If, Computed, this, Peek) from mgz.util import MgzPrefixed, ZlibCompressed, Version, VersionAdapter, get_version from mgz.header.ai import ai from mgz.header.replay import replay from mgz.header.map_info import map_info from mgz.header.initial import initial from mgz.header.achievements import achievements from mgz.header.scenario import scenario from mgz.header.lobby import lobby from mgz.header.de import de compressed_header = Struct( "game_version" / CString(encoding='latin1'), "save_version" / VersionAdapter(Float32l), "version" / Computed( lambda ctx: get_version(ctx.game_version, ctx.save_version, None)), "de" / If(lambda ctx: ctx.version == Version.DE, de), ai, replay, map_info, initial, achievements, scenario, lobby, Terminated) subheader = Struct( "check" / Peek(Int32ul), "chapter_address" / If(lambda ctx: ctx.check < 100000000, Int32ul), Embedded( MgzPrefixed( lambda ctx: ctx._.header_length - 4 - (4 if ctx.check < 100000000 else 0), ZlibCompressed(compressed_header)))) """Header is compressed""" header = Struct( "header_length" / Int32ul, Embedded(subheader), "log_version" / If(lambda ctx: ctx.save_version >= 11.76, Peek(Int32ul)), "version" / Computed(lambda ctx: get_version(
"player_name_length"/Int16ul, "player_name"/String(this.player_name_length, padchar=b'\x00', trimdir='right', encoding='latin1'), Padding(1), # 0x16 "num_header_data"/Int32ul, # always 198 Padding(1), # 0x21 player_stats, Padding(1), "camera_x"/Float32l, "camera_y"/Float32l, "end_of_camera"/Tell, "num_saved_views"/Int32sl, # present in resumed games If(lambda ctx: ctx.num_saved_views > 0, Array( lambda ctx: ctx.num_saved_views, "saved_view"/Struct( "camera_x"/Float32l, "camera_y"/Float32l ) )), "map_size"/Struct( "x"/Int16ul, "y"/Int16ul ), "culture"/Byte, CivEnum("civilization"/Byte), "game_status"/Byte, "resigned"/Flag, Padding(1), ColorEnum("player_color"/Byte), Padding(1) )
Float32l, "convert_min_adj" / Float32l, "convert_max_adj" / Float32l, "convert_resist_min_adj" / Float32l, "convert_resist_max_adj" / Float32l, "convert_building_min" / Float32l, "convert_building_max" / Float32l, "convert_building_chance" / Float32l, "spies" / Float32l, "value_wonders_castles" / Float32l, "food_score" / Float32l, "wood_score" / Float32l, "stone_score" / Float32l, "gold_score" / Float32l, "wood_bonus0" / Float32l, "food_bonus0" / Float32l, "relic_rate" / Float32l, "heresy" / Float32l, "theocracy" / Float32l, "crenellations" / Float32l, "construction_rate_mod" / Float32l, "hun_wonder_bonus" / Float32l, "spies_discount" / Float32l, Embedded( If( lambda ctx: ctx._.num_header_data == 219, Struct("unk2" / Float32l, "unk3" / Float32l, "unk4" / Float32l, "unk5" / Float32l, "unk6" / Float32l, "unk7" / Float32l, "unk8" / Float32l, "unk9" / Float32l, "unk10" / Float32l, "unk11" / Float32l, "unk12" / Float32l, "unk13" / Float32l, "unk14" / Float32l, "unk15" / Float32l, "unk16" / Float32l, "unk17" / Float32l, "unk18" / Float32l, "unk19" / Float32l, "unk20" / Float32l, "unk21" / Float32l, "unk22" / Float32l))), Embedded( If( lambda ctx: ctx._.num_header_data == 240, Struct(ModVersionAdapter( "mod" / Float32l), "unk2" / Float32l, "unk3" / Float32l, "unk4" / Float32l, "unk5" / Float32l, "unk6" / Float32l, "unk7" / Float32l, "trickle_food" / Float32l, "trickle_wood" / Float32l, "trickle_stone" / Float32l, "trickle_gold" / Float32l, "reveal_enemy_tcs" / Float32l, "reveal_gaia_class_1" / Float32l, "reveal_gaia_class_2" / Float32l, "unk15" / Float32l, "unk16" / Float32l,
SID = 19 HEXINT32 = 20 HEXINT64 = 21 COUNTEDSTRING = 22 COUNTEDANSISTRING = 23 STRUCT = 24 COUNTEDBINARY = 25 CCOUNT = 32 VCCOUNT = 64 CHAIN = 128 TlMetaDataField = Struct( "name" / CString("ascii"), "tag_in" / Int8ul, "tag_out" / If(lambda this: this.tag_in & TagIn.CHAIN.value, LazyBound(lambda: Int8ul))) TlMetaData = Struct("size" / Int16ul, "tag" / Int8ul, "name" / CString("ascii"), "fields" / GreedyRange(TlMetaDataField)) def build_tracelogging(event): """ Build tracelogging based on the source event Check if event have an extended :param event: event that encompass Tracelogging data """ if event.extended_data is not None: for extended_data in event.extended_data: if extended_data.ext_type == 11:
from construct import (Struct, CString, Const, Int32ul, Embedded, Float32l, Terminated, If, Computed, this, Peek) from mgz.util import MgzPrefixed, ZlibCompressed, Version, get_version from mgz.header.ai import ai from mgz.header.replay import replay from mgz.header.map_info import map_info from mgz.header.initial import initial from mgz.header.achievements import achievements from mgz.header.scenario import scenario from mgz.header.lobby import lobby from mgz.header.de import de compressed_header = Struct( "game_version" / CString(encoding='latin1'), "save_version" / Float32l, "version" / Computed(lambda ctx: get_version(ctx.game_version, ctx.save_version)), "de" / If(lambda ctx: ctx.version == Version.DE, de), ai, replay, map_info, initial, achievements, scenario, lobby, Terminated) subheader = Struct( "check" / Peek(Int32ul), "chapter_address" / If( lambda ctx: ctx.check == 0, # TODO: could be greater Int32ul), Embedded( MgzPrefixed( lambda ctx: ctx._.header_length - 4 - (4 if ctx.check == 0 else 0), ZlibCompressed(compressed_header)))) """Header is compressed""" header = Struct("header_length" / Int32ul, Embedded(subheader))
"""Lobby.""" from construct import Array, Byte, Bytes, Flag, Int32ul, Padding, Peek, Struct, If, Computed, Embedded, Int32sl from mgz.enums import GameTypeEnum, RevealMapEnum from mgz.util import Version, find_save_version # pylint: disable=invalid-name, bad-continuation # Player inputs in the lobby, and several host settings. lobby = "lobby" / Struct( If(lambda ctx: find_save_version(ctx) >= 13.34, Padding(5)), If(lambda ctx: find_save_version(ctx) >= 20.06, Padding(9)), Array(8, "teams" / Byte), # team number selected by each player If( lambda ctx: ctx._.version != Version.DE, Padding(1), ), Peek("reveal_map_id" / Int32ul), RevealMapEnum("reveal_map" / Int32ul), "fog_of_war" / Int32ul, "map_size" / Int32ul, "population_limit_encoded" / Int32ul, "population_limit" / Computed(lambda ctx: ctx.population_limit_encoded * (25 if ctx._.version in [Version.USERPATCH14, Version.USERPATCH15] else 1)), Embedded( If( lambda ctx: ctx._.version != Version.AOK, Struct(Peek("game_type_id" / Byte), GameTypeEnum(
Struct("dlc_id" / Int32ul, "color_id" / Int32sl, "selected_color" / Byte, "selected_team_id" / Byte, "resolved_team_id" / Byte, "dat_crc" / Bytes(8), "mp_game_version" / Byte, "civ_id" / Byte, Const(b"\x00\x00\x00"), "ai_type" / de_string, "ai_civ_name_index" / Byte, "ai_name" / de_string, "name" / de_string, "type" / PlayerTypeEnum(Int32ul), "profile_id" / Int32ul, Const(b"\x00\x00\x00\x00"), "player_number" / Int32sl, "hd_rm_elo" / Int32ul, "hd_dm_elo" / Int32ul, "animated_destruction_enabled" / Flag, "custom_ai" / Flag)), "fog_of_war" / Flag, "cheat_notifications" / Flag, "colored_chat" / Flag, Bytes(9), separator, Bytes(12), If(lambda ctx: ctx._.save_version >= 13.13, Bytes(5)), "strings" / Array( 23, Struct( "string" / de_string, RepeatUntil(lambda x, lst, ctx: lst[-1] not in [3, 21, 23, 42, 44], Int32ul))), "strategic_numbers" / Array(59, Int32sl), "num_ai_files" / Int64ul, "ai_files" / Array(lambda ctx: ctx.num_ai_files, Struct( Bytes(4), "name" / de_string, Bytes(4), )), "guid" / Bytes(16),
MountProcedure = Enum(Int32ub, null = 0, mnt = 1, dump = 2, umnt = 3, umntall = 4, export = 5 ) MountMntArgs = PascalString(Int32ub, encoding="utf-16-le") NfsFhandle = Bytes(32) MountMntRes = Struct( "status" / Int32ub, "fhandle" / If(this.status == 0, NfsFhandle) ) RpcCall = Struct( "rpcvers" / Const(Int32ub, 2), "prog" / RpcProgram, "vers" / Default(Int32ub, 2), "proc" / Switch(this.prog, { "portmap": PortmapProcedure, "nfs": NfsProcedure, "mount": MountProcedure }), "cred" / RpcOpaqueAuth, "verf" / RpcOpaqueAuth )
'name' / WIPString, 'type' / WIPTagType, 'data_start' / Int64sl, 'data_end' / Int64sl, # 'start'/Tell, # OneOf(Computed(this.start == this.data_start), [True]), 'data_size' / Computed(this.data_end - this.data_start), 'data' / If( this.data_end > this.data_start, Switch( this.type, dict( WIP_TAG_LIST=RepeatUntil( lambda obj, ctx: obj.data_end >= ctx.data_end, LazyBound(lambda: WIPTag)), WIP_TAG_EXTENDED=Bytes(10), WIP_TAG_DOUBLE=Float64l, WIP_TAG_FLOAT=Float32l, WIP_TAG_INT64=Int64sl, WIP_TAG_INT32=Array(this.data_size // 4, Int32sl), WIP_TAG_UINT32=Array(this.data_size // 4, Int32ul), WIP_TAG_CHAR=Array(this.data_size, Int8ul), WIP_TAG_BOOL=Int8ul, WIP_TAG_STRING=WIPString, ))), 'end' / Tell, # pad to get to data_end Padding(this.data_end - this.end), ) WIPFile = Struct( Const(b'WIT_PR06'), # alternately, "WIT_PRCT"
"convert_resist_max_adj"/Float32l, "convert_building_min"/Float32l, "convert_building_max"/Float32l, "convert_building_chance"/Float32l, "spies"/Float32l, "value_wonders_castles"/Float32l, "food_score"/Float32l, "wood_score"/Float32l, "stone_score"/Float32l, "gold_score"/Float32l, Embedded(If(this._._._._.save_version >= 11.76, Struct( "wood_bonus0"/Float32l, "food_bonus0"/Float32l, "relic_rate"/Float32l, "heresy"/Float32l, "theocracy"/Float32l, "crenellations"/Float32l, "construction_rate_mod"/Float32l, "hun_wonder_bonus"/Float32l, "spies_discount"/Float32l, ))), Embedded(If(this._._._._.version == Version.DE, Struct( Array(this._._.num_header_data - 198, Float32l) ))), Embedded(If(this._._._._.version == Version.USERPATCH15, Struct( ModVersionAdapter("mod"/Float32l), Array(6, Float32l), "trickle_food"/Float32l, "trickle_wood"/Float32l, "trickle_stone"/Float32l, "trickle_gold"/Float32l,
# Flying, position, and orientation, reused in several places. grounded = Struct("grounded", UBInt8("grounded")) position = Struct("position", BFloat64("x"), BFloat64("y"), BFloat64("stance"), BFloat64("z")) orientation = Struct("orientation", BFloat32("rotation"), BFloat32("pitch")) # Notchian item packing items = Struct( "items", SBInt16("primary"), If( lambda context: context["primary"] >= 0, Embed( Struct( "item_information", UBInt8("count"), UBInt16("secondary"), )), ), ) # Metadata subconstruct. metadata = StringAdapter( RepeatUntil(lambda obj, ctx: obj == "\x7f", Field("metadata", 1))) # Build faces, used during dig and build. faces = { "noop": -1, "-y": 0, "+y": 1,
StartingAgeEnum, VictoryEnum) from mgz.util import TimeSecAdapter # pylint: disable=invalid-name # Not all actions are defined, not all actions are complete. interact = "interact"/Struct( "player_id"/Byte, Const(b"\x00\x00"), "target_id"/Int32ul, "selected"/Int32ul, "x"/Float32l, "y"/Float32l, If(lambda ctx: ctx.selected < 0xff, Array( lambda ctx: ctx.selected, "unit_ids"/Int32ul )) ) ai_interact = "ai_interact"/Struct( Padding(3), "target_id"/Int32ul, "selected"/Byte, Padding(3), "x"/Float32l, "y"/Float32l, If(lambda ctx: ctx.selected < 0xff, Array( lambda ctx: ctx.selected, "unit_ids"/Int32ul )) )
GetCommModeInfoResponse = Struct( Padding(1), "commModeOptional" / CommModeOptional, Padding(1), "maxBs" / Int8ul, "minSt" / Int8ul, "queueSize" / Int8ul, "xcpDriverVersionNumber" / Int8ul, ) GetIDResponse = Struct( "mode" / Int8ul, Padding(2), "length" / Int32u, "identification" / If(this.mode == 1, Int8ul[this.length]), ) GetSeedResponse = Struct("length" / Int8ul, "seed" / If(this.length > 0, Int8ul[this.length])) SetRequestMode = BitStruct( Padding(4), "clearDaqReq" / Flag, "storeDaqReq" / Flag, Padding(1), "storeCalReq" / Flag, ) BuildChecksumResponse = Struct( "checksumType" / Enum(
import enum from typing import List, Tuple from construct import Default, Enum, If, Int8ul, Int32ul, Int64ul, Struct from database import enums from world_server import op_code ServerInventoryChangeFailure = Struct( 'code' / Int8ul, 'result' / If( lambda c: c.code != enums.InventoryChangeError.OK, Struct( 'required_level' / If( lambda c: c._.code == enums.InventoryChangeError. CANT_EQUIP_LEVEL_I, Default(Int32ul, 0)), 'item1_guid' / Default(Int64ul, 0), 'item2_guid' / Default(Int64ul, 0), 'bag_subclass' / Default(Int8ul, 0), ), ), ) def error(code: enums.InventoryChangeError, **kwargs) -> List[Tuple[op_code.Server, bytes]]: return [( op_code.Server.INVENTORY_CHANGE_FAILURE, ServerInventoryChangeFailure.build( dict( code=code,
from construct import BytesInteger, Const, If, Int8ul, Struct from common import srp from login_server import op_code, router ClientLoginProof = router.ClientPacket.Register( op_code.Client.LOGIN_PROOF, Struct( 'A' / BytesInteger(32, swapped=True), 'M' / BytesInteger(20, swapped=True), 'crc_hash' / BytesInteger(20, swapped=True), 'number_of_keys' / Int8ul, 'security_flags' / Int8ul, )) ServerLoginProof = Struct( 'error' / Int8ul, 'proof' / If( lambda self: self.error == 0, Struct( 'proof' / BytesInteger(20, swapped=True), 'unk1' / Const(int(0).to_bytes(4, 'little')), )), )
TMS470 = 0x0097, TMS320C5400 = 0x0098, TMS320C6000 = 0x0099, TMS320C5500 = 0x009C, TMS320C2800 = 0x009D, MSP430 = 0x00A0, TMS320C5500plus = 0x00A1, ), "optionalFileHeader" / If(this.sizeOptHeader == 28, Struct( "magic" / Int16ul, # Const(b'\0x01\0x08'), "version" / Int16ul, "executableSize" / Int32ul, "initializedDataSize" / Int32ul, "uninitializedDataSize" / Int32ul, "entryPoint" / Int32ul, "executableCodeAddress" / Int32ul, "initializedDataAddress" / Int32ul, ) ), "sections" / Array(this.numSectionHeaders, Struct( "name" / Bytes(8), "physicalAddress" / Int32ul, "virtualAddress" / Int32ul, "sectionSize" / Int32ul, "filePointer" / Int32ul,
# Action - length followed by data. action = "action"/Struct( "length"/Int32ul, action_data ) # Synchronization. sync = "sync"/Struct( "time_increment"/Int32ul, Peek("next"/Int32ul), "checksum"/If(lambda ctx: not ctx.next, Struct( Padding(8), "sync"/Int32ul, Padding(16) )) ) # View lock. viewlock = "viewlock"/Struct( "view"/Struct( "x"/Float32l, "y"/Float32l ), "player_id"/Int32ul )
"total_tribute_recvd" / Float32l, "total_value_of_razings" / Float32l, "castle_high" / Float32l, "wonder_high" / Float32l, "total_tribute_sent" / Float32l, "convert_min_adj" / Float32l, "convert_max_adj" / Float32l, "convert_resist_min_adj" / Float32l, "convert_resist_max_adj" / Float32l, "convert_building_min" / Float32l, "convert_building_max" / Float32l, "convert_building_chance" / Float32l, "spies" / Float32l, "value_wonders_castles" / Float32l, "food_score" / Float32l, "wood_score" / Float32l, "stone_score" / Float32l, "gold_score" / Float32l, Embedded( If( lambda ctx: find_save_version(ctx) >= 11.76, Struct( "wood_bonus0" / Float32l, "food_bonus0" / Float32l, "relic_rate" / Float32l, "heresy" / Float32l, "theocracy" / Float32l, "crenellations" / Float32l, "construction_rate_mod" / Float32l, "hun_wonder_bonus" / Float32l, "spies_discount" / Float32l, ))), Embedded( If(lambda ctx: find_version(ctx) in (Version.DE, Version.HD), Struct(Array(this._._.num_header_data - 198, Float32l)))), Embedded( If( lambda ctx: find_version(ctx) in [Version.USERPATCH15, Version.MCP], Struct(ModVersionAdapter("mod" / Float32l), Array( 6, Float32l), "trickle_food" / Float32l,
def _decode(self, obj, context, path=None): offset = datetime(2000, 1, 1, 12) - datetime(1970, 1, 1) return (datetime.utcfromtimestamp(obj.time_stamp_seconds) + offset) SecondaryHeaderRaw = Struct('time_stamp_seconds' / Int32ub, 'sub_seconds' / Int8ub, Padding(1)) SecondaryHeader = TimeAdapter(SecondaryHeaderRaw) cute_ax25_packet_header = RawCopy( Struct( 'ax25_header' / Header, 'primary_header' / PrimaryHeader, 'secondary_header' / If(lambda c: c.primary_header.secondary_header_flag, SecondaryHeader))) cute_ax25_packet_fragment = Struct('header' / cute_ax25_packet_header, 'packet' / GreedyBytes) cute_ax25_packet_complete = Struct( 'ax25_header' / Header, 'primary_header' / PrimaryHeader, 'secondary_header' / If(lambda c: c.primary_header.secondary_header_flag, SecondaryHeader), 'packet' / Switch(lambda c: (c.primary_header.APID), { (0x55): cute_bct_fsw, (0x56): cute_bct_soh, (0x1FF): cute_pld_sw_stat }))
# pylint: disable=invalid-name script = "script" / Struct( Padding(4), "seq" / Int32sl, "max_rules" / Int16ul, "num_rules" / Int16ul, Padding(4), Array( this.num_rules, "rules" / Struct( Padding(12), "num_facts" / Byte, "num_facts_actions" / Byte, Padding(2), Array( 16, "data" / Struct("type" / Int32ul, "id" / Int16ul, Padding( 2), Array(4, "params" / Int32ul)))))) ai = "ai" / Struct( "has_ai" / Int32ul, # if true, parse AI "yep" / If( this.has_ai == 1, "ais" / Struct( "max_strings" / Int16ul, "num_strings" / Int16ul, Padding(4), Array( this.num_strings, "strings" / PascalString( lengthfield="name_length" / Int32ul, encoding='latin1')), Padding(6), Array(8, script), Padding(104), Array(80, "timers" / Int32sl), Array(256, "shared_goals" / Int32sl), Padding(4096), )))
"postgame": actions.postgame, "de_attackmove": actions.de_attackmove, "de_autoscout": actions.de_autoscout }, default=Struct("unk_action" / Computed(lambda ctx: ctx._.type), "bytes" / Bytes(lambda ctx: ctx._._.length - 1)))), Padding(4)) # Action - length followed by data. action = "action" / Struct("length" / Int32ul, action_data) # Synchronization. sync = "sync" / Struct( "time_increment" / Int32ul, Peek("next" / Int32ul), "checksum" / If( lambda ctx: not ctx.next, Struct(Padding(8), "sync" / Int32ul, "unknown" / Bytes(4), "sequence" / Int32ul, If(lambda ctx: ctx.sequence > 0, Bytes(332)), Bytes(8)))) # View lock. viewlock = "viewlock" / Struct("view" / Struct("x" / Float32l, "y" / Float32l), "player_id" / Int32ul) # Chat. chat = "chat" / Struct(Padding(4), "length" / Int32ul, "text" / Bytes(lambda ctx: ctx.length - 0), Padding(0)) # Start. start = "start" / Struct( Seek(-4, whence=1), "checksum_interval" / Int32ul, BoolAdapter("multiplayer" / Int32ul), "rec_owner" / Int32ul,
"nsymbols" / Int32ul, "optionalheader_size" / Int16ul, "characteristics" / Int16ul, ) pe_header = Struct( "offset" / Tell, "magic" / Enum(Int16ul, PE32=0x10B, PE32PLUS=0x20B), Seek(this.offset + 64), "checksum_offset" / Tell, "checksum" / Int32ul, Seek(lambda ctx: ctx.offset + (92 if ctx.magic == "PE32" else 108)), "nrvasizes" / Int32ul, Seek(lambda ctx: ctx.offset + (128 if ctx.magic == "PE32" else 144)), "certtable_info" / If(this.nrvasizes >= 5, Tell), "certtable_offset" / If(this.nrvasizes >= 5, Int32ul), "certtable_size" / If(this.nrvasizes >= 5, Int32ul), ) certificate = Struct( "size" / Int32ul, "revision" / Enum(Int16ul, REV1=0x0100, REV2=0x0200), "certtype" / Enum(Int16ul, PKCS7=0x002), "data" / Bytes(this.size - 8), ) section = Struct( "name" / PaddedString(8, "utf8"), "vsize" / Int32ul,
Switch(this.version, { 'K': HeaderVersionK, 'L': Computed(_wrong_version_error), 'M': HeaderVersionM, }, default=Computed(_wrong_version_error)))) Subfile = Struct( 'flags' / Byte, 'exp' / Byte, 'index' / Int16sl, 'time' / Float32l, 'next' / Float32l, 'nois' / Float32l, 'npts' / Int32sl, 'scan' / Int32sl, 'wlevel' / Float32l, Padding(4), 'float_y' / Computed(this.exp == 128), 'num_pts' / Computed(lambda ctx: ctx.npts if ctx.npts > 0 else ctx._.Header.npts), 'exponent' / Computed(lambda ctx: ctx.exp if 0 < ctx.exp < 128 else ctx._.Header.exp), 'raw_x' / If(this._.Header.TFlags.use_subfile_xs, OnDemand(Array(this.num_pts, Int32sl))), 'raw_y' / IfThenElse(this.float_y, OnDemand(Array(this.num_pts, Float32l)), OnDemand(Array(this.num_pts, Int32sl)))) LogData = Struct( 'log_start' / Tell, 'sizd' / Int32sl, 'sizm' / Int32sl, 'text_offset' / Int32sl, 'bins' / Int32sl, 'dsks' / Int32sl, Padding(44), 'content' / Pointer(this.log_start + this.text_offset, OnDemand(String(this.sizd)))) # The entire file. SPCFile = Struct( 'Header' / Header, 'xvals' / If(this.Header.TFlags.has_xs, OnDemand(Array(this.Header.npts, Float32l))), 'Subfile' / Array(this.Header.nsub, Subfile), 'LogData' / If(this.Header.log_offset != 0, Pointer(this.Header.log_offset, LogData)))