Skip to lesson
Game Hacking Academy
Preparing lesson text…
Exit reader mode
Voice and speed

Preparing read-aloud controls…

Lesson 4.3 Listening edition

Why Snapshots Need Guarded Actions

Learn why live reads go stale and how snapshots, separate observation, and verified writes protect a game-state tool.

About 26 minutes

The observer in the previous lesson copied player state for display. A tool that changes state faces a harder problem: gold can change after the read but before the write. If income arrives in that gap, a blind write may overwrite it. We need a pipeline that treats every observation as temporary evidence.

Section: One long function hides where it can fail.

A beginner tool often grows as one long function:

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

That can work once, but every step depends on facts collected earlier. The game may restart, change maps, end a turn, replace an object, or update the value while the tool is still running.

A more reliable tool separates six phases:

Capture twice, recheck, then write, and read back

The important idea is not extra code. It is that data crosses a gate before the tool acts on it. A raw address read once may already be out of date. A Snapshot captured twice with equal results was consistent at that moment. A write happens only if a fresh capture, taken immediately before it, still equals the snapshot.

Income changes gold before the write.

In brief: Treat every read as temporary evidence. Re-check it right before acting, and write only if nothing has changed.

Section: Store one snapshot in one typed value.

This lesson records the entire Wesnoth pointer path, not only the final gold number:

Labelled memory cells

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

Why keep all four fields?

player changing means the root now reaches another object.

side changing can mean the active faction or match state changed.

gold_address is the exact destination a later action would touch.

gold is the value the learner actually observed.

Equality now asks a useful question: “Did the whole chain and its value remain the same?” It is stronger than comparing only the final address.

Section: Two equal reads are useful, not magical.

The tool captures twice and accepts the result only when both snapshots agree:

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

This is a small optimistic consistency check. The tool does not stop the game. It assumes a short read will usually see a quiet moment, then checks that assumption.

⚠️ Two equal reads are not a mathematical proof that no intermediate state existed. They are a practical gate for a tiny offline lab. A debugger pause, a game-provided snapshot A P I, application programming interface,, or a version counter is stronger when a larger structure must be perfectly atomic.

Alternative: Think of looking both ways before crossing: if both looks agree, the road is probably quiet, but a car could still appear. Equal reads raise confidence, not certainty.

The retry cap matters too. A loop that waits forever for stability can make a broken tool look frozen.

Section: Capabilities follow the chosen action.

The command has two modes:

Terminal window

Code example. The code’s comments explain: Observation only: requests query + read access Explicit local-lab change: also requests operation + write access

The program decides whether it needs write rights before opening the process:

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

This is capability-oriented design in plain English: if the user asked only to look, the handle should be unable to write.

Section: Validate, write, verify, and recover.

The write path has three gates:

re-capture and require the same snapshot;

write exactly four little-endian bytes to the verified gold field;

read the field back and require the requested result.

Lesson diagram

In the code below, observed is the snapshot the caller approved. A fresh snapshot must match it before any write; afterward, a read-back must equal replacement. Each added line enforces one arrow in the diagram.

The original helper writes to the gold address in a previously captured snapshot, then reports success. The target may have changed since that snapshot; the function also never checks what was stored.

Before: write through a cached snapshot

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

A guarded action checks its precondition immediately before writing and its postcondition afterward. Matching snapshots reduce stale-address mistakes; they still cannot prevent the game changing between the check and the write.

Improved code

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

Show the diff

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

Takeaway: recheck the state you approved, then verify the result of the write.

This is not a database transaction: Windows cannot automatically roll back the game. It is a guarded action with a checked precondition and postcondition. That pattern also fits toggles, patches, save editors, configuration tools, and mod installers.

Narration: Without the final read-back, a tool could print success after a write that did not stick, for example if the game rewrote the value. Checking catches that.

Section: Complete buildable tool.

The code below is the complete binary used by the lesson.

Additional detail: Complete lab source: snapshot_pipeline.rs.

Code example. The code’s comments explain: 📏 Pointer width belongs to the 32-bit game, not to this tool. 🧭 Resolve every address with checked arithmetic before reading it. 🔒 Read-only mode never requests VM_WRITE or VM_OPERATION rights. ⚠️ The game kept running after observation. Rebuild the whole pointer path and require the exact same evidence immediately before writing. ✅ Read back the postcondition instead of assuming the write succeeded.

The same source is available as snapshot_pipeline.rs.

Section: Build and run against Wesnoth.

Use the exact 32-bit Wesnoth 1.14.9 course build, start a disposable local match, and build the Windows binary:

Terminal window

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

Confirm that the printed address and value match Cheat Engine or x64dbg. Then perform one explicit change:

Terminal window

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

The visible gold should become 888. End the match and run it again: the tool should report a null or unstable object instead of writing to address zero.

Section: Read failures as information.

Lesson table

A trustworthy tool has more useful stop paths than force paths. 🛡️

Section: Extend the architecture.

Once this pipeline is clear, try these controlled upgrades:

add a target-profile name and executable hash to the snapshot;

attach a timestamp and module base to each capture;

replace two reads with a game-owned frame counter when one is known;

make Action::Observe and Action::SetGold(u32) an enum;

unit-test decision logic with fake snapshots, without opening a process.

Keep remote I/O at the edge. The middle of the program should compare ordinary typed values.

Section: What the write gate establishes.

The snapshot carries player and side identity along with gold and its address, so a changed object path invalidates a proposed action. Two equal captures are a bounded consistency check, not a lock on the running game. Observation mode therefore keeps a read-only handle. When an action is requested, a fresh precondition check guards the only write, and a read-back checks its postcondition before the tool reports success.