regenerate both headers (669 addresses); track objects/generated so the shared clone stops sitting dirty
This commit is contained in:
parent
805409ec11
commit
77abd388c7
2 changed files with 3377 additions and 1 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
// GENERATED — do not edit. Facts about Sword of the Stars.exe (GOG 1.8.1).
|
// GENERATED — do not edit. Facts about Sword of the Stars.exe (GOG 1.8.1).
|
||||||
// Source: sots-re ghidra/addresses.json @ ae00053, 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).
|
// Runtime address = (uintptr_t)GetModuleHandle(NULL) + RVA (the exe is ASLR-relocated).
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
@ -1237,6 +1237,64 @@ constexpr uint32_t Game_StarSystem_OutputRates_Write = 0x00345190;
|
||||||
constexpr uint32_t Game_StarSystem_OutputRates_Read = 0x003472a0;
|
constexpr uint32_t Game_StarSystem_OutputRates_Read = 0x003472a0;
|
||||||
// layout sizeof(Game::StarSystem::OutputRates) -- enumeration meets embedding [verified]
|
// layout sizeof(Game::StarSystem::OutputRates) -- enumeration meets embedding [verified]
|
||||||
constexpr uint32_t sizeof_Game_StarSystem_OutputRates = 0x0000001c;
|
constexpr uint32_t sizeof_Game_StarSystem_OutputRates = 0x0000001c;
|
||||||
|
// thiscall 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) [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<ShipSectionID> 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<ShipSectionID> at this+0, AISitWeapFams = AIWeightMap<StreamableEnum<WeaponFamilyID>> 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<Mars::String, Mars::String> [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<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 } [verified]
|
||||||
|
constexpr uint32_t Game_AIWeightMap_ShipSectionID_Write = 0x00296b40;
|
||||||
|
// thiscall bool (Game::AIWeightMap<Game::ShipSectionID>* this, Mars::Stream* s) [verified]
|
||||||
|
constexpr uint32_t Game_AIWeightMap_ShipSectionID_Read = 0x002bff00;
|
||||||
|
// thiscall 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 } [verified]
|
||||||
|
constexpr uint32_t Game_AIWeightMap_StreamableEnumUInt_Write = 0x00296c50;
|
||||||
|
// thiscall bool (Game::AIWeightMap<Mars::StreamableEnum<unsigned int>>* this, Mars::Stream* s) [verified]
|
||||||
|
constexpr uint32_t Game_AIWeightMap_StreamableEnumUInt_Read = 0x002b57c0;
|
||||||
|
// thiscall void (Game::AIWeightMap<Mars::StreamableEnum<Game::AIPurposeID>>* 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<Mars::StreamableEnum<Game::AIPurposeID>>* this, Mars::Stream* s) [verified]
|
||||||
|
constexpr uint32_t Game_AIWeightMap_AIPurposeID_Read = 0x002c01a0;
|
||||||
|
// thiscall void (Game::AIWeightMap<Mars::StreamableEnum<Game::WeaponFamilyID>>* 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<Mars::StreamableEnum<Game::WeaponFamilyID>>* 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<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 [verified]
|
||||||
|
constexpr uint32_t Mars_StreamableEnum_Write = 0x0014b6e0;
|
||||||
|
// thiscall void (Mars::StreamableHelper<Mars::StreamableEnum<T>>* 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<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 [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<Game::AIPlayerRequestStamp>* 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<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 [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]
|
// 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;
|
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]
|
// 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]
|
||||||
|
|
@ -1261,5 +1319,31 @@ constexpr uint32_t TechTree_ProcessResearch_TechsUnlockedCollector = 0x00187cc3;
|
||||||
constexpr uint32_t ServerPlayer_OnTechResearched_RecordObservedTech = 0x00491790;
|
constexpr uint32_t ServerPlayer_OnTechResearched_RecordObservedTech = 0x00491790;
|
||||||
// site site in ServerPlayer::OnTechResearched, second statement: `if (this->ResT(+0x294) == def) { if (this->ResearchRollPending(+0x3b4)) RollResearchEvent(this); this->ResearchRollPending = 0; this->ResT = 0; }`. RollResearchEvent (0x0088df20) draws EXACTLY ONE NextFloat unconditionally and then enters 0x00889d60 only when roll < ResearchEventOdds -- the odds are 0 for every tech outside the plague and AI-rebellion families, so that branch is normally dead. This is the one extra RNG word a completion consumes, and clearing ResT means a second completion in the same pass consumes none [verified]
|
// site site in ServerPlayer::OnTechResearched, second statement: `if (this->ResT(+0x294) == def) { if (this->ResearchRollPending(+0x3b4)) RollResearchEvent(this); this->ResearchRollPending = 0; this->ResT = 0; }`. RollResearchEvent (0x0088df20) draws EXACTLY ONE NextFloat unconditionally and then enters 0x00889d60 only when roll < ResearchEventOdds -- the odds are 0 for every tech outside the plague and AI-rebellion families, so that branch is normally dead. This is the one extra RNG word a completion consumes, and clearing ResT means a second completion in the same pass consumes none [verified]
|
||||||
constexpr uint32_t ServerPlayer_OnTechResearched_ResearchRollBlock = 0x00491790;
|
constexpr uint32_t ServerPlayer_OnTechResearched_ResearchRollBlock = 0x00491790;
|
||||||
|
// cdecl Game::SVScriptObject* (int encID) // The EncObj factory. `dec eax; cmp eax,0x16; ja <null>; jmp dword [eax*4 + 0x0052bf60]` -- a 23-entry dword jump table indexed by encID-1. Live ids: 1 VonNeumann, 3 Swarm, 4 Derelict, 5 Monitor, 7 SystemKiller, 8 PuppetMaster, 9 SlaversRefuel, 10 SwarmQueen, 14 Locust, 17 CrowRuins, 20 Refugees, 21 Ortgay. Ids 2, 6, 11-13, 15, 16, 18, 19, 22, 23 and everything outside 1..23 return NULL. Class names read off the vftable store in each ctor [verified]
|
||||||
|
constexpr uint32_t SVScriptObject_FactoryByEncID = 0x0012bf00;
|
||||||
|
// data void* [23] // the jump table SVScriptObject_FactoryByEncID indexes with encID-1 [verified]
|
||||||
|
constexpr uint32_t SVScriptObject_EncIDJumpTable = 0x0012bf60;
|
||||||
|
// thiscall Game::SVScriptObject* (Game::SVSOSots* this, int encID) // scans the loaded (id, obj) pair vector at this+0x0C..0x10 first and only calls SVScriptObject_FactoryByEncID on a miss [verified]
|
||||||
|
constexpr uint32_t SVSOSots_GetOrCreateEncObj = 0x001a4450;
|
||||||
|
// cdecl Game::SVScriptObject* (const char* xscn) // the xsc factory: a flat four-way _stricmp chain, EXHAUSTIVE. "traps" -> Game::SVSOTraps (ctor 0x0052cbb0), "crowdefs" -> Game::SVSOCrowDefenders (0x0052b3c0), "indsys" -> Game::SVSOIndependentSystems (0x0075b530), "gmtrigger" -> Game::SVSOGrandMenaceTrigger (0x004f5630). Falls through with "Error creating extra script %s." [verified]
|
||||||
|
constexpr uint32_t SVScriptObject_FactoryByScenarioName = 0x001a7050;
|
||||||
|
// thiscall void (Game::SVSOSots* this) // registers exactly traps, crowdefs, indsys and -- only when ScnObj == NULL -- gmtrigger. Corroborates that the four scenario names are the whole set [verified]
|
||||||
|
constexpr uint32_t SVSOSots_SeedNewGameScripts = 0x001a7d70;
|
||||||
|
// thiscall void (Game::SVSOSots* this, Mars::IStream* s) // slot 2 of vftable 0x00A063C4. Emits ScnID, ScnObj (only when non-NULL), numx x (xscn, xsc), NEncObjs x (EncID, EncObj) [verified]
|
||||||
|
constexpr uint32_t SVSOSots_Write = 0x0019ddf0;
|
||||||
|
// thiscall void (Game::SVSOSots* this, Mars::IStream* s) // slot 1. Accepts two tags Write never emits -- NPCPlr (int, first) and hastraps (bool) with a following traps object -- read-only backward compatibility; a writer that omits them is correct [verified]
|
||||||
|
constexpr uint32_t SVSOSots_Read = 0x001a7a40;
|
||||||
|
// data Game::SVSOSots vftable (slot0 dtor, slot1 Read 0x005a7a40, slot2 Write 0x0059ddf0) [verified]
|
||||||
|
constexpr uint32_t SVSOSots_vftable = 0x006063c4;
|
||||||
|
// data Game::SVSOIndependentSystems vftable. slot0 dtor 0x0075afb0; slot1 Read AND slot2 Write are both 0x005f8ac0, the shared `ret 4` no-op stub -- so the "indsys" frame is genuinely empty on disk and the class's 0x1c4-byte body is runtime-only state [verified]
|
||||||
|
constexpr uint32_t SVSOIndependentSystems_vftable = 0x00620314;
|
||||||
|
// thiscall void (void*, Mars::IStream*) // `C2 04 00` -- a bare RET 4 shared as the inherited Read/Write for classes that serialize nothing [verified]
|
||||||
|
constexpr uint32_t Streamable_NoOpStub = 0x001f8ac0;
|
||||||
|
// thiscall void (Game::SVSOCrowDefenders* this, Mars::IStream* s) // sys; ndsys count then a loop writing dsys; ndes count then a loop writing des; drad. NOTE: `dsys` is INSIDE the ndsys loop -- objects/layouts.json records it as a plain member, which is wrong, and no save can settle it because both counts are 0 everywhere [verified]
|
||||||
|
constexpr uint32_t SVSOCrowDefenders_Write = 0x000f8c90;
|
||||||
|
// thiscall void (Game::SVSOMonitor* this, Mars::IStream* s) // calls SVSODerelict::Write (0x004fc2b0) as its first act -- Monitor derives from Derelict, which is why its tag run starts NDsn/DsnID/Dwght + NAsg/Eflt/Esys before nt/scnm/spwt/rsmd/dsgn [verified]
|
||||||
|
constexpr uint32_t SVSOMonitor_Write = 0x000fd810;
|
||||||
|
// thiscall void (Game::SVSODerelict* this, Mars::IStream* s) // NDsn count then a loop of (DsnID, Dwght); NAsg count then a loop of (Eflt, Esys). Two fields per iteration in each, confirmed by the 8-byte element strides [verified]
|
||||||
|
constexpr uint32_t SVSODerelict_Write = 0x000fc2b0;
|
||||||
|
|
||||||
} // namespace sots::addr
|
} // namespace sots::addr
|
||||||
|
|
|
||||||
3292
objects/generated/sots_stream_schema.h
Normal file
3292
objects/generated/sots_stream_schema.h
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue