paavohtl Claude Opus 4.6 (1M context) commited on
Commit
56e9d3b
·
1 Parent(s): 10ece8a

fix: detect match completion for Surrender-ending replays in headful tests

Browse files

Surrender 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 {}",