debug: fix PCLandscape param order, defer sound_available, add logging
Browse files- Swap params 4/5 in PCLandscape__Constructor call (game_info+0xDAAC
before wrapper, matching original push order)
- Defer sound_available=1 to end of constructor (prevents message pump
in DDGame__LoadWeaponSprites from triggering during construction)
- Add diagnostic logging for PCLandscape crash investigation
- Crash still occurs inside PCLandscape β likely remaining param
issues with stack-local output pointers (ESP+0x47 and ESP+0x64
from original's 4KB stack frame)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-core/src/engine/ddgame.rs
CHANGED
|
@@ -468,7 +468,12 @@ pub unsafe fn create_ddgame(
|
|
| 468 |
|
| 469 |
// ββ 6. Sound available + always-1 flags ββ
|
| 470 |
let is_headless = *(game_info as *const u8).add(0xF914).cast::<i32>() != 0;
|
| 471 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 472 |
(*ddgame)._field_7efc = 1;
|
| 473 |
|
| 474 |
// ββ 7. DDGameWrapper+0x48C init ββ
|
|
@@ -495,6 +500,10 @@ pub unsafe fn create_ddgame(
|
|
| 495 |
// ββ 10. GfxHandler, landscape, sprites, audio, resources ββ
|
| 496 |
init_graphics_and_resources(wrapper, game_info, net_game, display, is_headless);
|
| 497 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 498 |
let _ = crate::log::log_line("[DDGame] create_ddgame complete");
|
| 499 |
ddgame
|
| 500 |
}
|
|
@@ -697,7 +706,8 @@ unsafe fn init_graphics_and_resources(
|
|
| 697 |
let f: unsafe extern "stdcall" fn(*mut DDGameWrapper) =
|
| 698 |
core::mem::transmute(rb(va::DSSOUND_LOAD_EFFECT_WAVS) as usize);
|
| 699 |
f(wrapper);
|
| 700 |
-
// DSSound_LoadAllSpeechBanks:
|
|
|
|
| 701 |
call_usercall_esi(wrapper, LOAD_SPEECH_BANKS_ADDR);
|
| 702 |
let _ = crate::log::log_line("[DDGame] audio: done");
|
| 703 |
// Allocate ActiveSoundTable (0x608 bytes)
|
|
@@ -728,6 +738,7 @@ unsafe fn init_graphics_and_resources(
|
|
| 728 |
"[DDGame] GfxResource returned: 0x{:08X}", gfx_resource as u32));
|
| 729 |
}
|
| 730 |
|
|
|
|
| 731 |
// ββ PCLandscape (alloc 0xB44, stdcall 11 params) ββ
|
| 732 |
let landscape = {
|
| 733 |
let alloc = wa_malloc(0xB44);
|
|
@@ -739,9 +750,9 @@ unsafe fn init_graphics_and_resources(
|
|
| 739 |
|
| 740 |
let pc_ctor: unsafe extern "stdcall" fn(
|
| 741 |
*mut u8, *mut DDGame, *mut u8, // this, ddgame, gfx_resource
|
| 742 |
-
*
|
| 743 |
*mut u8, u32, // &landscape_byte, gfx_mode
|
| 744 |
-
*mut [i32; 2],
|
| 745 |
*mut u8, *mut u8, // &ddgame+0x777C, &ddgame+0x7780
|
| 746 |
) -> *mut u8 = core::mem::transmute(rb(va::PC_LANDSCAPE_CONSTRUCTOR) as usize);
|
| 747 |
|
|
@@ -750,15 +761,17 @@ unsafe fn init_graphics_and_resources(
|
|
| 750 |
alloc,
|
| 751 |
ddgame,
|
| 752 |
gfx_resource,
|
| 753 |
-
|
| 754 |
-
|
| 755 |
&mut landscape_byte as *mut u8,
|
| 756 |
(*wrapper).gfx_mode,
|
|
|
|
| 757 |
&mut landscape_coords as *mut [i32; 2],
|
| 758 |
-
landscape_coords.as_mut_ptr(), // placeholder for extra output
|
| 759 |
(ddgame as *mut u8).add(0x777C),
|
| 760 |
(ddgame as *mut u8).add(0x7780),
|
| 761 |
);
|
|
|
|
|
|
|
| 762 |
// Store landscape pointer
|
| 763 |
(*wrapper).landscape = result as *mut PCLandscape;
|
| 764 |
(*ddgame).landscape = result as *mut PCLandscape;
|
|
|
|
| 468 |
|
| 469 |
// ββ 6. Sound available + always-1 flags ββ
|
| 470 |
let is_headless = *(game_info as *const u8).add(0xF914).cast::<i32>() != 0;
|
| 471 |
+
// Defer sound_available β keep at 0 during construction.
|
| 472 |
+
// DDGame__LoadWeaponSprites checks this flag; when set, it calls
|
| 473 |
+
// FUN_572E30 which pumps PeekMessage/DispatchMessage. That can
|
| 474 |
+
// trigger game task code that reads uninitialized DDGame fields.
|
| 475 |
+
// Set to final value at the end of init_graphics_and_resources.
|
| 476 |
+
(*ddgame).sound_available = 0;
|
| 477 |
(*ddgame)._field_7efc = 1;
|
| 478 |
|
| 479 |
// ββ 7. DDGameWrapper+0x48C init ββ
|
|
|
|
| 500 |
// ββ 10. GfxHandler, landscape, sprites, audio, resources ββ
|
| 501 |
init_graphics_and_resources(wrapper, game_info, net_game, display, is_headless);
|
| 502 |
|
| 503 |
+
// Now set sound_available to its real value β construction is complete,
|
| 504 |
+
// so the message pump in DDGame__LoadWeaponSprites is safe.
|
| 505 |
+
(*ddgame).sound_available = if is_headless { 0 } else { 1 };
|
| 506 |
+
|
| 507 |
let _ = crate::log::log_line("[DDGame] create_ddgame complete");
|
| 508 |
ddgame
|
| 509 |
}
|
|
|
|
| 706 |
let f: unsafe extern "stdcall" fn(*mut DDGameWrapper) =
|
| 707 |
core::mem::transmute(rb(va::DSSOUND_LOAD_EFFECT_WAVS) as usize);
|
| 708 |
f(wrapper);
|
| 709 |
+
// DSSound_LoadAllSpeechBanks: the original is hooked to our Rust
|
| 710 |
+
// replacement (speech.rs), so the usercall bridge calls our code.
|
| 711 |
call_usercall_esi(wrapper, LOAD_SPEECH_BANKS_ADDR);
|
| 712 |
let _ = crate::log::log_line("[DDGame] audio: done");
|
| 713 |
// Allocate ActiveSoundTable (0x608 bytes)
|
|
|
|
| 738 |
"[DDGame] GfxResource returned: 0x{:08X}", gfx_resource as u32));
|
| 739 |
}
|
| 740 |
|
| 741 |
+
let _ = crate::log::log_line("[DDGame] calling PCLandscape ctor");
|
| 742 |
// ββ PCLandscape (alloc 0xB44, stdcall 11 params) ββ
|
| 743 |
let landscape = {
|
| 744 |
let alloc = wa_malloc(0xB44);
|
|
|
|
| 750 |
|
| 751 |
let pc_ctor: unsafe extern "stdcall" fn(
|
| 752 |
*mut u8, *mut DDGame, *mut u8, // this, ddgame, gfx_resource
|
| 753 |
+
*const u8, *mut DDGameWrapper, // game_info+0xDAAC, wrapper
|
| 754 |
*mut u8, u32, // &landscape_byte, gfx_mode
|
| 755 |
+
*mut u8, *mut [i32; 2], // stack local, coord output
|
| 756 |
*mut u8, *mut u8, // &ddgame+0x777C, &ddgame+0x7780
|
| 757 |
) -> *mut u8 = core::mem::transmute(rb(va::PC_LANDSCAPE_CONSTRUCTOR) as usize);
|
| 758 |
|
|
|
|
| 761 |
alloc,
|
| 762 |
ddgame,
|
| 763 |
gfx_resource,
|
| 764 |
+
gi.add(0xDAAC), // param 4
|
| 765 |
+
wrapper, // param 5
|
| 766 |
&mut landscape_byte as *mut u8,
|
| 767 |
(*wrapper).gfx_mode,
|
| 768 |
+
&mut landscape_byte as *mut u8, // param 8 (stack local)
|
| 769 |
&mut landscape_coords as *mut [i32; 2],
|
|
|
|
| 770 |
(ddgame as *mut u8).add(0x777C),
|
| 771 |
(ddgame as *mut u8).add(0x7780),
|
| 772 |
);
|
| 773 |
+
let _ = crate::log::log_line(&format!(
|
| 774 |
+
"[DDGame] PCLandscape returned: 0x{:08X}", result as u32));
|
| 775 |
// Store landscape pointer
|
| 776 |
(*wrapper).landscape = result as *mut PCLandscape;
|
| 777 |
(*ddgame).landscape = result as *mut PCLandscape;
|