fix: correct SpriteRegion params from hook data + pass gfx_resource
Browse filesSpriteRegion params 4-8 were completely wrong (guessed from asm,
not verified). Hooked SpriteRegion__Constructor with naked fastcall
trampoline to capture actual params from original:
- Entries 4-8: ECX/EDX values were wrong (0x21β0x0C, etc.)
- p6 (6th stack param): was 0, should be GfxResource pointer
2/5 runs now pass. Crash moved to GfxDir__FindEntry in arrow loop β
likely a calling convention issue in the arrow sprite loading section.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-core/src/engine/ddgame.rs
CHANGED
|
@@ -818,16 +818,19 @@ unsafe fn init_graphics_and_resources(
|
|
| 818 |
// ββ 8Γ SpriteRegion at DDGame+0x46C..0x488 ββ
|
| 819 |
// SpriteRegion__Constructor: fastcall(ECX, EDX) + 6 stack(this, p2, p3, p4, p5, p6), RET 0x18
|
| 820 |
{
|
| 821 |
-
//
|
|
|
|
|
|
|
|
|
|
| 822 |
let regions: [(u32, u32, u32, u32, u32, u32, u32, u32); 8] = [
|
| 823 |
-
(0x474, 0x37, 0x36, 0x2E, 0x24, 0x41, 0x2D,
|
| 824 |
-
(0x46C, 0x30, 0x0C, 0x2D, 0x07, 0x34, 0x09,
|
| 825 |
-
(0x470, 0x11, 0x1A, 0x0D, 0x0A, 0x16, 0x13,
|
| 826 |
-
(0x478,
|
| 827 |
-
(0x47C,
|
| 828 |
-
(0x484,
|
| 829 |
-
(0x488,
|
| 830 |
-
(0x480,
|
| 831 |
];
|
| 832 |
|
| 833 |
for &(offset, ecx, edx, p2, p3, p4, p5, p6) in ®ions {
|
|
|
|
| 818 |
// ββ 8Γ SpriteRegion at DDGame+0x46C..0x488 ββ
|
| 819 |
// SpriteRegion__Constructor: fastcall(ECX, EDX) + 6 stack(this, p2, p3, p4, p5, p6), RET 0x18
|
| 820 |
{
|
| 821 |
+
// Params verified by hooking original (see SpriteRegion param logger).
|
| 822 |
+
// (ddgame_offset, ECX, EDX, p2, p3, p4, p5, p6=gfx_resource)
|
| 823 |
+
// p6 is the GfxResource pointer returned by GfxResource__Create_Maybe.
|
| 824 |
+
let gr = gfx_resource as u32;
|
| 825 |
let regions: [(u32, u32, u32, u32, u32, u32, u32, u32); 8] = [
|
| 826 |
+
(0x474, 0x37, 0x36, 0x2E, 0x24, 0x41, 0x2D, gr),
|
| 827 |
+
(0x46C, 0x30, 0x0C, 0x2D, 0x07, 0x34, 0x09, gr),
|
| 828 |
+
(0x470, 0x11, 0x1A, 0x0D, 0x0A, 0x16, 0x13, gr),
|
| 829 |
+
(0x478, 0x0C, 0x3D, 0x00, 0x20, 0x18, 0x33, gr),
|
| 830 |
+
(0x47C, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, gr),
|
| 831 |
+
(0x484, 0x1A2,0x1B, 0x173,0x09, 0x1D8,0x03, gr),
|
| 832 |
+
(0x488, 0x1EF,0x26, 0x1E5,0x07, 0x1F9,0x16, gr),
|
| 833 |
+
(0x480, 0x2D, 0x08, 0x2D, 0x07, 0x2E, 0x07, gr),
|
| 834 |
];
|
| 835 |
|
| 836 |
for &(offset, ecx, edx, p2, p3, p4, p5, p6) in ®ions {
|
crates/openwa-wormkit/src/replacements/game_session.rs
CHANGED
|
@@ -322,6 +322,51 @@ unsafe extern "stdcall" fn hook_pc_landscape_ctor(
|
|
| 322 |
orig(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
|
| 323 |
}
|
| 324 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 325 |
pub fn install() -> Result<(), String> {
|
| 326 |
unsafe {
|
| 327 |
INIT_REPLAY_ADDR = rb(va::DDGAMEWRAPPER_INIT_REPLAY);
|
|
@@ -338,6 +383,14 @@ pub fn install() -> Result<(), String> {
|
|
| 338 |
hook_pc_landscape_ctor as *const (),
|
| 339 |
)?;
|
| 340 |
PC_LANDSCAPE_TRAMPOLINE = tramp as *const ();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 341 |
}
|
| 342 |
Ok(())
|
| 343 |
}
|
|
|
|
| 322 |
orig(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
|
| 323 |
}
|
| 324 |
|
| 325 |
+
// ββ SpriteRegion__Constructor param logger ββββββββββββββββββββββββββ
|
| 326 |
+
static mut SPRITE_REGION_TRAMPOLINE: *const () = core::ptr::null();
|
| 327 |
+
|
| 328 |
+
/// Log fastcall params. Called from naked trampoline with all params on stack.
|
| 329 |
+
unsafe extern "cdecl" fn log_sprite_region(
|
| 330 |
+
ecx: u32, edx: u32, p1: u32, p2: u32, p3: u32, p4: u32, p5: u32, p6: u32,
|
| 331 |
+
) {
|
| 332 |
+
let _ = log_line(&format!(
|
| 333 |
+
"[SpriteRgn] ECX=0x{:X} EDX=0x{:X} p1=0x{:X} p2=0x{:X} p3=0x{:X} p4=0x{:X} p5=0x{:X} p6=0x{:X}",
|
| 334 |
+
ecx, edx, p1, p2, p3, p4, p5, p6));
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
/// Naked trampoline: captures ECX/EDX, logs, then calls original fastcall.
|
| 338 |
+
#[unsafe(naked)]
|
| 339 |
+
unsafe extern "C" fn hook_sprite_region_ctor() {
|
| 340 |
+
core::arch::naked_asm!(
|
| 341 |
+
// Save all regs
|
| 342 |
+
"pushl %eax",
|
| 343 |
+
"pushl %ecx",
|
| 344 |
+
"pushl %edx",
|
| 345 |
+
// Push all 8 params for logger: ECX, EDX, then 6 stack params
|
| 346 |
+
// Stack after 3 pushes: [edx][ecx][eax][ret][p1][p2][p3][p4][p5][p6]
|
| 347 |
+
// p1 at ESP+16, p2 at ESP+20, ...
|
| 348 |
+
"pushl 36(%esp)", // p6
|
| 349 |
+
"pushl 36(%esp)", // p5
|
| 350 |
+
"pushl 36(%esp)", // p4
|
| 351 |
+
"pushl 36(%esp)", // p3
|
| 352 |
+
"pushl 36(%esp)", // p2
|
| 353 |
+
"pushl 36(%esp)", // p1
|
| 354 |
+
"pushl %edx", // EDX
|
| 355 |
+
"pushl %ecx", // ECX
|
| 356 |
+
"calll {logger}",
|
| 357 |
+
"addl $32, %esp", // clean 8 cdecl params
|
| 358 |
+
// Restore regs
|
| 359 |
+
"popl %edx",
|
| 360 |
+
"popl %ecx",
|
| 361 |
+
"popl %eax",
|
| 362 |
+
// Jump to original (fastcall, same params on stack)
|
| 363 |
+
"jmpl *({tramp})",
|
| 364 |
+
logger = sym log_sprite_region,
|
| 365 |
+
tramp = sym SPRITE_REGION_TRAMPOLINE,
|
| 366 |
+
options(att_syntax),
|
| 367 |
+
);
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
pub fn install() -> Result<(), String> {
|
| 371 |
unsafe {
|
| 372 |
INIT_REPLAY_ADDR = rb(va::DDGAMEWRAPPER_INIT_REPLAY);
|
|
|
|
| 383 |
hook_pc_landscape_ctor as *const (),
|
| 384 |
)?;
|
| 385 |
PC_LANDSCAPE_TRAMPOLINE = tramp as *const ();
|
| 386 |
+
|
| 387 |
+
// Hook SpriteRegion__Constructor to log fastcall params
|
| 388 |
+
let tramp2 = hook::install(
|
| 389 |
+
"SpriteRegion__Constructor",
|
| 390 |
+
va::SPRITE_REGION_CONSTRUCTOR,
|
| 391 |
+
hook_sprite_region_ctor as *const (),
|
| 392 |
+
)?;
|
| 393 |
+
SPRITE_REGION_TRAMPOLINE = tramp2 as *const ();
|
| 394 |
}
|
| 395 |
Ok(())
|
| 396 |
}
|