diff --git a/include/generated/sots_addresses.h b/include/generated/sots_addresses.h index c526501..7fba331 100644 --- a/include/generated/sots_addresses.h +++ b/include/generated/sots_addresses.h @@ -1,5 +1,5 @@ // GENERATED — do not edit. Facts about Sword of the Stars.exe (GOG 1.8.1). -// Source: sots-re ghidra/addresses.json @ 2308b6e, generated 2026-09-08 by tools/gen_addresses.py +// Source: sots-re ghidra/addresses.json @ 805409e, generated 2026-09-08 by tools/gen_addresses.py // Runtime address = (uintptr_t)GetModuleHandle(NULL) + RVA (the exe is ASLR-relocated). #pragma once #include @@ -1237,6 +1237,64 @@ constexpr uint32_t Game_StarSystem_OutputRates_Write = 0x00345190; constexpr uint32_t Game_StarSystem_OutputRates_Read = 0x003472a0; // layout sizeof(Game::StarSystem::OutputRates) -- enumeration meets embedding [verified] constexpr uint32_t sizeof_Game_StarSystem_OutputRates = 0x0000001c; +// thiscall void (Game::StrategyAIAgent::Streamable* this, Mars::Stream* s) // the body of every `Player..AIAgent` CD block. 36 wire items, NO conditionals: the only `if` the decompiler shows around `lnat` is an inlined std::vector destructor whose operator delete is marked noreturn, and both paths converge at 0x006c72e8. The agent object is *(this+4) [verified] +constexpr uint32_t Game_StrategyAIAgent_Streamable_Write = 0x002c6f00; +// thiscall bool (Game::StrategyAIAgent::Streamable* this, Mars::Stream* s) [verified] +constexpr uint32_t Game_StrategyAIAgent_Streamable_Read = 0x002c8fd0; +// thiscall void (Game::StrategyAIAgent::DesignNameGen* this, Mars::Stream* s) // `dnnc` = (this+8 - this+4)/0x24, then dnnc x { dnid: StreamableHelper at elem+0, dnnm: WriteString at elem+8 }. Element stride 0x24 = ShipSectionID(8) + Mars::String(0x1c) [verified] +constexpr uint32_t Game_StrategyAIAgent_DesignNameGen_Write = 0x002c77a0; +// thiscall bool (Game::StrategyAIAgent::DesignNameGen* this, Mars::Stream* s) [verified] +constexpr uint32_t Game_StrategyAIAgent_DesignNameGen_Read = 0x002ccc70; +// thiscall void (Game::AISituation* this, Mars::Stream* s) // AISitSecs = AIWeightMap at this+0, AISitWeapFams = AIWeightMap> at this+0x10. sizeof >= 0x20 [verified] +constexpr uint32_t Game_AISituation_Write = 0x0029a220; +// thiscall bool (Game::AISituation* this, Mars::Stream* s) [verified] +constexpr uint32_t Game_AISituation_Read = 0x0029a160; +// thiscall void (Game::AISystem* this, Mars::Stream* s) // writes ONE `AISysSit` frame and nothing else, and the AISituation it writes is constructed empty on the stack -- `this` is never read. Every AISys body on disk is therefore two empty weight maps regardless of game state [verified] +constexpr uint32_t Game_AISystem_Write = 0x002bda30; +// thiscall bool (Game::AISystem* this, Mars::Stream* s) [verified] +constexpr uint32_t Game_AISystem_Read = 0x002bd960; +// thiscall void (Game::AttribMap* this, Mars::Stream* s) // count = *(this+8) (the tree's _Mysize; _Myhead is at this+4), then a red-black walk writing two NULL-named strings per node -- key at node+0x0c, value at node+0x28, _Isnil at node+0x45. So AttribMap is a std::map [verified] +constexpr uint32_t Game_AttribMap_Write = 0x0019ee60; +// thiscall bool (Game::AttribMap* this, Mars::Stream* s) [verified] +constexpr uint32_t Game_AttribMap_Read = 0x001a8a60; +// thiscall void (Game::AIWeightMap* this, Mars::Stream* s) // NULL-named count = span/0xc, then n x { NULL-named StreamableHelper frame at elem+0, NULL-named float at elem+8 } [verified] +constexpr uint32_t Game_AIWeightMap_ShipSectionID_Write = 0x00296b40; +// thiscall bool (Game::AIWeightMap* this, Mars::Stream* s) [verified] +constexpr uint32_t Game_AIWeightMap_ShipSectionID_Read = 0x002bff00; +// thiscall void (Game::AIWeightMap>* this, Mars::Stream* s) // NULL-named count = span>>3, then n x { NULL-named StreamableHelper> frame at elem+0, NULL-named float at elem+4 } [verified] +constexpr uint32_t Game_AIWeightMap_StreamableEnumUInt_Write = 0x00296c50; +// thiscall bool (Game::AIWeightMap>* this, Mars::Stream* s) [verified] +constexpr uint32_t Game_AIWeightMap_StreamableEnumUInt_Read = 0x002b57c0; +// thiscall void (Game::AIWeightMap>* this, Mars::Stream* s) // same wire shape as the uint instantiation; `AITurnPris` [verified] +constexpr uint32_t Game_AIWeightMap_AIPurposeID_Write = 0x0029b590; +// thiscall bool (Game::AIWeightMap>* this, Mars::Stream* s) [verified] +constexpr uint32_t Game_AIWeightMap_AIPurposeID_Read = 0x002c01a0; +// thiscall void (Game::AIWeightMap>* this, Mars::Stream* s) // same wire shape as the uint instantiation; `AISitWeapFams` [verified] +constexpr uint32_t Game_AIWeightMap_WeaponFamilyID_Write = 0x0029b4c0; +// thiscall bool (Game::AIWeightMap>* this, Mars::Stream* s) [verified] +constexpr uint32_t Game_AIWeightMap_WeaponFamilyID_Read = 0x002bffe0; +// thiscall void (Game::ShipSectionID* this, Mars::Stream* s) // two NULL-named ints, at this+0 and this+4 [verified] +constexpr uint32_t Game_ShipSectionID_Write = 0x0016ed50; +// thiscall bool (Game::ShipSectionID* this, Mars::Stream* s) [verified] +constexpr uint32_t Game_ShipSectionID_Read = 0x0016ed10; +// data void* [3] // { 0x004f7230 scalar-deleting dtor, 0x00697ae0 Read, 0x0054b6e0 Write } [verified] +constexpr uint32_t Mars_StreamableHelper_StreamableEnumUInt_vftable = 0x005e24b8; +// thiscall void (Mars::StreamableHelper>* this, Mars::Stream* s) // writes exactly ONE NULL-named int. So a StreamableEnum member is a FRAME on the wire whose body is a single int -- not a bare int. This is what makes a VectorHelper> a framed array of one-int frames [verified] +constexpr uint32_t Mars_StreamableEnum_Write = 0x0014b6e0; +// thiscall void (Mars::StreamableHelper>* this, Mars::Stream* s) // ReadInt through stream slot +0x10; stores only when the read succeeds [verified] +constexpr uint32_t Mars_StreamableEnum_Read = 0x00297ae0; +// data void* [3] // { 0x004f7230 dtor, 0x00431610 Read, 0x0042f7f0 Write } [verified] +constexpr uint32_t Mars_VectorHelper_StreamableEnumUInt_vftable = 0x005e2438; +// thiscall void (Mars::VectorHelper>* this, Mars::Stream* s) // NULL-named count = span>>2, then n NULL-named FRAMES each written by Mars_StreamableEnum_Write. Backs `nalat`, `SysMem` and `mts`, all of which have count 0 in every save we hold [verified] +constexpr uint32_t Mars_VectorHelper_StreamableEnumUInt_Write = 0x0002f7f0; +// data void* [3] // { 0x004f7230 dtor, 0x006b5600 Read, 0x0069b310 Write }; backs `prs2` [verified] +constexpr uint32_t Mars_VectorHelper_AIPlayerRequestStamp_vftable = 0x0061a700; +// thiscall void (Mars::VectorHelper* this, Mars::Stream* s) // NULL-named count = span>>3, then n NULL-named frames written by Game_AIPlayerRequestStamp_Write. Element stride 8 [verified] +constexpr uint32_t Mars_VectorHelper_AIPlayerRequestStamp_Write = 0x0029b310; +// data void* [3] // { 0x004f7230 dtor, 0x006953b0 Read, 0x00695400 Write } [verified] +constexpr uint32_t Mars_StreamableHelper_AIPlayerRequestStamp_vftable = 0x0061a730; +// thiscall void (Mars::StreamableHelper* this, Mars::Stream* s) // two named ints: `pid` at +0 and `trn` at +4. Game::AIPlayerRequestStamp is a POD with no RTTI class of its own, reached only through this specialised helper, so tools/serializers.py reports 'no serializer' for it and it has no entry in the generated wire table [verified] +constexpr uint32_t Game_AIPlayerRequestStamp_Write = 0x00295400; // thiscall bool (TechTree* this, TechPrereqs* prereqs /* = TechDef + 0x88 */) // RET 4. An AND over groups, each group an OR over techs: a group is satisfied by any listed tech whose node exists in this->nodes AND whose state (+0x14) is 4. Zero groups -> TRUE (the function returns satisfied==total with both 0); a group with ZERO entries -> FALSE and the whole test fails, because the inner loop cannot break and the outer one then exits with that group uncounted. Reads only. Called from SetResearched twice: the unforced completion gate on the argument def, and the availability sweep on each node's self-resolved def [verified] constexpr uint32_t TechTree_PrereqsMet = 0x0017d8e0; // field TechPrereqs prereqs -- the block TechTree::PrereqsMet is called on. Two MSVC vectors back to back: the flat entry array at +0x00 and the group array at +0x10. SetResearched passes `def + 0x88` at both call sites [verified] diff --git a/include/generated/sots_stream_schema.h b/include/generated/sots_stream_schema.h index 83908a0..5f73546 100644 --- a/include/generated/sots_stream_schema.h +++ b/include/generated/sots_stream_schema.h @@ -1,5 +1,5 @@ // GENERATED -- do not edit. Wire schema of Sword of the Stars.exe (GOG 1.8.1). -// Source: sots-re objects/streams.json @ 2308b6e, generated 2026-09-08 by tools/gen_stream_schema.py +// Source: sots-re objects/streams.json @ 805409e, generated 2026-09-08 by tools/gen_stream_schema.py // // For each serializable class, the ordered sequence of items its Mars::IStreamable // Write() puts on the stream. Recovered mechanically from the serializers; the