re: the positive control ran, and is still inconclusive
poke_control.sh (self-retrying, succeeded on attempt 1 with no freeze) set the player's hull at pos+0x154 to 1. Twelve seconds later the game had put 0x447A0000 back. That establishes an asymmetry worth having: the hull word is continuously rewritten by the game, while the unit-record fields held our value untouched for 60s. It separates fields the game maintains from fields nobody writes. But it is not yet a control. The after-frame shows a red WARNING banner -- and the before-frame already shows MISSILE ALERT, so the ship was under attack in both and the banner is not attributable to the poke. A value being overwritten proves the game writes that address, not that it read ours. Correction: hull at pos+0x154 is 0x447A0000, a FLOAT 1000.0, not the 1500 the pilot logs -- those are different fields or scales and should not be conflated. The settling refinement: poke in a tight loop for several seconds so the value is low whenever the game samples it. If hull is authoritative the ship dies and the screen goes to GAME OVER; if it survives, the field is a readout. The reusable part is the harness: boot -> verify animating -> locate -> act, with a freeze at any step costing one retry rather than the iteration.
This commit is contained in:
@@ -322,3 +322,44 @@ rather than informative, and the two null results above must be read as
|
||||
|
||||
**What still stands** from these runs is only what was *observed*, not poked:
|
||||
the arrival transitions, the destruction of ADN111, and the mission-over branch.
|
||||
|
||||
## 🟡 The positive control ran — and is still inconclusive
|
||||
|
||||
`tools/re-capture/poke_control.sh` (self-retrying; **succeeded on attempt 1**, no
|
||||
freeze) poked the player's hull at `position + 0x154` to `1`, on the theory that
|
||||
the game visibly reacts to a dead player.
|
||||
|
||||
```
|
||||
hull before: 0x447A0000 (= 1000.0f)
|
||||
poke 0x447A0000 -> 0x00000001 OK
|
||||
hull after : 0x447A0000 (12 s later -- the game put it back)
|
||||
screen before: flight screen after: flight
|
||||
```
|
||||
|
||||
**What it establishes:** the hull word is **continuously rewritten by the game**,
|
||||
so a poke there cannot persist — unlike the unit-record fields, which held our
|
||||
value for 60 s untouched. That asymmetry is itself informative: it separates
|
||||
fields the game actively maintains from fields nobody is writing.
|
||||
|
||||
**Why it is still not a control.** I looked for a visible reaction and found a
|
||||
red `WARNING` banner in the after-frame — but the before-frame already shows
|
||||
`MISSILE ALERT`, i.e. the ship was under attack in both. **The banner is not
|
||||
attributable to the poke**, and I am not going to count it. A value being
|
||||
overwritten proves the game writes that address; it does not prove the game
|
||||
*read* ours.
|
||||
|
||||
**New fact, and a correction:** hull at `pos + 0x154` reads `0x447A0000` — a
|
||||
**float, 1000.0** — not the `1500` the pilot logs. The pilot's `hull=` is a
|
||||
different field or scale, and the two should not be conflated.
|
||||
|
||||
### The refinement that would settle it
|
||||
|
||||
Poke in a **tight loop** for several seconds so the value is low whenever the
|
||||
game samples it, rather than once between two of its own writes. If hull is
|
||||
authoritative, the ship dies and the screen goes to `GAME OVER` — unambiguous. If
|
||||
it survives a sustained low hull, the field is a readout and the authoritative
|
||||
copy is elsewhere. Either answer is worth having.
|
||||
|
||||
✅ **The self-retrying harness works** and is the reusable part of this
|
||||
iteration: boot → verify animating → locate → act, with a freeze at any step
|
||||
costing one retry instead of a whole iteration.
|
||||
|
||||
59
tools/re-capture/poke_control.sh
Executable file
59
tools/re-capture/poke_control.sh
Executable file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
# POSITIVE CONTROL for the poke method: does a write to /dev/shm reach the guest?
|
||||
#
|
||||
# Two poke experiments produced no observable effect, and without this control
|
||||
# "the game ignored it" cannot be told from "the write never arrived"
|
||||
# (script-runtime-probe.md). The stick test only proves the value persisted in
|
||||
# the shared-memory FILE.
|
||||
#
|
||||
# The control has to be something the GAME visibly reacts to. Hull is ideal:
|
||||
# it lives at `player position + 0x154`, and dropping it to 1 should destroy the
|
||||
# player -- an unambiguous screen change, no OCR needed.
|
||||
#
|
||||
# Self-retrying, because roughly two runs in three freeze and a freeze was
|
||||
# costing a whole iteration. Each attempt: boot, check the guest is animating,
|
||||
# locate the player, poke, look. A freeze at any step costs a retry.
|
||||
set -u
|
||||
export HOME=/sylph-home/re SDL_AUDIODRIVER=dummy DISPLAY=:98
|
||||
export PYTHONPATH=/sylph-home/.local/lib/python3.12/site-packages
|
||||
SD="$(cd "$(dirname "$0")" && pwd)"
|
||||
ATTEMPTS="${1:-3}"
|
||||
|
||||
alive_and_moving(){ python3 -c "
|
||||
import sys; sys.path.insert(0,'$SD')
|
||||
import frozen; d,_=frozen.frozen(5.0); sys.exit(1 if d else 0)"; }
|
||||
|
||||
for a in $(seq 1 "$ATTEMPTS"); do
|
||||
echo "=== attempt $a/$ATTEMPTS ($(date +%T))"
|
||||
pkill -9 -x xenia_canary 2>/dev/null; pkill -9 -f '[p]ilot.py' 2>/dev/null; sleep 2
|
||||
rm -f /tmp/xenia-canary.lock
|
||||
"$SD/launch_mission.sh" fly >/tmp/pc-boot.log 2>&1 || { echo " boot failed"; continue; }
|
||||
if ! alive_and_moving; then echo " guest already frozen after boot"; continue; fi
|
||||
|
||||
pos=""
|
||||
for t in 1 2 3; do
|
||||
python3 "$SD/pad.py" set "rt=1" >/dev/null 2>&1; sleep 4
|
||||
python3 "$SD/pad.py" clear >/dev/null 2>&1
|
||||
pos=$(timeout 120 python3 "$SD/entities2.py" self 0x130 2>/dev/null \
|
||||
| sed -n 's/.*pos va \(0x[0-9a-fA-F]*\).*/\1/p' | head -1)
|
||||
[ -n "$pos" ] && break
|
||||
echo " locate attempt $t: no player"
|
||||
done
|
||||
[ -n "$pos" ] || { echo " could not locate the player"; continue; }
|
||||
if ! alive_and_moving; then echo " froze during locate"; continue; fi
|
||||
|
||||
hull=$((pos + 0x154))
|
||||
echo " player pos $pos, hull $(printf '0x%X' $hull)"
|
||||
before=$(python3 "$SD/gpoke.py" r32 "$hull" 1 2>/dev/null | tail -1)
|
||||
echo " hull before: $before"
|
||||
screenshot /tmp/pc-before.png >/dev/null 2>&1
|
||||
python3 "$SD/gpoke.py" w32 "$hull" 1 2>&1 | tail -2
|
||||
sleep 12
|
||||
screenshot /tmp/pc-after.png >/dev/null 2>&1
|
||||
echo " hull after : $(python3 "$SD/gpoke.py" r32 "$hull" 1 2>/dev/null | tail -1)"
|
||||
echo " screen before: $(python3 "$SD/screen_id.py" /tmp/pc-before.png | head -1)"
|
||||
echo " screen after : $(python3 "$SD/screen_id.py" /tmp/pc-after.png | head -1)"
|
||||
python3 "$SD/frozen.py" --pair /tmp/pc-before.png /tmp/pc-after.png 2>&1 | tail -1
|
||||
echo "CONTROL RAN"; exit 0
|
||||
done
|
||||
echo "CONTROL DID NOT RUN in $ATTEMPTS attempts"; exit 1
|
||||
Reference in New Issue
Block a user