paavohtl Claude Opus 4.6 (1M context) commited on
Commit
c7109bc
·
1 Parent(s): 7c2aa5e

docs: add InitGameState porting plan

Browse files

Incremental strategy: 7 usercall functions ported to pure Rust (Groups A-C),
10 stdcall constructors hooked individually (Groups D-G), with headful+headless
replay tests after each group.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

docs/plans/2026-03-19-init-game-state-design.md ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # DDGame__InitGameState Porting Plan
2
+
3
+ ## Overview
4
+
5
+ Port `DDGame__InitGameState` (0x526500, 1226 decompiled lines) using the same
6
+ incremental strategy as the DDGame constructor: port sub-functions individually
7
+ as hooks, test each group, then eventually combine into a full Rust replacement.
8
+
9
+ InitGameState is called once after the DDGame constructor. It creates all runtime
10
+ game objects: HUD panel, weapon table, team arena, turn game task, camera state,
11
+ scoring, alliance data, and more.
12
+
13
+ ## Structure
14
+
15
+ InitGameState is actually two merged functions:
16
+ - Wrapper (0x526500-0x52657B): SEH setup, copies 2 scheme bytes, calls FUN_541620
17
+ - Falls through into CTaskGameState__vmethod_7 (0x52657C, ~2000 instructions)
18
+
19
+ `param_1` = DDGameWrapper. `param_1+0x488` = DDGame. `DDGame+0x24` = GameInfo/scheme.
20
+
21
+ ## Phase 1: Port usercall functions to pure Rust
22
+
23
+ All 7 usercall functions are small (<80 lines), mostly pure field writes, and
24
+ have zero or minimal dependencies. Porting them eliminates naked asm bridges.
25
+
26
+ ### Group A — Zero-dependency functions (port first, test)
27
+
28
+ | Function | Address | Lines | What it does |
29
+ |---|---|---|---|
30
+ | FUN_541620 | 0x541620 | ~15 | Sprite/gfx table init (fastcall ECX,EDX, loop + 3 fields) |
31
+ | FUN_541060 | 0x541060 | ~15 | Buffer alloc constructor (EAX=size, ESI=output, calls wa_malloc) |
32
+
33
+ ### Group B — Team/scoring init (port, test)
34
+
35
+ | Function | Address | Lines | What it does |
36
+ |---|---|---|---|
37
+ | InitTeamScoring | 0x528510 | ~65 | Pure field writes to CGameTask scoring arrays, zero calls |
38
+ | InitAllianceData | 0x5262D0 | ~80 | Alliance bitmask computation, pure field writes + bitmath |
39
+
40
+ ### Group C — Turn state + weapon availability (port, test)
41
+
42
+ | Function | Address | Lines | What it does |
43
+ |---|---|---|---|
44
+ | InitTurnState | 0x528690 | ~80 | DDGame turn fields + camera center. Calls FUN_524700 (bridge) |
45
+ | FUN_53FFC0 | 0x53FFC0 | ~50 | Weapon availability switch (port FUN_565960 ~20 lines too) |
46
+ | FUN_528480 | 0x528480 | ~20 | Post-init: scheme flag + 1 vtable dispatch |
47
+
48
+ ### Bridge (defer porting)
49
+
50
+ | Function | Address | Lines | Why |
51
+ |---|---|---|---|
52
+ | FUN_524700 | 0x524700 | ~600 | Scheme-version feature flags. Pure computation but massive. |
53
+
54
+ ## Phase 2: Hook stdcall constructors individually
55
+
56
+ All verified via RET instruction. Hook each, test in isolation.
57
+
58
+ ### Group D — Core game objects
59
+
60
+ | Function | Address | RET | Params | Creates |
61
+ |---|---|---|---|---|
62
+ | HudPanel__Constructor | 0x524070 | 0x4 | 1 | DDGame+0x534 |
63
+ | InitWeaponTable | 0x53CAB0 | 0x4 | 1 | Weapon table setup |
64
+ | InitTeamsFromSetup | 0x5220B0 | 0x8 | 2 | DDGame+0x4628 team arena |
65
+
66
+ ### Group E — Task objects
67
+
68
+ | Function | Address | RET | Params | Creates |
69
+ |---|---|---|---|---|
70
+ | TeamManager__Constructor | 0x563D40 | 0x8 | 2 | DDGame+0x530 |
71
+ | CTaskTurnGame__Constructor | 0x55B280 | 0x8 | 2 | Turn game task |
72
+ | CTaskGameState__Constructor | 0x532330 | 0x8 | 2 | Game state task |
73
+
74
+ ### Group F — Display objects
75
+
76
+ | Function | Address | RET | Params | Creates |
77
+ |---|---|---|---|---|
78
+ | DisplayGfx__Constructor | 0x563FC0 | 0x14 | 5 | Full display gfx |
79
+ | DDDisplay__ConstructTextbox | 0x4FAF00 | 0xC | 3 | Textbox |
80
+ | FUN_567770 | 0x567770 | 0x4 | 1 | Final conditional display ctor |
81
+
82
+ ### Group G — Buffer/stream objects
83
+
84
+ | Function | Address | RET | Params | Creates |
85
+ |---|---|---|---|---|
86
+ | FUN_545FD0 | 0x545FD0 | 0xC | 3 | Buffer object (called twice) |
87
+ | FUN_4FB490 | 0x4FB490 | 0x4 | 1 | GameStateStream sub-init |
88
+
89
+ ## Testing Strategy
90
+
91
+ - Run headful + headless replay tests after each group (A, B, C, D, E, F, G)
92
+ - Headless MUST pass (deterministic output match) before proceeding
93
+ - Headful validates no crashes, correct rendering, game completion
94
+ - Name all functions in Ghidra as they're analyzed
95
+
96
+ ## Naming Convention
97
+
98
+ Functions ported to Rust: `init_sprite_table`, `init_team_scoring`, etc.
99
+ Functions bridged via FFI: `wa_init_feature_flags` (for FUN_524700)
100
+ Ghidra labels: `CGameTask__InitTeamScoring`, `CGameTask__InitAllianceData`, etc.