Skip to content

feat(cheat): implement Game Genie + Pro Action Replay cheat codes (T-81-003) - #54

Merged
doublegate merged 2 commits into
mainfrom
feat/t-81-003-cheat-codes
Jul 9, 2026
Merged

doublegate merged 2 commits into
mainfrom
feat/t-81-003-cheat-codes

Conversation

@doublegate

Copy link
Copy Markdown
Owner

Summary

Implements T-81-003's full stated scope, behind a new cheats flag:

  • Decode: a new rustysnes_core::cheat module decodes SNES Game Genie codes (XXXX-XXXX, 9 characters including the dash, the 16-character alphabet DF4709156BC8A23E) and Pro Action Replay codes (8 hex digits, AAAAAADD — 6 hex-digit address, 2 hex-digit value, no scrambling) into a plain 24-bit CPU-bus (address, value) patch. Ported from bsnes's CheatEditor::decodeSNES (ref-proj/bsnes/bsnes/target-bsnes/tools/cheat-editor.cpp) and cross-checked bit-for-bit against Mesen2's independent CheatManager::ConvertFromSnesGameGenie/ConvertFromSnesProActionReplay — both codebases compute an identical address/value for any given code. Unit tests decode real commercial codes drawn from Mesen2's shipped CheatDb.Snes.json as an external-oracle check.
  • Application: unlike NES's Game Genie (PRG-ROM read interception), neither SNES format supports a compare byte and neither needs LoROM/HiROM bank translation in the decoder — that stays the Bus's job. A decoded patch is applied by poking WRAM directly via Bus::poke_wram (the same bank/mirror-aware accessor T-81-002's scripting/movie work already built), applied every real frame before it runs. A cheat is host-applied external input (docs/adr/0004), not emulated hardware — with cheats off, or no entries enabled, nothing executes and the determinism contract is untouched.
  • Frontend: a Tools → Cheats… window (add/enable/disable/remove codes, shows the decoded address=value), gated #[cfg(feature = "cheats")]. Unlike scripting's mlua, cheat decoding is pure computation with no platform constraint, so this works on native and wasm32 both — verified via clippy on both wasm-winit and wasm-canvas.
  • In-memory only for this pass (no per-ROM disk persistence yet) — matches the frontend's own quick-save slot's current in-memory-only maturity level; an honest, documented scope cut, not a silent gap.

Test plan

  • cargo test --workspace (357 tests, incl. 8 new rustysnes_core::cheat unit tests against real commercial-code oracles, 4 new rustysnes-frontend::cheats unit tests)
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo clippy -p rustysnes-frontend --all-targets --features cheats -- -D warnings and --features cheats,scripting
  • cargo clippy -p rustysnes-frontend --target wasm32-unknown-unknown --no-default-features --features wasm-winit,cheats --lib -- -D warnings and wasm-canvas,cheats
  • cargo build -p rustysnes-core --target thumbv7em-none-eabihf --no-default-features (no_std gate)
  • cargo fmt --check
  • RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps and -p rustysnes-frontend --features cheats,scripting
  • With cheats off, full default-feature workspace build/test/clippy/fmt/doc verified unaffected

🤖 Generated with Claude Code

…81-003)

Adds rustysnes_core::cheat, decoding SNES Game Genie (XXXX-XXXX,
16-char alphabet) and Pro Action Replay (8 hex digits, no scrambling)
codes into a 24-bit CPU-bus (address, value) patch. Ported from
bsnes's CheatEditor::decodeSNES and cross-checked bit-for-bit against
Mesen2's independent decoder; unit tests use real commercial codes
from Mesen2's shipped cheat database as an external oracle.

