fix: detect match completion for Surrender-ending replays in headful tests
Browse filesSurrender doesn't zero TeamArena worm health — it sets worm state to
Dead (0x86) via a different mechanism. The per-frame alive-team poll
never saw alive<=1, and DDGame is already null at DLL_PROCESS_DETACH,
so the final check couldn't run either. Now treat DDGame-null-at-detach
(meaning DDGameWrapper::EndGame ran normally) as match completion when
the match had started.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-dll/src/replacements/replay_test.rs
CHANGED
|
@@ -116,9 +116,32 @@ unsafe fn check_milestones(ddgame: *const DDGame, frame: u32) {
|
|
| 116 |
pub fn write_gameplay_report() {
|
| 117 |
use crate::log_line;
|
| 118 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
let frames = super::frame_hook::frames_processed();
|
| 120 |
let started = MATCH_STARTED.load(Ordering::Relaxed);
|
| 121 |
-
let completed = MATCH_COMPLETED.load(Ordering::Relaxed);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
|
| 123 |
let _ = log_line("--- Gameplay Checks ---");
|
| 124 |
|
|
@@ -150,8 +173,10 @@ pub fn write_gameplay_report() {
|
|
| 150 |
let alive = ALIVE_AT_END.load(Ordering::Relaxed);
|
| 151 |
let outcome = if alive == 1 {
|
| 152 |
"winner decided"
|
| 153 |
-
} else {
|
| 154 |
"draw (all eliminated)"
|
|
|
|
|
|
|
| 155 |
};
|
| 156 |
let _ = log_line(&format!(
|
| 157 |
"[GAMEPLAY PASS] Match completed - {} at frame {}",
|
|
|
|
| 116 |
pub fn write_gameplay_report() {
|
| 117 |
use crate::log_line;
|
| 118 |
|
| 119 |
+
// Final milestone check if DDGame is still alive at detach time.
|
| 120 |
+
unsafe {
|
| 121 |
+
let ddgame = openwa_core::engine::game_session::get_ddgame();
|
| 122 |
+
if !ddgame.is_null() {
|
| 123 |
+
let frame = super::frame_hook::frames_processed();
|
| 124 |
+
check_milestones(ddgame, frame);
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
let frames = super::frame_hook::frames_processed();
|
| 129 |
let started = MATCH_STARTED.load(Ordering::Relaxed);
|
| 130 |
+
let mut completed = MATCH_COMPLETED.load(Ordering::Relaxed);
|
| 131 |
+
|
| 132 |
+
// If DDGame was already cleaned up (null at detach), that means
|
| 133 |
+
// DDGameWrapper::EndGame ran — the game session ended normally. If the
|
| 134 |
+
// match had started, this counts as completion. This handles cases like
|
| 135 |
+
// Surrender where TeamArena health values don't reflect the game-over
|
| 136 |
+
// state, so the per-frame alive-team check never triggers.
|
| 137 |
+
if started && !completed {
|
| 138 |
+
let ddgame_null = unsafe { game_session::get_ddgame().is_null() };
|
| 139 |
+
if ddgame_null && frames > 0 {
|
| 140 |
+
completed = true;
|
| 141 |
+
MATCH_COMPLETED.store(true, Ordering::Relaxed);
|
| 142 |
+
COMPLETION_FRAME.store(frames, Ordering::Relaxed);
|
| 143 |
+
}
|
| 144 |
+
}
|
| 145 |
|
| 146 |
let _ = log_line("--- Gameplay Checks ---");
|
| 147 |
|
|
|
|
| 173 |
let alive = ALIVE_AT_END.load(Ordering::Relaxed);
|
| 174 |
let outcome = if alive == 1 {
|
| 175 |
"winner decided"
|
| 176 |
+
} else if alive == 0 {
|
| 177 |
"draw (all eliminated)"
|
| 178 |
+
} else {
|
| 179 |
+
"game session ended normally"
|
| 180 |
};
|
| 181 |
let _ = log_line(&format!(
|
| 182 |
"[GAMEPLAY PASS] Match completed - {} at frame {}",
|