fix: enable loading progress ticks, fix _field_4dc condition
Browse files- Enable DDGameWrapper__LoadingProgressTick calls (4 total) that were
disabled β these update wrapper+0x4D8/4DC/4E0 progress fields
- Fix _field_4dc condition: check net_game null (original checks
display null, but our headless display is non-null)
- Add DDGameWrapper shadow dump for comparison
Headful replay completes. Headless still has frame-0 checksum mismatch.
Wrapper fields 0x4D8/4DC/4E0 now closer to original.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-core/src/engine/ddgame.rs
CHANGED
|
@@ -1237,7 +1237,9 @@ unsafe fn init_graphics_and_resources(
|
|
| 1237 |
|
| 1238 |
// ββ DDGameWrapper field inits ββ
|
| 1239 |
(*wrapper)._field_4d8 = 0;
|
| 1240 |
-
|
|
|
|
|
|
|
| 1241 |
(*wrapper)._field_4dc = 0x2AD;
|
| 1242 |
} else {
|
| 1243 |
let byte_val = *net_game.add(0x44C) as u32;
|
|
@@ -1273,9 +1275,9 @@ unsafe fn init_graphics_and_resources(
|
|
| 1273 |
|
| 1274 |
let _ = crate::log::log_line("[DDGame] past ActiveSoundTable");
|
| 1275 |
|
| 1276 |
-
// ββ Loading
|
| 1277 |
-
|
| 1278 |
-
|
| 1279 |
|
| 1280 |
// ββ GfxResource: thiscall(ECX=gfx_handler) + EAX=name + 1 stack(output), RET 0x4 ββ
|
| 1281 |
// Test: call GfxResource with real params
|
|
@@ -1540,9 +1542,9 @@ unsafe fn init_graphics_and_resources(
|
|
| 1540 |
// TODO: populate coord_list from landscape data (complex loop)
|
| 1541 |
}
|
| 1542 |
|
| 1543 |
-
// ββ Loading
|
| 1544 |
-
|
| 1545 |
-
|
| 1546 |
|
| 1547 |
// ββ Sprite resource loading via DDGameWrapper vtable[0] ββ
|
| 1548 |
// DDNetGameWrapper__LoadResourceList: thiscall(ECX=wrapper) +
|
|
|
|
| 1237 |
|
| 1238 |
// ββ DDGameWrapper field inits ββ
|
| 1239 |
(*wrapper)._field_4d8 = 0;
|
| 1240 |
+
// Original checks `display == NULL`, but our headless display is non-null.
|
| 1241 |
+
// Use net_game null check as equivalent (net_game is null in headless/offline modes).
|
| 1242 |
+
if net_game.is_null() {
|
| 1243 |
(*wrapper)._field_4dc = 0x2AD;
|
| 1244 |
} else {
|
| 1245 |
let byte_val = *net_game.add(0x44C) as u32;
|
|
|
|
| 1275 |
|
| 1276 |
let _ = crate::log::log_line("[DDGame] past ActiveSoundTable");
|
| 1277 |
|
| 1278 |
+
// ββ Loading progress ticks (original calls DDGameWrapper__LoadingProgressTick twice here) ββ
|
| 1279 |
+
call_usercall_ecx(wrapper, LOADING_PROGRESS_TICK_ADDR);
|
| 1280 |
+
call_usercall_ecx(wrapper, LOADING_PROGRESS_TICK_ADDR);
|
| 1281 |
|
| 1282 |
// ββ GfxResource: thiscall(ECX=gfx_handler) + EAX=name + 1 stack(output), RET 0x4 ββ
|
| 1283 |
// Test: call GfxResource with real params
|
|
|
|
| 1542 |
// TODO: populate coord_list from landscape data (complex loop)
|
| 1543 |
}
|
| 1544 |
|
| 1545 |
+
// ββ Loading progress ticks (second pair, before sprite resource loading) ββ
|
| 1546 |
+
call_usercall_ecx(wrapper, LOADING_PROGRESS_TICK_ADDR);
|
| 1547 |
+
call_usercall_ecx(wrapper, LOADING_PROGRESS_TICK_ADDR);
|
| 1548 |
|
| 1549 |
// ββ Sprite resource loading via DDGameWrapper vtable[0] ββ
|
| 1550 |
// DDNetGameWrapper__LoadResourceList: thiscall(ECX=wrapper) +
|
crates/openwa-wormkit/src/replacements/game_session.rs
CHANGED
|
@@ -163,6 +163,29 @@ pub(crate) unsafe fn construct_ddgame_wrapper(
|
|
| 163 |
));
|
| 164 |
}
|
| 165 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
// Initialize DDGame's game-state fields.
|
| 167 |
let _ = log_line("[GameSession] calling InitGameState");
|
| 168 |
let init_state: unsafe extern "stdcall" fn(*mut DDGameWrapper) =
|
|
|
|
| 163 |
));
|
| 164 |
}
|
| 165 |
|
| 166 |
+
// Dump DDGameWrapper state
|
| 167 |
+
if std::env::var("OPENWA_VALIDATE").is_ok() {
|
| 168 |
+
let wrapper_dwords = this as *const u32;
|
| 169 |
+
// DDGameWrapper is ~0x6EF0 bytes (from DDGameWrapper__Constructor at 0x56DEF0)
|
| 170 |
+
let w_count = 0x6EF0 / 4;
|
| 171 |
+
let mut w_nonzero = 0u32;
|
| 172 |
+
let _ = log_line("[Shadow:Wrapper] === DDGameWrapper ===");
|
| 173 |
+
for i in 0..w_count {
|
| 174 |
+
let val = *wrapper_dwords.add(i);
|
| 175 |
+
if val != 0 {
|
| 176 |
+
w_nonzero += 1;
|
| 177 |
+
if w_nonzero <= 200 {
|
| 178 |
+
let _ = log_line(&format!(
|
| 179 |
+
"[Shadow:Wrapper] +0x{:04X} = 0x{:08X}", i * 4, val,
|
| 180 |
+
));
|
| 181 |
+
}
|
| 182 |
+
}
|
| 183 |
+
}
|
| 184 |
+
let _ = log_line(&format!(
|
| 185 |
+
"[Shadow:Wrapper] Total non-zero: {} / {}", w_nonzero, w_count,
|
| 186 |
+
));
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
// Initialize DDGame's game-state fields.
|
| 190 |
let _ = log_line("[GameSession] calling InitGameState");
|
| 191 |
let init_state: unsafe extern "stdcall" fn(*mut DDGameWrapper) =
|