A decoded patch is applied via Bus::poke_wram (the same WRAM accessor
the T-81-002 scripting/movie work already built), so a cheat is
host-applied external input, not emulated hardware, and the
determinism contract holds unchanged when the new `cheats` feature is
off. Wires a Tools -> Cheats... window (native and wasm32 both, since
decoding is pure computation with no mlua-style platform constraint)
for adding/enabling/removing codes, applied every real frame before
it runs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 9, 2026 21:37

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces Game Genie and Pro Action Replay cheat-code support under a new cheats feature flag, adding a decoding module in rustysnes-core and a dedicated UI window in the frontend to manage and apply patches. The review feedback highlights a critical correctness issue: Game Genie codes target ROM addresses rather than WRAM, meaning applying them via poke_wram will have no effect; instead, read operations should be intercepted. Additionally, the reviewer suggests avoiding heap allocations and double passes during decoding, resolving a potential lossy truncation in character casting, preserving specific parsing errors during format dispatch, and suffixing egui widget labels with unique IDs to prevent ID clashes in the cheat list.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/rustysnes-frontend/src/cheats.rs Outdated
Comment thread crates/rustysnes-core/src/cheat.rs
Comment thread crates/rustysnes-core/src/cheat.rs
Comment thread crates/rustysnes-core/src/cheat.rs
Comment thread crates/rustysnes-core/src/cheat.rs
Comment thread crates/rustysnes-frontend/src/ui_shell.rs

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds SNES cheat-code support (Game Genie + Pro Action Replay) to RustySNES, introducing a core decoder and a feature-gated frontend UI + per-frame WRAM patch application, with accompanying documentation/changelog updates.

Changes:

  • Add rustysnes-core::cheat with Game Genie / Pro Action Replay decoding + unit tests.
  • Add rustysnes-frontend cheats feature: in-session cheat list, Tools → Cheats… UI, and per-frame Bus::poke_wram application.
  • Update sprint tracking, docs/STATUS.md, and CHANGELOG.md to reflect T-81-003 completion and feature details.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
to-dos/phase-8-reach/sprint-1-instrumentation.md Marks T-81-003 acceptance criteria and sprint checklist as completed with implementation notes.
docs/STATUS.md Updates frontend status to mention the new cheats feature and where it lives.
crates/rustysnes-frontend/src/ui_shell.rs Adds Cheats window state and renders a new Cheats UI entry under Tools.
crates/rustysnes-frontend/src/lib.rs Feature-gates and exports the new cheats module.
crates/rustysnes-frontend/src/cheats.rs Implements cheat entry parsing/storage and per-frame WRAM application, plus tests.
crates/rustysnes-frontend/src/app.rs Stores cheat list in Active and applies enabled cheats before each emulated frame.
crates/rustysnes-frontend/Cargo.toml Introduces the cheats feature flag for the frontend.
crates/rustysnes-core/src/lib.rs Exposes the new cheat module from core.
crates/rustysnes-core/src/cheat.rs Implements the decoders + tests for Game Genie and Pro Action Replay.
CHANGELOG.md Documents the new cheats feature for the upcoming release entry.

Comment thread crates/rustysnes-core/src/cheat.rs Outdated
Comment thread crates/rustysnes-frontend/src/ui_shell.rs
…#54

- CRITICAL: real Game Genie/Pro Action Replay codes overwhelmingly
  target cartridge ROM (a pass-through cart intercepting CPU-visible
  reads), not WRAM. Applying decoded patches via Bus::poke_wram made
  virtually every real Game Genie code a silent no-op. Fixed by adding
  a Bus::set_cheats/read24 CPU-read intercept: Bus checks an installed
  patch list once per read (empty and one branch when unused) and
  substitutes a matching patch's value, without modifying the
  underlying ROM/RAM byte. crate::cheats::apply_all (WRAM poke)
  becomes crate::cheats::sync (installs the enabled set into Bus).
- cheat.rs: genie_nibble no longer lossily casts a non-ASCII char to
  u8 (could alias onto a valid alphabet byte); decode_game_genie/
  decode_pro_action_replay avoid the earlier Vec<char> allocation
  (no_std-conscious) while still checking shape (length/dash) before
  character content, which decode()'s corrected fallback depends on;
  decode() now only falls through to Pro Action Replay on a genuine
  UnrecognizedFormat, not any Game Genie error, so a Game-Genie-shaped
  code with an invalid character reports that specific error instead
  of a misleading "wrong format".
- ui_shell.rs: the cheat list's per-row widgets (identical "" checkbox
  and "Remove" button labels in a loop) collided IDs across rows in
  egui; wrapped each row in ui.push_id(i, ...).

Regression tests added for all four; full verification matrix
(build/test/clippy default + cheats+scripting, wasm-winit/wasm-canvas
clippy, no_std gate, fmt, doc gate) re-run clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@doublegate doublegate self-assigned this Jul 9, 2026
@doublegate
doublegate merged commit 377956d into main Jul 9, 2026
5 checks passed
@doublegate
doublegate deleted the feat/t-81-003-cheat-codes branch July 9, 2026 22:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants