From 65ee3c535588bbfaeff21312801b5b3451621ebd Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sat, 22 Aug 2026 20:23:06 +0200 Subject: [PATCH] fix(reverse): trace active injected ball states The tracer could only rediscover the game object while all original position copies agreed, which is normally true at the waiting launcher but not during an active controlled probe. Accept the injector-reported object base explicitly so one process can be sampled through an entire sequence of collision tests. Test Plan: - `ruff check original/tools/trace_original_state.py original/tools/inject_original_state.py` -- passed - active live trace with `--object-base 0xadc2b0` -- passed - `git diff --cached --check` -- passed --- original/MECHANICS_PROGRESS.md | 3 ++- original/tools/trace_original_state.py | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/original/MECHANICS_PROGRESS.md b/original/MECHANICS_PROGRESS.md index cef6d1a..c794701 100644 --- a/original/MECHANICS_PROGRESS.md +++ b/original/MECHANICS_PROGRESS.md @@ -104,7 +104,8 @@ original/tools/inject_original_state.py --x 289 --y 94 --vx 0 --vy 0 The executable image remains unchanged; only the current disposable Wine process is modified. Run the injector while the ball is waiting in the launcher so it can identify the live game object, or supply the previously reported -`--object-base` during a sequence of probes. +`--object-base` to both the injector and tracer during a sequence of active +probes. A probe at `(289,94)` captured the original terminal-18 path. The collision suspended the ball while frames advanced from 10 through 18 at the configured diff --git a/original/tools/trace_original_state.py b/original/tools/trace_original_state.py index 6fc8996..d45e8ec 100755 --- a/original/tools/trace_original_state.py +++ b/original/tools/trace_original_state.py @@ -261,6 +261,11 @@ def sample_state(data: bytes, obj: bytes) -> tuple[int, ...]: def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--pid", type=int, help="Linux PID of the TDKPIN winevdm.exe process") + parser.add_argument( + "--object-base", + type=lambda value: int(value, 0), + help="known live object base; otherwise locate it from the waiting ball", + ) parser.add_argument("--duration", type=float, default=10.0, help="capture duration in seconds") parser.add_argument("--interval-ms", type=float, default=1.0, help="sampling interval in milliseconds") parser.add_argument("--output", type=Path, help="CSV path; stdout when omitted") @@ -281,7 +286,11 @@ def main() -> None: with ProcessMemory(pid) as memory: data_base = locate_data_segment(memory) initial_data = memory.read(data_base, DATA_READ_SIZE) - object_base = locate_game_object(memory, initial_data) + object_base = ( + args.object_base + if args.object_base is not None + else locate_game_object(memory, initial_data) + ) print( f"TDKPIN pid={pid} data={data_base:#x} object={object_base:#x}", file=sys.stderr,