re: the poke control PASSES -- writes reach the guest, hull is authoritative
Hammering settles what a single write could not: hull 0x44BB8000 (1500.0f), 944,387 writes of 1 over 15s, and afterwards the value HELD at 1 -- the game stopped rewriting it. The screen left 'flight', the HUD is gone, the ship is burning, and Natalie radios 'I've lost contact with Rhino 3!', the player's own callsign. The game read the poked value and killed the player. Established: writes to /dev/shm reach the running guest; hull at pos+0x154 is authoritative, not a readout; and a single write loses a race against the game's own continuous writes. This upgrades two earlier results from inconclusive to genuine negatives. The unit-record pokes were downgraded because I could not tell 'ignored' from 'never arrived'. The write arrives -- and those pokes persisted untouched for 60s, so the game genuinely saw state=4 and handle=0 on all three objective squadrons and did nothing. That is real evidence the phase-1 condition coroutine is not polling and its checks run only when a trigger starts them. Withdrawn: last iteration's claim that the pilot's hull= is a different field or scale. I read 1000.0f at pos+0x154 and inferred a mismatch with the logged 1500; this run reads 1500.0f at the same offset. Same field, different value per run.
This commit is contained in:
BIN
docs/re/captures/poke-control-kill.png
Normal file
BIN
docs/re/captures/poke-control-kill.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 634 KiB |
@@ -363,3 +363,47 @@ 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.
|
||||
|
||||
## ✅ THE CONTROL PASSES — pokes reach the guest, and hull is authoritative
|
||||
|
||||
Hammering the write instead of doing it once settles it:
|
||||
|
||||
```
|
||||
hull before: 0x44BB8000 (= 1500.0f)
|
||||
hammered hull=1 for 15 s -- 944,387 writes
|
||||
hull after : 0x00000001 (the game STOPPED rewriting it)
|
||||
screen: flight -> other
|
||||
```
|
||||
|
||||
The after-frame (`captures/poke-control-kill.png`) shows the **flight HUD gone**,
|
||||
the ship trailing fire, and a radio line: **"I've lost contact with Rhino 3!"** —
|
||||
Rhino 3 being the player's own callsign. **The game read the poked value and
|
||||
killed the player.**
|
||||
|
||||
So, established:
|
||||
|
||||
* **Writes to `/dev/shm/xenia_memory_*` do reach the running guest.** The
|
||||
plumbing works.
|
||||
* **Hull at `player position + 0x154` is authoritative**, not a readout.
|
||||
* **A single write loses a race** — the game rewrites hull continuously, so one
|
||||
poke lands between two of its own writes. Hammering wins; 15 s was ample.
|
||||
|
||||
### ✅ This upgrades two earlier "inconclusive" results to genuine negatives
|
||||
|
||||
The poke experiments on the unit records were downgraded to inconclusive because
|
||||
I could not tell "the game ignored it" from "the write never arrived". **The
|
||||
write arrives.** And those pokes *persisted untouched for 60 s* — nothing
|
||||
overwrote them — so the game genuinely saw `state = 4` and `handle = 0` on all
|
||||
three objective squadrons and **did nothing**.
|
||||
|
||||
That is now real evidence for the standing explanation: the phase-1 condition
|
||||
coroutine **is not polling** during ordinary flight, and the polls at `0xF524`
|
||||
run only when a trigger starts them.
|
||||
|
||||
### 🔴 Withdrawn: "the pilot's `hull=` is a different field"
|
||||
|
||||
Last iteration I read `0x447A0000` (1000.0f) at `pos + 0x154` and concluded it
|
||||
could not be the `1500` the pilot logs. **Wrong.** This run reads
|
||||
`0x44BB8000` = **1500.0f** at the same offset. It is the same field; the value
|
||||
simply differs between runs (craft or loadout). The "different field or scale"
|
||||
note is retracted.
|
||||
|
||||
@@ -10,13 +10,24 @@
|
||||
# it lives at `player position + 0x154`, and dropping it to 1 should destroy the
|
||||
# player -- an unambiguous screen change, no OCR needed.
|
||||
#
|
||||
# A SINGLE write is not enough: measured 2026-08-25, the game rewrote hull from
|
||||
# 1 back to 1000.0f within 12 s, so one poke lands between two of the game's own
|
||||
# writes and is gone before anything samples it. This HAMMERS the value in a
|
||||
# tight loop for HAMMER_S seconds so it is low whenever the game looks.
|
||||
#
|
||||
# ship dies / GAME OVER -> the guest reads our writes, and hull is
|
||||
# authoritative. The poke method is validated.
|
||||
# nothing happens -> hull is a readout and the real copy is elsewhere;
|
||||
# the method is still unproven, but that is a fact
|
||||
# about the field rather than about the plumbing.
|
||||
#
|
||||
# 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)"
|
||||
SD="$(cd "$(dirname "$0")" && pwd)"; export SD
|
||||
ATTEMPTS="${1:-3}"
|
||||
|
||||
alive_and_moving(){ python3 -c "
|
||||
@@ -47,8 +58,21 @@ for a in $(seq 1 "$ATTEMPTS"); do
|
||||
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
|
||||
HAMMER_S="${HAMMER_S:-15}"
|
||||
echo " hammering hull=1 for ${HAMMER_S}s..."
|
||||
python3 - "$hull" "$HAMMER_S" <<'PY'
|
||||
import os, struct, sys, time
|
||||
sys.path.insert(0, os.environ.get('SD', '.'))
|
||||
import gmem
|
||||
va = int(sys.argv[1]); secs = float(sys.argv[2])
|
||||
off = gmem.va_to_off(va)
|
||||
n = 0
|
||||
with open(gmem.mem_path(), 'r+b', buffering=0) as f:
|
||||
t0 = time.time()
|
||||
while time.time() - t0 < secs:
|
||||
f.seek(off); f.write(struct.pack('>I', 1)); n += 1
|
||||
print(' wrote hull=1 %d times' % n)
|
||||
PY
|
||||
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)"
|
||||
|
||||
Reference in New Issue
Block a user