# Record a whole run of the original from its memory as the reference for a port

## What to know

A port that must behave like the original needs a reference run of the original: the state
of every actor over a whole game, with the game's own results to check it against. When the
game runs under Wine on Linux (natively or in a VM), the simplest recorder reads the
process's memory from outside through `/proc/PID/mem` as root. The game is not changed or
slowed, and nothing is injected.

`memlog.py summary REC.jsonl` and `memlog.py csv` read a recording back. GameFrame's
`tools/live/memrec.py` is that recorder: `snap` copies the writable memory for
`memscan.py` diffs, and `record SPEC` writes named values as JSON Lines. What worked for POD,
whose recorder it came from:

- **Find the state first**, by tracing and by memory diffs: the eight race cars, the race
  records, the order table, the clock, the frame time. Static addresses stay the same in
  every run of a non-relocated EXE.
- **Keep raw words.** Store 16.16 values as integers in JSON Lines, one sample per line, so
  nothing is rounded.
- **Sample at a fixed rate** (10 Hz) and add the game's own counters: the clock, and the sum
  of frame times. They date each sample in game time.
- **Read the final state** a few seconds after the run ends: games often finish their
  bookkeeping after the main loop (POD drives unfinished cars to the line).
- **Check against the screen.** Take screenshots at events (each lap) and at the end. Print
  the recorded values the way the game prints them, and compare digit for digit. In POD all
  times on four results screens matched once the reader formatted like the game
  ([x87 time format](https://tanepiper.github.io/game-frame/knowhow/x87-truncating-time-format.md)).

Limits:
- A sample is not atomic: the values are read one after another while the game runs.
- At 10 Hz an outside reader sees about one frame in eight. Per-frame inputs (each frame's
  time, the keys) need a hook inside the game.
- A screenshot taken in the sampling loop stops sampling while it runs (0.7 s in POD).

Related: [mods spoil a reference recording](https://tanepiper.github.io/game-frame/knowhow/mods-loaded-in-a-reference-recording.md),
[wait for the next race](https://tanepiper.github.io/game-frame/knowhow/wait-for-the-next-race.md).
