Skip to content

test: add deterministic replay snapshots#279

Merged
jonathanperis merged 3 commits into
mainfrom
test/replay-overlay-snapshots
May 16, 2026
Merged

test: add deterministic replay snapshots#279
jonathanperis merged 3 commits into
mainfrom
test/replay-overlay-snapshots

Conversation

@jonathanperis
Copy link
Copy Markdown
Owner

@jonathanperis jonathanperis commented May 16, 2026

Summary

  • add --replay-script deterministic smoke input that feeds gameplay movement/jump state plus SDL overlay events
  • expand scripted smoke to run generated replay scenarios across all levels/seeds
  • generate overlay text snapshots directly from src/render/render_overlay.c and enforce freshness in docs drift checks
  • document replay smoke and overlay snapshots in the wiki/source map

Verification

  • make validate-levels && make test CC=clang
  • make smoke CC=clang SMOKE_FRAMES=5 SMOKE_SEED=1
  • make scripted-smoke CC=clang SMOKE_FRAMES=5 SMOKE_SEEDS="1 7 23"
  • make docs-drift
  • cd docs && mise exec node@24.13.1 -- bun run lint
  • cd docs && mise exec node@24.13.1 -- bun run build
  • make web
  • make sanitize CC=clang
  • make sanitize-smoke CC=clang SMOKE_FRAMES=5 SMOKE_SEED=1
  • git diff --check
  • diff secret/sink scan
  • independent review twice; first blockers resolved, final review merge-ready

Summary by CodeRabbit

  • New Features

    • Added deterministic replay script support via --replay-script command-line flag for automated testing scenarios
  • Documentation

    • Updated build-system and overlay-snapshots documentation
    • Added automated overlay-snapshot generation tooling
  • Chores

    • Enhanced CI workflow and Makefile with overlay-snapshot freshness validation

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

Warning

Rate limit exceeded

@jonathanperis has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 43 minutes and 40 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8dd3c972-06f8-46fd-9270-facf7252d19d

📥 Commits

Reviewing files that changed from the base of the PR and between ea38892 and 8bf7158.

📒 Files selected for processing (6)
  • docs/wiki/build-system.md
  • docs/wiki/source-files.md
  • src/game.h
  • src/input/game_replay.c
  • src/main.c
  • tools/run_scripted_smoke.py
📝 Walkthrough

Walkthrough

This PR implements deterministic replay injection for smoke testing by adding SDL key event scripting support. It extends GameState with replay state tracking, introduces a replay event injection module that reads script files and pushes SDL events, integrates replay input masks into player input handling, adds --replay-script CLI support, and updates smoke test tooling to execute scenarios with injected player input. Documentation and quality checks validate the replay-script wiring.

Changes

Deterministic Replay System

Layer / File(s) Summary
Game state and input contracts
src/game.h, src/player/player.h
GameState adds four replay-tracking fields (replay_script_path, replay_input_mask, replay_held_mask, replay_frame). player.h defines a PLAYER_INPUT_* bitmask enum and extends player_handle_input to accept replay_input_mask parameter.
Game replay injection system
src/input/game_replay.h, src/input/game_replay.c
New module parses replay script files line-by-line, maps script action names to SDL keycodes and player input bitmasks, maintains held-vs-momentary input state, and injects SDL_KEYDOWN/SDL_KEYUP events via SDL_PushEvent.
Player input handling with replay
src/player/player_input.c
Extended player_handle_input uses replay_input_mask to augment keyboard/controller sampling for jump, vine grab, climbing, and ground movement states via bitwise checks.
Game loop and CLI integration
src/core/game_loop.c, src/core/game_player_step.c, src/main.c
Game loop calls game_replay_inject_events before normal event handling. Main parses --replay-script <path> flag with full argument validation and copies the replay path into GameState for both direct (--level) and menu-launched gameplay. Player step passes replay_input_mask to input handler.
Smoke test execution with replay
tools/run_scripted_smoke.py
Script adds --replays CLI option, generates default replay .replay files on demand via tempfile.TemporaryDirectory, and runs smoke scenarios across levels × seeds × replays by passing --replay-script to the binary.
Build system, documentation, and validation
.github/workflows/docs.yml, Makefile, docs/wiki/build-system.md, docs/wiki/overlay-snapshots.md, docs/wiki/source-files.md, tools/check_roadmap_quality.py, tools/generate_overlay_snapshots.py
Docs workflow triggers on generate_overlay_snapshots.py changes. Makefile adds overlay-snapshots target and updates docs-drift to check snapshot freshness. Build docs describe replay-script smoke behavior. Quality checks validate replay-script wiring across run_scripted_smoke.py, player input headers/sources, docs, and game_replay.c SDL event injection.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

documentation, github_actions

Suggested reviewers

  • fersantos
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding deterministic replay snapshots for testing purposes, which aligns with the core objectives of implementing replay-script functionality, overlay snapshot generation, and expanded scripted smoke testing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/replay-overlay-snapshots

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread src/input/game_replay.c Fixed
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tools/generate_overlay_snapshots.py (1)

23-30: ⚡ Quick win

Consider brace-counting for precise function body extraction.

The current approach slices from the start of one render_*_overlay function to the start of the next. If helper functions appear between overlay functions in render_overlay.c, their string literals would be incorrectly attributed to the preceding overlay function.

A brace-counting parser would extract only the body of each matched function, avoiding spurious token extraction.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/generate_overlay_snapshots.py` around lines 23 - 30, The current
overlay_blocks() function slices from one render_*_overlay start to the next
which misattributes any intervening helpers; instead implement brace-counting
starting at each regex match (the group(1) name) to find the matching closing
'}' for that function body and slice only that span before calling text_tokens;
update overlay_blocks() to iterate matches from starts, compute body_end by
scanning source from match.end() while tracking '{' and '}' nesting (respecting
strings/comments if necessary), then set blocks[match.group(1)] =
text_tokens(source[match.start():body_end]) using the same SOURCE and
text_tokens symbols.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tools/generate_overlay_snapshots.py`:
- Around line 23-30: The current overlay_blocks() function slices from one
render_*_overlay start to the next which misattributes any intervening helpers;
instead implement brace-counting starting at each regex match (the group(1)
name) to find the matching closing '}' for that function body and slice only
that span before calling text_tokens; update overlay_blocks() to iterate matches
from starts, compute body_end by scanning source from match.end() while tracking
'{' and '}' nesting (respecting strings/comments if necessary), then set
blocks[match.group(1)] = text_tokens(source[match.start():body_end]) using the
same SOURCE and text_tokens symbols.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3f075fb4-31f8-47d6-a954-d1ecb40ee61c

📥 Commits

Reviewing files that changed from the base of the PR and between cbeef23 and ea38892.

📒 Files selected for processing (16)
  • .github/workflows/docs.yml
  • Makefile
  • docs/wiki/build-system.md
  • docs/wiki/overlay-snapshots.md
  • docs/wiki/source-files.md
  • src/core/game_loop.c
  • src/core/game_player_step.c
  • src/game.h
  • src/input/game_replay.c
  • src/input/game_replay.h
  • src/main.c
  • src/player/player.h
  • src/player/player_input.c
  • tools/check_roadmap_quality.py
  • tools/generate_overlay_snapshots.py
  • tools/run_scripted_smoke.py

Comment thread src/input/game_replay.c Fixed
@jonathanperis jonathanperis merged commit a82eb03 into main May 16, 2026
9 checks passed
@jonathanperis jonathanperis deleted the test/replay-overlay-snapshots branch May 16, 2026 22:11
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