Game::StrategyAIAgent::Streamable typed end to end. The writer is entirely unconditional; the branch the decompiler shows is an inlined vector destructor whose operator delete is marked noreturn. dsh is a std::map's _Mysize, so it is the (pid, trns) count and not a scalar; lnat and lat are scalars, not elements. AISystem::Write never reads its object, so every AISys body on disk is empty regardless of game state. StreamableEnum<T> is a frame holding one int, which makes SysMem/mts/nalat arrays of frames rather than of ints. Named coverage 98.0% -> 99.9% on all four saves; state_checksum.py unchanged and still PROVED. Section 7 lists the ten element layouts no save exercises and says what workload would settle each. 29 addresses in the per-lane fragment; merges to 669 with no duplicate name.
236 lines
11 KiB
JSON
236 lines
11 KiB
JSON
{
|
|
"entries": [
|
|
{
|
|
"name": "Game_StrategyAIAgent_Streamable_Write",
|
|
"addr": "0x006c6f00",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Game::StrategyAIAgent::Streamable* this, Mars::Stream* s) // the body of every `Player.<id>.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)",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_StrategyAIAgent_Streamable_Read",
|
|
"addr": "0x006c8fd0",
|
|
"convention": "thiscall",
|
|
"prototype": "bool (Game::StrategyAIAgent::Streamable* this, Mars::Stream* s)",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_StrategyAIAgent_DesignNameGen_Write",
|
|
"addr": "0x006c77a0",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Game::StrategyAIAgent::DesignNameGen* this, Mars::Stream* s) // `dnnc` = (this+8 - this+4)/0x24, then dnnc x { dnid: StreamableHelper<ShipSectionID> at elem+0, dnnm: WriteString at elem+8 }. Element stride 0x24 = ShipSectionID(8) + Mars::String(0x1c)",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_StrategyAIAgent_DesignNameGen_Read",
|
|
"addr": "0x006ccc70",
|
|
"convention": "thiscall",
|
|
"prototype": "bool (Game::StrategyAIAgent::DesignNameGen* this, Mars::Stream* s)",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AISituation_Write",
|
|
"addr": "0x0069a220",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Game::AISituation* this, Mars::Stream* s) // AISitSecs = AIWeightMap<ShipSectionID> at this+0, AISitWeapFams = AIWeightMap<StreamableEnum<WeaponFamilyID>> at this+0x10. sizeof >= 0x20",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AISituation_Read",
|
|
"addr": "0x0069a160",
|
|
"convention": "thiscall",
|
|
"prototype": "bool (Game::AISituation* this, Mars::Stream* s)",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AISystem_Write",
|
|
"addr": "0x006bda30",
|
|
"convention": "thiscall",
|
|
"prototype": "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",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AISystem_Read",
|
|
"addr": "0x006bd960",
|
|
"convention": "thiscall",
|
|
"prototype": "bool (Game::AISystem* this, Mars::Stream* s)",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AttribMap_Write",
|
|
"addr": "0x0059ee60",
|
|
"convention": "thiscall",
|
|
"prototype": "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<Mars::String, Mars::String>",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AttribMap_Read",
|
|
"addr": "0x005a8a60",
|
|
"convention": "thiscall",
|
|
"prototype": "bool (Game::AttribMap* this, Mars::Stream* s)",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AIWeightMap_ShipSectionID_Write",
|
|
"addr": "0x00696b40",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Game::AIWeightMap<Game::ShipSectionID>* this, Mars::Stream* s) // NULL-named count = span/0xc, then n x { NULL-named StreamableHelper<ShipSectionID> frame at elem+0, NULL-named float at elem+8 }",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AIWeightMap_ShipSectionID_Read",
|
|
"addr": "0x006bff00",
|
|
"convention": "thiscall",
|
|
"prototype": "bool (Game::AIWeightMap<Game::ShipSectionID>* this, Mars::Stream* s)",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AIWeightMap_StreamableEnumUInt_Write",
|
|
"addr": "0x00696c50",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Game::AIWeightMap<Mars::StreamableEnum<unsigned int>>* this, Mars::Stream* s) // NULL-named count = span>>3, then n x { NULL-named StreamableHelper<StreamableEnum<uint>> frame at elem+0, NULL-named float at elem+4 }",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AIWeightMap_StreamableEnumUInt_Read",
|
|
"addr": "0x006b57c0",
|
|
"convention": "thiscall",
|
|
"prototype": "bool (Game::AIWeightMap<Mars::StreamableEnum<unsigned int>>* this, Mars::Stream* s)",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AIWeightMap_AIPurposeID_Write",
|
|
"addr": "0x0069b590",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Game::AIWeightMap<Mars::StreamableEnum<Game::AIPurposeID>>* this, Mars::Stream* s) // same wire shape as the uint instantiation; `AITurnPris`",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AIWeightMap_AIPurposeID_Read",
|
|
"addr": "0x006c01a0",
|
|
"convention": "thiscall",
|
|
"prototype": "bool (Game::AIWeightMap<Mars::StreamableEnum<Game::AIPurposeID>>* this, Mars::Stream* s)",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AIWeightMap_WeaponFamilyID_Write",
|
|
"addr": "0x0069b4c0",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Game::AIWeightMap<Mars::StreamableEnum<Game::WeaponFamilyID>>* this, Mars::Stream* s) // same wire shape as the uint instantiation; `AISitWeapFams`",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AIWeightMap_WeaponFamilyID_Read",
|
|
"addr": "0x006bffe0",
|
|
"convention": "thiscall",
|
|
"prototype": "bool (Game::AIWeightMap<Mars::StreamableEnum<Game::WeaponFamilyID>>* this, Mars::Stream* s)",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_ShipSectionID_Write",
|
|
"addr": "0x0056ed50",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Game::ShipSectionID* this, Mars::Stream* s) // two NULL-named ints, at this+0 and this+4",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_ShipSectionID_Read",
|
|
"addr": "0x0056ed10",
|
|
"convention": "thiscall",
|
|
"prototype": "bool (Game::ShipSectionID* this, Mars::Stream* s)",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Mars_StreamableHelper_StreamableEnumUInt_vftable",
|
|
"addr": "0x009e24b8",
|
|
"convention": "data",
|
|
"prototype": "void* [3] // { 0x004f7230 scalar-deleting dtor, 0x00697ae0 Read, 0x0054b6e0 Write }",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Mars_StreamableEnum_Write",
|
|
"addr": "0x0054b6e0",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Mars::StreamableHelper<Mars::StreamableEnum<T>>* 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<StreamableEnum<T>> a framed array of one-int frames",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Mars_StreamableEnum_Read",
|
|
"addr": "0x00697ae0",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Mars::StreamableHelper<Mars::StreamableEnum<T>>* this, Mars::Stream* s) // ReadInt through stream slot +0x10; stores only when the read succeeds",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Mars_VectorHelper_StreamableEnumUInt_vftable",
|
|
"addr": "0x009e2438",
|
|
"convention": "data",
|
|
"prototype": "void* [3] // { 0x004f7230 dtor, 0x00431610 Read, 0x0042f7f0 Write }",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Mars_VectorHelper_StreamableEnumUInt_Write",
|
|
"addr": "0x0042f7f0",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Mars::VectorHelper<Mars::StreamableEnum<unsigned int>>* 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",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Mars_VectorHelper_AIPlayerRequestStamp_vftable",
|
|
"addr": "0x00a1a700",
|
|
"convention": "data",
|
|
"prototype": "void* [3] // { 0x004f7230 dtor, 0x006b5600 Read, 0x0069b310 Write }; backs `prs2`",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Mars_VectorHelper_AIPlayerRequestStamp_Write",
|
|
"addr": "0x0069b310",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Mars::VectorHelper<Game::AIPlayerRequestStamp>* this, Mars::Stream* s) // NULL-named count = span>>3, then n NULL-named frames written by Game_AIPlayerRequestStamp_Write. Element stride 8",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Mars_StreamableHelper_AIPlayerRequestStamp_vftable",
|
|
"addr": "0x00a1a730",
|
|
"convention": "data",
|
|
"prototype": "void* [3] // { 0x004f7230 dtor, 0x006953b0 Read, 0x00695400 Write }",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
},
|
|
{
|
|
"name": "Game_AIPlayerRequestStamp_Write",
|
|
"addr": "0x00695400",
|
|
"convention": "thiscall",
|
|
"prototype": "void (Mars::StreamableHelper<Game::AIPlayerRequestStamp>* 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",
|
|
"status": "verified",
|
|
"source": "findings/objects/aiagent-block.md (lane A 2026-09-08)"
|
|
}
|
|
]
|
|
}
|