Gameplay Differential Capture V2¶
scripts/frida/gameplay_diff_capture_v2.js captures deterministic gameplay
ticks as replay-like checkpoint rows plus rich event diagnostics.
Primary output:
C:\share\frida\gameplay_diff_capture_v2.jsonl
Attach:
Just shortcut (Windows VM):
Why use v2¶
- Emits
event: "tick"rows aligned togameplay_update_and_render. - Each tick includes
checkpointfields compatible withreplay convert-original-capture. - Captures per-tick command/event summary (
projectile_spawn, SFX, bonus apply,secondary_projectile_spawn, weapon assign, damage, creature spawns, state transitions). - Captures projectile hit resolves from native
creature_find_in_radiuswhen called byprojectile_update(event_counts.projectile_find_hit+ head rows withcorpse_hit), so missing corpse-hit RNG branches can be diagnosed directly. - Captures both template-level and low-level creature spawn paths
(
creature_spawn_template,creature_spawn,survival_spawn_creature,creature_spawn_tinted) with caller buckets. - Captures input-query telemetry (
input_primary_*,input_any_key_pressed) and RNG usage (crt_rand) per tick, including hashes/callers. - Captures perk applications (
perk_apply) including outside-tick carry (perk_apply_outside_before) so replay conversion can reconstruct picked perk IDs. - Captures RNG rolls with stable per-session sequence IDs (
seq), per-tick call indices (tick_call_index), and mirrored CRT state transitions (state_before_u32/state_after_u32) so branch drift can be anchored by RNG order instead of absolute tick numbers. - Emits per-player key state snapshots (
input_player_keys) derived fromplayer_updatekey queries, so replay conversion can avoid ambiguousinput_any_keyunions when opposite directions appear in the same tick. - Emits per-tick diagnostics for timing/sampling analysis:
diagnostics.timing,diagnostics.spawn, pluscheckpoint.debug. Spawn diagnostics include low-level source buckets (top_low_level_sources). - Emits session fingerprint metadata (
session_id, module hash, pointer hash) for run-to-run provenance. - Emits compact
before/aftersnapshots (including input + bindings) and detailed entity samples each captured tick by default.
Convert to checkpoints¶
uv run crimson replay convert-original-capture \
artifacts/frida/share/gameplay_diff_capture_v2.jsonl \
analysis/frida/original_capture_v2.checkpoints.json.gz
This also writes analysis/frida/original_capture_v2.crdemo.gz by default (override with --replay).
The replay file is best-effort (rebuilt from input telemetry) and useful for
visual inspection; it bootstraps from the first captured tick but still does
not guarantee sidecar-level parity. Checkpoint sidecars are the source of truth
for diffing.
Verify capture directly against rewrite sim¶
uv run crimson replay verify-original-capture \
artifacts/frida/share/gameplay_diff_capture_v2.jsonl
This path does not depend on replay playback parity. It reconstructs inputs from capture telemetry, runs headless sim, then compares checkpoint state fields at captured ticks and prints first divergent fields.
Divergence report + run narrative¶
uv run python scripts/original_capture_divergence_report.py \
artifacts/frida/share/gameplay_diff_capture_v2.jsonl \
--float-abs-tol 2e-3 \
--window 24 \
--lead-lookback 1024 \
--run-summary
--run-summary prints a compact timeline from the original recording
(bonus pickups, weapon assignments, perk picks when present, level-ups, and
state transitions) so divergence debugging has immediate run context.
If you only want a quick "what happened in this run?" mental model, use:
uv run python scripts/original_capture_divergence_report.py \
artifacts/frida/share/gameplay_diff_capture_v2.jsonl \
--run-summary-short
--run-summary-short prints a shorter highlight list (bonus/weapon/perk/level/state).
Both modes can be tuned with --run-summary-max-rows and
--run-summary-short-max-rows.
The report also infers rewrite-side rand_calls from checkpoint RNG marks and
prints rand_calls(e/a/d) in the window table (expected/actual/delta), plus
focus-tick stage attribution (secondary_projectiles, creatures, etc.) and
rewrite death ledger head to localize large RNG bursts quickly. With v2 projectile
hit telemetry, the window also prints p_hits(e/a) (capture projectile_find_hit
vs rewrite events.hit_count).
Track each run in docs/frida/differential-sessions.md.
Focus tick trace¶
When the divergence report points at a suspicious tick and you need deeper rewrite-side mechanics (RNG callsites + collision near-misses + indexed sample diffs), run:
uv run python scripts/original_capture_focus_trace.py \
artifacts/frida/share/gameplay_diff_capture_v2.jsonl \
--tick 3453 \
--near-miss-threshold 0.35 \
--json-out
This is especially useful when checkpoint fields still match but native RNG
callers indicate hidden branch drift (for example corpse-hit resolution).
Using --json-out without a value writes to
artifacts/frida/reports/focus_trace_tick<TICK>_latest.json.
original_capture_focus_trace.py now also prints rng_value_alignment:
- exact native-vs-rewrite RNG value prefix length for the focus tick,
- native-only tail draw count,
- dominant native
caller_staticbuckets in that missing tail, - a short inferred rewrite callsite preview for the missing native tail.
This makes it much easier to tell whether a focus mismatch is a midstream value desync or a late-tick missing branch (prefix match + missing tail).
Default capture profile¶
Without any extra env vars, v2 now captures full detail for every tracked tick:
before/aftersnapshots on every tick.- Detailed entity samples (
creatures,projectiles,secondary_projectiles,bonuses) on every tick. - Unlimited per-tick sample stream limits (
*_SAMPLE_LIMIT=-1semantics). - Unlimited RNG sample/caller heads (
CRIMSON_FRIDA_V2_RNG_HEAD=-1,CRIMSON_FRIDA_V2_RNG_CALLERS=-1). - Full per-roll RNG stream enabled by default (
CRIMSON_FRIDA_V2_RNG_ROLL_LOG=1, unlimited by default). - RNG mirror tracking on by default (
CRIMSON_FRIDA_V2_RNG_STATE_MIRROR=1). - Between-tick RNG rolls retained in tick-local diagnostics
(
rng.outside_before_*,checkpoint.rng_marks.rand_outside_before_*) with unlimited head by default. - Between-tick perk-apply events retained in tick-local diagnostics
(
perk_apply_outside_before) with unlimited head by default. - Unlimited event/phase head + tick event budget (
CRIMSON_FRIDA_V2_MAX_HEAD=-1,CRIMSON_FRIDA_V2_MAX_EVENTS_PER_TICK=-1). - Player count resolved from game memory (
config_player_count) unless manually overridden.
Backtraces remain off by default (CRIMSON_FRIDA_INCLUDE_BT=0).
Optional env knobs¶
CRIMSON_FRIDA_V2_STATES=6,9,10(override tracked game states)CRIMSON_FRIDA_V2_ALL_STATES=1(capture ticks for all states)CRIMSON_FRIDA_V2_TICK_DETAILS_EVERY=30(throttle detailed entity samples)CRIMSON_FRIDA_V2_CREATURE_SAMPLE_LIMIT=24CRIMSON_FRIDA_V2_PROJECTILE_SAMPLE_LIMIT=32CRIMSON_FRIDA_V2_SECONDARY_PROJECTILE_SAMPLE_LIMIT=32CRIMSON_FRIDA_V2_BONUS_SAMPLE_LIMIT=12CRIMSON_FRIDA_V2_INCLUDE_RAW_EVENTS=1CRIMSON_FRIDA_V2_INPUT_HOOKS=0(disable input query hooks)CRIMSON_FRIDA_V2_RNG_HOOKS=0(disable rng hooks)CRIMSON_FRIDA_V2_CREATURE_SPAWN_HOOK=0(disable low-levelcreature_spawnhook)CRIMSON_FRIDA_V2_RNG_HEAD=-1(per-tick RNG sample head size; default unlimited,0disables head samples)CRIMSON_FRIDA_V2_RNG_CALLERS=-1(per-tick RNG caller buckets; default unlimited)CRIMSON_FRIDA_V2_RNG_STATE_MIRROR=0(disable mirrored CRT state tracking)CRIMSON_FRIDA_V2_RNG_OUTSIDE_TICK_HEAD=256(reduce between-tick RNG roll head retained on the next tick;0disables)CRIMSON_FRIDA_V2_RNG_ROLL_LOG=0(disable per-callevent: "rng_roll"rows)CRIMSON_FRIDA_V2_MAX_RNG_ROLL_LOG_EVENTS=-1(cap forrng_rollrow emission;-1unlimited)CRIMSON_FRIDA_PLAYER_COUNT=2(optional override; default usesconfig_player_countfrom memory)CRIMSON_FRIDA_V2_FOCUS_TICK=1234andCRIMSON_FRIDA_V2_FOCUS_RADIUS=30(optional focus tagging for diagnostics; does not gate snapshots/samples)
RNG-Trace Defaults¶
The capture script now defaults to the full RNG divergence-trace profile:
CRIMSON_FRIDA_V2_RNG_ROLL_LOG=1
CRIMSON_FRIDA_V2_MAX_RNG_ROLL_LOG_EVENTS=-1
CRIMSON_FRIDA_V2_RNG_HEAD=-1
CRIMSON_FRIDA_V2_RNG_CALLERS=-1
CRIMSON_FRIDA_V2_RNG_OUTSIDE_TICK_HEAD=-1
CRIMSON_FRIDA_V2_RNG_STATE_MIRROR=1
Set env vars only if you want to reduce or disable this tracing volume.