feat: add passthrough hooks for 6 more InitGameState constructors (Groups F+G)
Browse filesGroup 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(())
|