paavohtl Claude Opus 4.6 (1M context) commited on
Commit
47c8e50
Β·
1 Parent(s): 72a7fdf

feat: add passthrough hooks for 6 more InitGameState constructors (Groups F+G)

Browse files

Group F (display objects):
- DisplayGfx__ConstructFull (0x563FC0): stdcall(5), RET 0x14
- DDDisplay__ConstructTextbox (0x4FAF00): stdcall(3), RET 0xC
- DDGame__InitWeaponPanel (0x567770): stdcall(1), RET 0x4

Group G (buffer/stream objects):
- BufferObject__Constructor (0x545FD0): stdcall(3), RET 0xC
- GameStateStream__Init (0x4FB490): stdcall(1), RET 0x4
- DisplayObject__Constructor (0x540440): stdcall(2), RET 0x8

All no-log passthroughs (heap allocation in logging clobbers registers).
All 6 named in Ghidra. Total: 12 stdcall + 7 pure Rust = 19 hooks on
InitGameState sub-functions.

Headful + headless replay tests PASS.

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

crates/openwa-core/src/address.rs CHANGED
@@ -376,6 +376,18 @@ pub mod va {
376
  pub const TURN_GAME_CONSTRUCTOR: u32 = 0x0055_B280;
377
  /// CTaskGameState__Constructor (0x532330): stdcall(this, param), RET 0x8.
378
  pub const GAME_STATE_CONSTRUCTOR: u32 = 0x0053_2330;
 
 
 
 
 
 
 
 
 
 
 
 
379
  /// DDGame__InitFeatureFlags (0x524700): stdcall(wrapper), RET 0x4.
380
  pub const DDGAME_INIT_FEATURE_FLAGS: u32 = 0x0052_4700;
381
  /// DDGame__InitDisplayFinal_Maybe (0x56A830): display finalization for non-headless.
 
376
  pub const TURN_GAME_CONSTRUCTOR: u32 = 0x0055_B280;
377
  /// CTaskGameState__Constructor (0x532330): stdcall(this, param), RET 0x8.
378
  pub const GAME_STATE_CONSTRUCTOR: u32 = 0x0053_2330;
379
+ /// DisplayGfx__ConstructFull (0x563FC0): stdcall(5 params), RET 0x14.
380
+ pub const DISPLAYGFX_CONSTRUCT_FULL: u32 = 0x0056_3FC0;
381
+ /// DDDisplay__ConstructTextbox (0x4FAF00): stdcall(3 params), RET 0xC.
382
+ pub const CONSTRUCT_TEXTBOX: u32 = 0x004F_AF00;
383
+ /// FUN_567770 (0x567770): stdcall(1 param = wrapper), RET 0x4.
384
+ pub const FUN_567770: u32 = 0x0056_7770;
385
+ /// FUN_545FD0 (0x545FD0): stdcall(3 params), RET 0xC. Buffer object constructor.
386
+ pub const BUFFER_OBJECT_CONSTRUCTOR: u32 = 0x0054_5FD0;
387
+ /// FUN_4FB490 (0x4FB490): stdcall(1 param), RET 0x4. GameStateStream sub-init.
388
+ pub const GAME_STATE_STREAM_INIT: u32 = 0x004F_B490;
389
+ /// FUN_540440 (0x540440): stdcall(2 params), RET 0x8. Display object constructor.
390
+ pub const DISPLAY_OBJECT_CONSTRUCTOR: u32 = 0x0054_0440;
391
  /// DDGame__InitFeatureFlags (0x524700): stdcall(wrapper), RET 0x4.
392
  pub const DDGAME_INIT_FEATURE_FLAGS: u32 = 0x0052_4700;
393
  /// DDGame__InitDisplayFinal_Maybe (0x56A830): display finalization for non-headless.
crates/openwa-wormkit/src/replacements/game_state_hooks.rs CHANGED
@@ -16,6 +16,12 @@ static mut INIT_TEAMS_ORIG: *const () = core::ptr::null();
16
  static mut TEAM_MANAGER_ORIG: *const () = core::ptr::null();
17
  static mut TURN_GAME_ORIG: *const () = core::ptr::null();
18
  static mut GAME_STATE_ORIG: *const () = core::ptr::null();
 
 
 
 
 
 
19
 
20
  // ─── Passthrough hooks ──────────────────────────────────────────────────────
21
 
@@ -69,6 +75,54 @@ unsafe extern "stdcall" fn hook_game_state(this: u32, param: u32) -> u32 {
69
  orig(this, param)
70
  }
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  // ─── Hook installation ──────────────────────────────────────────────────────
73
 
74
  pub fn install() -> Result<(), String> {
@@ -107,6 +161,44 @@ pub fn install() -> Result<(), String> {
107
  va::GAME_STATE_CONSTRUCTOR,
108
  hook_game_state as *const (),
109
  )? as *const ();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  }
111
 
112
  Ok(())
 
16
  static mut TEAM_MANAGER_ORIG: *const () = core::ptr::null();
17
  static mut TURN_GAME_ORIG: *const () = core::ptr::null();
18
  static mut GAME_STATE_ORIG: *const () = core::ptr::null();
19
+ static mut DISPLAYGFX_FULL_ORIG: *const () = core::ptr::null();
20
+ static mut TEXTBOX_ORIG: *const () = core::ptr::null();
21
+ static mut WEAPON_PANEL_ORIG: *const () = core::ptr::null();
22
+ static mut BUFFER_OBJ_ORIG: *const () = core::ptr::null();
23
+ static mut STREAM_INIT_ORIG: *const () = core::ptr::null();
24
+ static mut DISPLAY_OBJ_ORIG: *const () = core::ptr::null();
25
 
26
  // ─── Passthrough hooks ──────────────────────────────────────────────────────
27
 
 
75
  orig(this, param)
76
  }
