paavohtl Claude Sonnet 4.6 commited on
Commit
d467819
·
1 Parent(s): f2e565c

feat: add CTaskFire and CTaskTurnGame structs with runtime validation

Browse files

- CTaskFire (0xD8 bytes, class_type=0x18): spawn coords, timer, burn_rate,
spread_counter, lifetime, slot_index fields
- CTaskTurnGame (0x2E0 bytes): 15 named fields covering timers (turn_timer
+0x18C, idle_timer +0x184, retreat_timer +0x178), team tracking
(current_team, current_worm, arena_team, arena_worm), and frame counters
(active_worm_frames, retreat_frames, _timer_scale); all offsets runtime-
validated via offset_of! checks (15 PASS)
- dump_turngame(): finds TurnGame via vtable scan + SharedDataTable, dumps
known fields and full 0x2E0-byte raw region via dump_region
- dump_region refactored from DDGame-specific to generic *const u8 base
- replay-test.ps1: fix launcher invocation (pass $waExe explicitly so
replay file is forwarded as a WA.exe arg, not misinterpreted as exe path)
- Debug UI inspector sections for CTaskFire and CTaskTurnGame

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

crates/openwa-core/src/task.rs CHANGED
@@ -611,6 +611,107 @@ pub struct CTaskFire {
611
 
612
  const _: () = assert!(core::mem::size_of::<CTaskFire>() == 0xD8);
613
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
614
  // ============================================================
615
  // Derived task overlays — for accessing task-specific fields
616
  // beyond or within CGameTask that differ per task type.
 
611
 
612
  const _: () = assert!(core::mem::size_of::<CTaskFire>() == 0xD8);
613
 
614
+ /// Root turn-controller task — one instance per game, parent of the entire entity tree.
615
+ ///
616
+ /// Every worm, team, projectile, and environment task is a child (direct or indirect)
617
+ /// of this node. `CTaskTurnGame` drives the turn loop: it processes 50 game frames
618
+ /// per second via `CTaskTurnGame__TurnManager_ProcessFrame` (0x55FDA0), which is
619
+ /// called from HandleMessage case 2 (FrameFinish).
620
+ ///
621
+ /// Inheritance: CTask → CTaskTeam → CTaskTurnGame. Class type 6.
622
+ /// Constructor: `CTaskTurnGame__Constructor` (0x55B2B1).
623
+ /// vtable: `CTaskTurnGame__vtable` (0x00669F70), 20 slots.
624
+ /// Total size: 0x2E0 bytes.
625
+ ///
626
+ /// Key vtable slots:
627
+ /// [0] 0x55B5E0 — task-tree state snapshot serialiser
628
+ /// [1] 0x55B540 — destructor / Free
629
+ /// [2] 0x55DC00 — HandleMessage (30+ message types)
630
+ /// [3] 0x5612E0 — HUD data query (responds to msg 0x7D3)
631
+ ///
632
+ /// All timers decrement by 20 ms per frame (= 1000 ms / 50 fps).
633
+ #[repr(C)]
634
+ pub struct CTaskTurnGame {
635
+ /// 0x00-0x2F: CTask base (vtable, parent, children, shared_data, ddgame, …)
636
+ pub base: CTask,
637
+ /// 0x30-0xDB: CTaskTeam base region (opaque — includes secondary interface pointer
638
+ /// at +0x30, team position/physics fields, and per-team bookkeeping).
639
+ pub _ctaskteam: [u8; 0xAC],
640
+
641
+ // ---- CTaskTurnGame-specific fields (0xDC onwards) ----
642
+
643
+ pub _unknown_dc: u32,
644
+ pub _unknown_e0: u32,
645
+ /// 0xE4: turn-seed: ~(DDGame+0x45EC % 9000), used for random initialisation.
646
+ pub _turn_seed: u32,
647
+ /// 0xE8: number of teams in this game (copy of DDGame+0x44C).
648
+ pub num_teams: u32,
649
+ pub _unknown_ec: [u8; 0x1C],
650
+ /// 0x108: "worm active" flag — non-zero while the current worm is shooting or
651
+ /// moving. While non-zero, `turn_timer` is paused.
652
+ /// A copy is also written to DDGame+0x7234 at construction.
653
+ pub worm_active: u32,
654
+ pub _unknown_10c: [u8; 0x20],
655
+ /// 0x12C: active team index, **1-based** (0 = no active team).
656
+ /// Used to index per-team sound tables in DDGame (stride 0xF0 at DDGame+0x774C).
657
+ pub current_team: u32,
658
+ /// 0x130: active worm index within the current team, **0-based** (stride 0x9C).
659
+ pub current_worm: u32,
660
+ /// 0x134: arena team index used for TeamArenaState lookups.
661
+ pub arena_team: u32,
662
+ /// 0x138: arena worm index used for TeamArenaState lookups.
663
+ pub arena_worm: u32,
664
+ pub _unknown_13c: u32,
665
+ /// 0x140: set to 1 at construction; role unclear.
666
+ pub _init_140: u32,
667
+ pub _unknown_144: u32,
668
+ pub _unknown_148: u32,
669
+ /// 0x14C: set to 1 at construction and reset by turn-flow restart; role unclear.
670
+ pub _init_14c: u32,
671
+ /// 0x150: set to 1 when the active worm's firing phase ends and retreat begins.
672
+ pub turn_ended: u32,
673
+ /// 0x154: set to 1 when the scheme turn time is 0 (no time limit).
674
+ pub no_time_limit: u32,
675
+ pub _unknown_158: [u8; 0x14],
676
+ /// 0x16C: set to 1 once the "5 seconds left" warning sound has played.
677
+ pub warning_sound_played: u32,
678
+ pub _unknown_170: u32,
679
+ /// 0x174: set while a worm is transitioning out of a special state (e.g. landing
680
+ /// after a fly animation); cleared once settled.
681
+ pub _worm_state_transition: u32,
682
+ /// 0x178: retreat-phase countdown (ms). Initialised from `retreat_time_max` when
683
+ /// firing ends; decrements 20 ms/frame. Dispatches message 0x35 at zero.
684
+ pub retreat_timer: i32,
685
+ /// 0x17C: initial retreat duration (ms) loaded from the scheme at turn start.
686
+ pub retreat_time_max: i32,
687
+ /// 0x180: last tick when the displayed "seconds remaining" value was updated.
688
+ pub last_second_tick: u32,
689
+ /// 0x184: idle-phase timer (ms). Initialised to `scheme_turn_time × 1000`.
690
+ /// Decrements 20 ms/frame **only while `worm_active == 0`** (timer pauses when
691
+ /// the worm is moving/shooting). When it reaches zero, sudden-death is triggered.
692
+ /// This is NOT the per-turn HUD countdown — see `turn_timer` at +0x18C instead.
693
+ pub idle_timer: i32,
694
+ /// 0x188: smoothed display copy of `turn_timer`; tracks it at ≤ 0xCCC ms/frame
695
+ /// to avoid visual jumping on the HUD.
696
+ pub turn_timer_display: i32,
697
+ /// 0x18C: per-turn countdown timer (ms) — this is what the HUD shows.
698
+ /// Decrements 20 ms/frame every game frame. When it reaches zero,
699
+ /// `FUN_0055f4f0` fires (turn ends / retreat begins).
700
+ pub turn_timer: i32,
701
+ pub _unknown_190: [u8; 0x8],
702
+ /// 0x198: turn-timer visual pulse intensity (Fixed 16.16); grows as time runs low.
703
+ pub timer_flash: u32,
704
+ pub _unknown_19c: [u8; 0x138],
705
+ /// 0x2D4: frame count accumulated while this team held the active worm.
706
+ pub active_worm_frames: u32,
707
+ /// 0x2D8: frame count accumulated during the retreat phase.
708
+ pub retreat_frames: u32,
709
+ /// 0x2DC: timer scale factor derived from scheme (2, 3, or 4; default 4).
710
+ pub _timer_scale: u32,
711
+ }
712
+
713
+ const _: () = assert!(core::mem::size_of::<CTaskTurnGame>() == 0x2E0);
714
+
715
  // ============================================================
716
  // Derived task overlays — for accessing task-specific fields
717
  // beyond or within CGameTask that differ per task type.
crates/openwa-debugui/src/app.rs CHANGED
@@ -3,7 +3,7 @@ use openwa_core::address::va;
3
  use openwa_core::ddgame::DDGame;
4
  use openwa_core::ddgame_wrapper::DDGameWrapper;
5
  use openwa_core::rebase::rb;
6
- use openwa_core::task::{CTask, CTaskCloud, CTaskFire, CTaskMine, CTaskOilDrum, CTaskWorm};
7
 
8
  use crate::log;
9
 
@@ -460,6 +460,30 @@ impl DebugApp {
460
  });
