paavohtl Claude Opus 4.6 (1M context) commited on
Commit
487fa54
Β·
1 Parent(s): c2c06b0

feat: port DSSound_LoadEffectWAVs to Rust, rename DDGame__LoadFonts

Browse files

Port DSSound_LoadEffectWAVs (0x5714B0) to pure Rust β€” iterates the SFX
name table at 0x6AF378, builds "data\wav\Effects\{name}.wav" paths, and
calls the already-ported DSSound::load_wav for each entry. Removes the
last WA bridge call from the audio init path in ddgame_constructor.

Rename DDGAME_INIT_SOUND_PATHS to DDGAME_LOAD_FONTS β€” the function at
0x570F30 loads .fnt font resources, not sound paths.

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

crates/openwa-core/src/address.rs CHANGED
@@ -97,8 +97,8 @@ pub mod va {
97
  fn/Usercall DDGAME_INIT_RENDER_INDICES = 0x0052_6080;
98
  /// DDGame__InitVersionFlags β€” stdcall(ddgame_wrapper)
99
  fn/Stdcall DDGAME_INIT_VERSION_FLAGS = 0x0052_5BE0;
100
- /// DDGame__InitSoundPaths_Maybe
101
- fn DDGAME_INIT_SOUND_PATHS = 0x0057_0F30;
102
  /// DDGame__LoadHudAndWeaponSprites
103
  fn/Thiscall DDGAME_LOAD_HUD_AND_WEAPON_SPRITES = 0x0053_D0E0;
104
  /// DDGame__InitPaletteGradientSprites
 
97
  fn/Usercall DDGAME_INIT_RENDER_INDICES = 0x0052_6080;
98
  /// DDGame__InitVersionFlags β€” stdcall(ddgame_wrapper)
99
  fn/Stdcall DDGAME_INIT_VERSION_FLAGS = 0x0052_5BE0;
100
+ /// DDGame__LoadFonts β€” loads .fnt font resources into the display.
101
+ fn DDGAME_LOAD_FONTS = 0x0057_0F30;
102
  /// DDGame__LoadHudAndWeaponSprites
103
  fn/Thiscall DDGAME_LOAD_HUD_AND_WEAPON_SPRITES = 0x0053_D0E0;
104
  /// DDGame__InitPaletteGradientSprites
crates/openwa-core/src/engine/ddgame_constructor.rs CHANGED
@@ -153,7 +153,7 @@ pub fn init_constructor_addrs() {
153
  unsafe {
154
  SPRITE_REGION_CTOR_ADDR = rb(va::SPRITE_REGION_CONSTRUCTOR);
155
  FUN_570A90_ADDR = rb(va::FUN_570A90);
156
- FUN_570F30_ADDR = rb(va::DDGAME_INIT_SOUND_PATHS);
157
  LOAD_SPEECH_BANKS_ADDR = rb(va::DSSOUND_LOAD_ALL_SPEECH_BANKS);
158
  LOADING_PROGRESS_TICK_ADDR = rb(va::DDGAME_WRAPPER_LOADING_PROGRESS_TICK);
159
  GFX_LOAD_SPRITES_ADDR = rb(va::GFX_DIR_LOAD_SPRITES);
@@ -203,12 +203,48 @@ unsafe extern "C" fn wa_load_sprites(
203
 
204
  static mut GFX_LOAD_SPRITES_ADDR: u32 = 0;
205
 
206
- /// DSSound_LoadEffectWAVs (0x571660): load sound effect WAVs.
207
- #[cfg(target_arch = "x86")]
208
- unsafe fn wa_load_effect_wavs(wrapper: *mut DDGameWrapper) {
209
- let f: unsafe extern "stdcall" fn(*mut DDGameWrapper) =
210
- core::mem::transmute(rb(va::DSSOUND_LOAD_EFFECT_WAVS) as usize);
211
- f(wrapper);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  }
213
 
214
  /// PCLandscape__Constructor (0x57ACB0): construct landscape object (0xB44 bytes, 11 params).
@@ -591,10 +627,10 @@ unsafe fn init_graphics_and_resources(
591
 
592
  // ── Audio init (non-headless + sound available) ──
593
  if !is_headless {
594
- // FUN_570F30: usercall(ESI=wrapper)
595
  call_usercall_esi(wrapper, FUN_570F30_ADDR);
596
  if !(*ddgame).sound.is_null() {
597
- wa_load_effect_wavs(wrapper);
598
  // DSSound_LoadAllSpeechBanks: the original is hooked to our Rust
599
  // replacement (speech.rs), so the usercall bridge calls our code.
600
  call_usercall_esi(wrapper, LOAD_SPEECH_BANKS_ADDR);
 
153
  unsafe {
154
  SPRITE_REGION_CTOR_ADDR = rb(va::SPRITE_REGION_CONSTRUCTOR);
155
  FUN_570A90_ADDR = rb(va::FUN_570A90);
156
+ FUN_570F30_ADDR = rb(va::DDGAME_LOAD_FONTS);
157
  LOAD_SPEECH_BANKS_ADDR = rb(va::DSSOUND_LOAD_ALL_SPEECH_BANKS);
158
  LOADING_PROGRESS_TICK_ADDR = rb(va::DDGAME_WRAPPER_LOADING_PROGRESS_TICK);
159
  GFX_LOAD_SPRITES_ADDR = rb(va::GFX_DIR_LOAD_SPRITES);
 
203
 
204
  static mut GFX_LOAD_SPRITES_ADDR: u32 = 0;
205
 
206
+ /// Port of DSSound_LoadEffectWAVs (0x5714B0).
207
+ ///
208
+ /// Iterates the sound effect name table at 0x6AF378 (pairs of [slot_id, name_ptr],
209
+ /// null-terminated). For each entry, builds "data\wav\Effects\{name}.wav" and calls
210
+ /// DSSound::load_wav (vtable slot 12, already Rust).
211
+ unsafe fn load_effect_wavs(wrapper: *mut DDGameWrapper) {
212
+ use std::ffi::CStr;
213
+
214
+ /// Sound effect name table entry: (slot_id, name_ptr).
215
+ #[repr(C)]
216
+ struct SfxEntry {
217
+ slot_id: i32,
218
+ name_ptr: *const std::ffi::c_char,
219
+ }
220
+
221
+ let table = rb(0x006A_F378) as *const SfxEntry;
222
+ let sound = (*wrapper).sound;
223
+ if sound.is_null() {
224
+ return;
225
+ }
226
+ let sound_vt = &*(*sound).vtable;
227
+
228
+ let mut i = 0;
229
+ loop {
230
+ let entry = &*table.add(i);
231
+ if entry.name_ptr.is_null() {
232
+ break;
233
+ }
234
+ if entry.slot_id == 0 {
235
+ break;
236
+ }
237
+
238
+ let name = CStr::from_ptr(entry.name_ptr).to_str().unwrap_or("");
239
+ let path = format!("data\\wav\\Effects\\{}.wav\0", name);
240
+
241
+ (sound_vt.load_wav)(sound, entry.slot_id, path.as_ptr());
242
+
243
+ // Update loading progress bar
244
+ call_usercall_ecx(wrapper, LOADING_PROGRESS_TICK_ADDR);
245
+
246
+ i += 1;
247
+ }
248
  }
249
 
250
  /// PCLandscape__Constructor (0x57ACB0): construct landscape object (0xB44 bytes, 11 params).
 
627
 
628
  // ── Audio init (non-headless + sound available) ──
629
  if !is_headless {
630
+ // FUN_570F30: font loading (usercall ESI=wrapper) β€” NOT audio related
631
  call_usercall_esi(wrapper, FUN_570F30_ADDR);
632
  if !(*ddgame).sound.is_null() {
633
+ load_effect_wavs(wrapper);
634
  // DSSound_LoadAllSpeechBanks: the original is hooked to our Rust
635
  // replacement (speech.rs), so the usercall bridge calls our code.
636
  call_usercall_esi(wrapper, LOAD_SPEECH_BANKS_ADDR);