77
 
78
+ // ─── Group F: Display objects ────────────────────────────────────────────────
79
+
80
+ // DisplayGfx__ConstructFull (0x563FC0): stdcall(5 params), RET 0x14
81
+ unsafe extern "stdcall" fn hook_displaygfx_full(
82
+ p1: u32,
83
+ p2: u32,
84
+ p3: u32,
85
+ p4: u32,
86
+ p5: u32,
87
+ ) -> u32 {
88
+ let orig: unsafe extern "stdcall" fn(u32, u32, u32, u32, u32) -> u32 =
89
+ core::mem::transmute(DISPLAYGFX_FULL_ORIG);
90
+ orig(p1, p2, p3, p4, p5)
91
+ }
92
+
93
+ // DDDisplay__ConstructTextbox (0x4FAF00): stdcall(3 params), RET 0xC
94
+ unsafe extern "stdcall" fn hook_textbox(p1: u32, p2: u32, p3: u32) -> u32 {
95
+ let orig: unsafe extern "stdcall" fn(u32, u32, u32) -> u32 = core::mem::transmute(TEXTBOX_ORIG);
96
+ orig(p1, p2, p3)
97
+ }
98
+
99
+ // DDGame__InitWeaponPanel (0x567770): stdcall(1 param = wrapper), RET 0x4
100
+ unsafe extern "stdcall" fn hook_weapon_panel(wrapper: u32) -> u32 {
101
+ let orig: unsafe extern "stdcall" fn(u32) -> u32 = core::mem::transmute(WEAPON_PANEL_ORIG);
102
+ orig(wrapper)
103
+ }
104
+
105
+ // ─── Group G: Buffer/stream objects ─────────────────────────────────────────
106
+
107
+ // BufferObject__Constructor (0x545FD0): stdcall(3 params), RET 0xC
108
+ unsafe extern "stdcall" fn hook_buffer_obj(p1: u32, p2: u32, p3: u32) -> u32 {
109
+ let orig: unsafe extern "stdcall" fn(u32, u32, u32) -> u32 =
110
+ core::mem::transmute(BUFFER_OBJ_ORIG);
111
+ orig(p1, p2, p3)
112
+ }
113
+
114
+ // GameStateStream__Init (0x4FB490): stdcall(1 param), RET 0x4
115
+ unsafe extern "stdcall" fn hook_stream_init(p1: u32) -> u32 {
116
+ let orig: unsafe extern "stdcall" fn(u32) -> u32 = core::mem::transmute(STREAM_INIT_ORIG);
117
+ orig(p1)
118
+ }
119
+
120
+ // DisplayObject__Constructor (0x540440): stdcall(2 params), RET 0x8
121
+ unsafe extern "stdcall" fn hook_display_obj(p1: u32, p2: u32) -> u32 {
122
+ let orig: unsafe extern "stdcall" fn(u32, u32) -> u32 = core::mem::transmute(DISPLAY_OBJ_ORIG);
123
+ orig(p1, p2)
124
+ }
125
+
126
  // ─── Hook installation ──────────────────────────────────────────────────────
127
 
128
  pub fn install() -> Result<(), String> {
 
161
  va::GAME_STATE_CONSTRUCTOR,
162
  hook_game_state as *const (),
163
  )? as *const ();
164
+
165
+ // Group F: Display objects
166
+ DISPLAYGFX_FULL_ORIG = hook::install(
167
+ "DisplayGfx__ConstructFull",
168
+ va::DISPLAYGFX_CONSTRUCT_FULL,
169
+ hook_displaygfx_full as *const (),
170
+ )? as *const ();
171
+
172
+ TEXTBOX_ORIG = hook::install(
173
+ "DDDisplay__ConstructTextbox",
174
+ va::CONSTRUCT_TEXTBOX,
175
+ hook_textbox as *const (),
176
+ )? as *const ();
177
+
178
+ WEAPON_PANEL_ORIG = hook::install(
179
+ "DDGame__InitWeaponPanel",
180
+ va::FUN_567770,
181
+ hook_weapon_panel as *const (),
182
+ )? as *const ();
183
+
184
+ // Group G: Buffer/stream objects
185
+ BUFFER_OBJ_ORIG = hook::install(
186
+ "BufferObject__Constructor",
187
+ va::BUFFER_OBJECT_CONSTRUCTOR,
188
+ hook_buffer_obj as *const (),
189
+ )? as *const ();
190
+
191
+ STREAM_INIT_ORIG = hook::install(
192
+ "GameStateStream__Init",
193
+ va::GAME_STATE_STREAM_INIT,
194
+ hook_stream_init as *const (),
195
+ )? as *const ();
196
+
197
+ DISPLAY_OBJ_ORIG = hook::install(
198
+ "DisplayObject__Constructor",
199
+ va::DISPLAY_OBJECT_CONSTRUCTOR,
200
+ hook_display_obj as *const (),
201
+ )? as *const ();
202
  }
203
 
204
  Ok(())