461
  }
462
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
  // --- CTaskFire-specific fields ---
464
  if name == "CTaskFire" {
465
  let fire = addr as *const CTaskFire;
 
3
  use openwa_core::ddgame::DDGame;
4
  use openwa_core::ddgame_wrapper::DDGameWrapper;
5
  use openwa_core::rebase::rb;
6
+ use openwa_core::task::{CTask, CTaskCloud, CTaskFire, CTaskMine, CTaskOilDrum, CTaskTurnGame, CTaskWorm};
7
 
8
  use crate::log;
9
 
 
460
  });
461
  }
462
 
463
+ // --- CTaskTurnGame-specific fields ---
464
+ if name == "CTaskTurnGame" {
465
+ let tg = addr as *const CTaskTurnGame;
466
+ egui::CollapsingHeader::new("CTaskTurnGame")
467
+ .default_open(true)
468
+ .show(ui, |ui| {
469
+ egui::Grid::new("tg_grid").striped(true).show(ui, |ui| {
470
+ ui.label("current_team"); ui.label(format!("{}", (*tg).current_team)); ui.end_row();
471
+ ui.label("current_worm"); ui.label(format!("{}", (*tg).current_worm)); ui.end_row();
472
+ ui.label("arena_team"); ui.label(format!("{}", (*tg).arena_team)); ui.end_row();
473
+ ui.label("arena_worm"); ui.label(format!("{}", (*tg).arena_worm)); ui.end_row();
474
+ ui.label("worm_active"); ui.label(format!("{}", (*tg).worm_active != 0)); ui.end_row();
475
+ ui.label("turn_ended"); ui.label(format!("{}", (*tg).turn_ended != 0)); ui.end_row();
476
+ ui.label("no_time_lim"); ui.label(format!("{}", (*tg).no_time_limit != 0)); ui.end_row();
477
+ ui.label("turn_timer"); ui.label(format!("{:.1}s", (*tg).turn_timer as f32 / 1000.0)); ui.end_row();
478
+ ui.label("retreat"); ui.label(format!("{:.1}s", (*tg).retreat_timer as f32 / 1000.0)); ui.end_row();
479
+ ui.label("idle_timer"); ui.label(format!("{:.1}s", (*tg).idle_timer as f32 / 1000.0)); ui.end_row();
480
+ ui.label("num_teams"); ui.label(format!("{}", (*tg).num_teams)); ui.end_row();
481
+ ui.label("active_frm"); ui.label(format!("{}", (*tg).active_worm_frames)); ui.end_row();
482
+ ui.label("retreat_frm"); ui.label(format!("{}", (*tg).retreat_frames)); ui.end_row();
483
+ });
484
+ });
485
+ }
486
+
487
  // --- CTaskFire-specific fields ---
488
  if name == "CTaskFire" {
489
  let fire = addr as *const CTaskFire;
crates/openwa-wormkit/src/replacements/input.rs CHANGED
@@ -51,16 +51,28 @@ pub unsafe fn can_read(ptr: u32, size: u32) -> bool {
51
  ptr >= 0x10000 && IsBadReadPtr(ptr as *const u8, size) == 0
52
  }
53
 
54
- /// Dump a region of DDGame as DWORDs with classification.
55
  ///
56
- /// Classifies each non-zero DWORD as vtable (.rdata), code (.text), data,
57
- /// heap object (dereferences to check for vtable), small integer, or raw value.
58
- pub unsafe fn dump_region(ddgame: *mut DDGame, offset: usize, size: usize, label: &str) {
59
- let base_ptr = ddgame as *const u8;
 
 
 
 
 
 
 
 
 
 
 
 
60
  let wa_base = rb(va::IMAGE_BASE);
61
  let delta = wa_base.wrapping_sub(va::IMAGE_BASE);
62
 
63
- let _ = log_line(&format!("\n=== DDGame+0x{:04X}..0x{:04X}: {} ===", offset, offset + size, label));
64
 
65
  let dword_count = size / 4;
66
  for i in 0..dword_count {
 
51
  ptr >= 0x10000 && IsBadReadPtr(ptr as *const u8, size) == 0
52
  }
53
 
54
+ /// Dump a memory region as DWORDs with automatic classification.
55
  ///
56
+ /// Each non-zero DWORD is classified as:
57
+ /// - `[VTABLE]` — points into .rdata (likely a vtable or function pointer table);
58
+ /// also dereferences `vt[0]` if readable
59
+ /// - `[CODE]` — points into .text
60
+ /// - `[DATA]` — points into .data/.bss
61
+ /// - `[OBJECT]` — heap pointer whose first DWORD is a vtable; prints vtable address
62
+ /// - `[ptr]` — any other readable heap pointer; prints the dereferenced DWORD
63
+ /// - `[small=N]` — value < 0x10000 (integer / enum / flag)
64
+ /// - `[value]` — anything else
65
+ ///
66
+ /// # Parameters
67
+ /// - `base_ptr`: start of the object to dump (e.g. `turngame as *const u8`)
68
+ /// - `offset`: byte offset within `base_ptr` to start the dump
69
+ /// - `size`: number of bytes to dump (must be a multiple of 4)
70
+ /// - `struct_name`: used as the prefix in log lines (e.g. `"CTaskTurnGame"`)
71
+ pub unsafe fn dump_region(base_ptr: *const u8, offset: usize, size: usize, struct_name: &str) {
72
  let wa_base = rb(va::IMAGE_BASE);
73
  let delta = wa_base.wrapping_sub(va::IMAGE_BASE);
74
 
75
+ let _ = log_line(&format!("\n=== {}+0x{:04X}..0x{:04X} ===", struct_name, offset, offset + size));
76
 
77
  let dword_count = size / 4;
78
  for i in 0..dword_count {
crates/openwa-wormkit/src/replacements/mod.rs CHANGED
@@ -1,6 +1,6 @@
1
  mod config;
2
  mod frontend;
3
- mod input;
4
  mod scheme;
5
  mod render;
6
  mod sound;
 
1
  mod config;
2
  mod frontend;
3
+ pub(crate) mod input;
4
  mod scheme;
5
  mod render;
6
  mod sound;
crates/openwa-wormkit/src/validation/mod.rs CHANGED
@@ -11,7 +11,7 @@ use std::sync::atomic::{AtomicU32, Ordering};
11
 
12
  use openwa_core::rebase::rb;
13
  use openwa_core::address::va;
14
- use openwa_core::task::{CTask, CGameTask, SharedDataTable};
15
  use openwa_core::ddgame::DDGame;
16
  use openwa_core::ddgame_wrapper::DDGameWrapper;
17
 
@@ -296,6 +296,24 @@ fn validate_struct_offsets(result: &mut ValidationResult) {
296
  check_offset!(result, DDGameWrapper, _field_4c0, 0x4C0);
297
  check_offset!(result, DDGameWrapper, landscape, 0x4CC);
298
  check_offset!(result, DDGameWrapper, display, 0x4D0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
  }
300
 
301
  // ---------------------------------------------------------------------------
@@ -920,6 +938,83 @@ fn dump_worm_tasks() {
920
  }
921
  }
922
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
923
  // ---------------------------------------------------------------------------
924
  // Public entry point — called from wormkit's run()
925
  // ---------------------------------------------------------------------------
@@ -986,6 +1081,8 @@ pub fn run() -> Result<(), String> {
986
  dump_entity_census();
987
  let _ = log_validation(" Running worm entity dump (5s mark)...");
988
  dump_worm_tasks();
 
 
989
 
990
  // Wait briefly for replay to start, then dump game state
991
  // (fast-forward finishes the replay in ~10-15s total, so dump early)
 
11
 
12
  use openwa_core::rebase::rb;
13
  use openwa_core::address::va;
14
+ use openwa_core::task::{CTask, CGameTask, CTaskTurnGame, SharedDataTable};
15
  use openwa_core::ddgame::DDGame;
16
  use openwa_core::ddgame_wrapper::DDGameWrapper;
17
 
 
296
  check_offset!(result, DDGameWrapper, _field_4c0, 0x4C0);
297
  check_offset!(result, DDGameWrapper, landscape, 0x4CC);
298
  check_offset!(result, DDGameWrapper, display, 0x4D0);
299
+
300
+ let _ = log_validation("");
301
+ let _ = log_validation(" CTaskTurnGame:");
302
+ check_offset!(result, CTaskTurnGame, worm_active, 0x108);
303
+ check_offset!(result, CTaskTurnGame, current_team, 0x12C);
304
+ check_offset!(result, CTaskTurnGame, current_worm, 0x130);
305
+ check_offset!(result, CTaskTurnGame, arena_team, 0x134);
306
+ check_offset!(result, CTaskTurnGame, arena_worm, 0x138);
307
+ check_offset!(result, CTaskTurnGame, turn_ended, 0x150);
308
+ check_offset!(result, CTaskTurnGame, no_time_limit, 0x154);
309
+ check_offset!(result, CTaskTurnGame, retreat_timer, 0x178);
310
+ check_offset!(result, CTaskTurnGame, retreat_time_max, 0x17C);
311
+ check_offset!(result, CTaskTurnGame, idle_timer, 0x184);
312
+ check_offset!(result, CTaskTurnGame, turn_timer_display, 0x188);
313
+ check_offset!(result, CTaskTurnGame, turn_timer, 0x18C);
314
+ check_offset!(result, CTaskTurnGame, active_worm_frames, 0x2D4);
315
+ check_offset!(result, CTaskTurnGame, retreat_frames, 0x2D8);
316
+ check_offset!(result, CTaskTurnGame, _timer_scale, 0x2DC);
317
  }
318
 
319
  // ---------------------------------------------------------------------------
 
938
  }
939
  }
940
 
941
+ // ---------------------------------------------------------------------------
942
+ // CTaskTurnGame dump
943
+ // ---------------------------------------------------------------------------
944
+
945
+ fn dump_turngame() {
946
+ use openwa_core::task::CTaskTurnGame;
947
+ use crate::replacements::input::dump_region;
948
+
949
+ let _ = log_validation("");
950
+ let _ = log_validation("--- CTaskTurnGame Dump ---");
951
+
952
+ unsafe {
953
+ let session_ptr = read_u32(rb(va::G_GAME_SESSION));
954
+ if session_ptr == 0 { let _ = log_validation(" No game session — skipping."); return; }
955
+ let wrapper_addr = read_u32(session_ptr + 0xA0);
956
+ if wrapper_addr == 0 { let _ = log_validation(" No DDGameWrapper."); return; }
957
+ let ddgame_ptr = read_u32(wrapper_addr + 0x488);
958
+ if ddgame_ptr == 0 { let _ = log_validation(" No DDGame."); return; }
959
+
960
+ // Find CTaskTurnGame via the shared_data entity table.
961
+ let task_land_ptr = read_u32(ddgame_ptr + 0x54C);
962
+ if task_land_ptr == 0 { let _ = log_validation(" CTaskLand NULL — skipping."); return; }
963
+ let task_land = task_land_ptr as *const openwa_core::task::CTask;
964
+ let shared_data_ptr = (*task_land).shared_data;
965
+ if shared_data_ptr.is_null() { let _ = log_validation(" shared_data NULL."); return; }
966
+
967
+ let table = SharedDataTable::from_ptr(shared_data_ptr);
968
+ let expected_vt = rb(va::CTASK_TURN_GAME_VTABLE);
969
+ let mut tg_ptr: u32 = 0;
970
+ for node in table.iter() {
971
+ let entity = (*node).entity;
972
+ if entity.is_null() { continue; }
973
+ if !is_in_rdata(read_u32(entity as u32)) { continue; }
974
+ if read_u32(entity as u32) == expected_vt {
975
+ tg_ptr = entity as u32;
976
+ break;
977
+ }
978
+ }
979
+
980
+ if tg_ptr == 0 {
981
+ let _ = log_validation(" CTaskTurnGame not found in entity table.");
982
+ return;
983
+ }
984
+
985
+ let _ = log_validation(&format!(" CTaskTurnGame @ 0x{:08X}", tg_ptr));
986
+
987
+ // Print known named fields for cross-validation.
988
+ let tg = &*(tg_ptr as *const CTaskTurnGame);
989
+ let _ = log_validation(" Known fields:");
990
+ let _ = log_validation(&format!(" +0x108 worm_active = {}", tg.worm_active));
991
+ let _ = log_validation(&format!(" +0x12C current_team = {} (1-based, 0=none)", tg.current_team));
992
+ let _ = log_validation(&format!(" +0x130 current_worm = {} (0-based)", tg.current_worm));
993
+ let _ = log_validation(&format!(" +0x134 arena_team = {}", tg.arena_team));
994
+ let _ = log_validation(&format!(" +0x138 arena_worm = {}", tg.arena_worm));
995
+ let _ = log_validation(&format!(" +0x150 turn_ended = {}", tg.turn_ended));
996
+ let _ = log_validation(&format!(" +0x154 no_time_limit = {}", tg.no_time_limit));
997
+ let _ = log_validation(&format!(" +0x178 retreat_timer = {} ms", tg.retreat_timer));
998
+ let _ = log_validation(&format!(" +0x17C retreat_time_max = {} ms", tg.retreat_time_max));
999
+ let _ = log_validation(&format!(" +0x184 idle_timer = {} ms", tg.idle_timer));
1000
+ let _ = log_validation(&format!(" +0x188 turn_timer_display = {} ms", tg.turn_timer_display));
1001
+ let _ = log_validation(&format!(" +0x18C turn_timer = {} ms", tg.turn_timer));
1002
+ let _ = log_validation(&format!(" +0x2D4 active_worm_frames = {}", tg.active_worm_frames));
1003
+ let _ = log_validation(&format!(" +0x2D8 retreat_frames = {}", tg.retreat_frames));
1004
+ let _ = log_validation(&format!(" +0x2DC _timer_scale = {}", tg._timer_scale));
1005
+
1006
+ // Full memory dump — classify every DWORD to discover unknown fields.
1007
+ // Dump in chunks to keep log lines manageable.
1008
+ let base = tg_ptr as *const u8;
1009
+ dump_region(base, 0x00, 0x30, "CTaskTurnGame"); // CTask base
1010
+ dump_region(base, 0x30, 0xAC, "CTaskTurnGame"); // CTaskTeam region
1011
+ dump_region(base, 0xDC, 0x80, "CTaskTurnGame"); // 0xDC..0x15B
1012
+ dump_region(base, 0x15C, 0x80, "CTaskTurnGame"); // 0x15C..0x1DB
1013
+ dump_region(base, 0x1DC, 0x80, "CTaskTurnGame"); // 0x1DC..0x25B
1014
+ dump_region(base, 0x25C, 0x84, "CTaskTurnGame"); // 0x25C..0x2DF
1015
+ }
1016
+ }
1017
+
1018
  // ---------------------------------------------------------------------------
1019
  // Public entry point — called from wormkit's run()
1020
  // ---------------------------------------------------------------------------
 
1081
  dump_entity_census();
1082
  let _ = log_validation(" Running worm entity dump (5s mark)...");
1083
  dump_worm_tasks();
1084
+ let _ = log_validation(" Running TurnGame dump (5s mark)...");
1085
+ dump_turngame();
1086
 
1087
  // Wait briefly for replay to start, then dump game state
1088
  // (fast-forward finishes the replay in ~10-15s total, so dump early)
replay-test.ps1 CHANGED
@@ -51,7 +51,7 @@ $env:OPENWA_REPLAY_TEST = "1"
51
  $env:OPENWA_WA_PATH = $waExe
52
 
53
  # The launcher blocks until WA.exe exits, so run it as a background job for timeout support.
54
- $proc = Start-Process -FilePath $launcher -ArgumentList "--minimized `"$ReplayFile`"" -PassThru
55
  $timeout = 150 # seconds
56
  if (-not $proc.WaitForExit($timeout * 1000)) {
57
  Write-Host "WARNING: launcher did not exit within ${timeout}s, killing..." -ForegroundColor Red
 
51
  $env:OPENWA_WA_PATH = $waExe
52
 
53
  # The launcher blocks until WA.exe exits, so run it as a background job for timeout support.
54
+ $proc = Start-Process -FilePath $launcher -ArgumentList "--minimized `"$waExe`" `"$ReplayFile`"" -PassThru
55
  $timeout = 150 # seconds
56
  if (-not $proc.WaitForExit($timeout * 1000)) {
57
  Write-Host "WARNING: launcher did not exit within ${timeout}s, killing..." -ForegroundColor Red