# ForgeGuard gameplay recordings

The modern core can save short, playable reconstructions of server observations for staff investigations.
They use a separate recorder and format from the existing deterministic case-check replay.
No client mod is required. The first recorder is restricted to native **Paper 1.21.11**; it is not
available in the portable staff adapter, other native releases or Folia. Updating the website alone
does not add recording support to an older plugin JAR.

## Staff workflow

1. Pair the Minecraft server with its website workspace as usual.
2. Open **Players → a player → Gameplay replays**. Retained clips can be watched after logout.
3. For an online, unprotected player, a web moderator/admin/owner can choose **Save replay snippet**
   and enter a reason. The request saves the available recent buffer and captures a short period
   after the trigger. Keep the dialog open or return to the list later.
4. Open **Evidence → Inspect → Watch gameplay replay** for a case's automatic snippet, when available.
5. Use Play/Pause, the time slider, speed control, Orbit/Top/Player view cameras and event jumps.
   Player view follows recorded yaw/pitch at a fixed standing eye height; it is not the player's exact camera.
6. Read partial-data warnings, timestamps, ping and event details before taking a moderation action.
   **Download replay data** saves JSON for the investigation, not a rendered video.

Starting a new capture requires `moderate` web capability. Watching retained clips requires `read`.
The relay rechecks membership and capabilities before dispatch, and Minecraft rechecks its own
policy and protected-player rules. Capture requests are audited. Website roles do not grant
Minecraft permissions.

In Minecraft, staff with `forgeguard.staff` and `forgeguard.recordings` can open a player's GUI and
choose **Save replay snippet**. **Visual recordings** shows retained capture information, and a case
has a **Visual recording** entry. Use the linked website to watch the 3D reconstruction; playback
inside a Minecraft world is not implemented by this version.

The manual request has a stable recording UUID. If the connection fails, **Retry same capture**
resubmits the original ID and reason. The console keeps that pending request in this tab's session
storage. While the original record is retained, an identical request returns it and a different
payload under that ID is refused. Do not issue a fresh request simply because the first response
was uncertain. Retention is not an indefinite idempotency ledger.

## What is captured

- Player position, yaw/pitch, health, ping and on-ground state at up to 5 samples per second.
- Up to 12 nearby entities per sample, including their observed positions and bounding dimensions.
- Nearby loaded block **materials**, once per second, within a configurable bounded volume.
  Known air is explicitly recorded; omitted cells mean unknown, unloaded or missed under budget.
- Event markers for findings/manual triggers and supported gameplay events such as swings,
  attacks, damage, block placement/breakage, teleport, death and disconnect.
- The case association, capture limits, timestamps and partial-data warnings.

The viewer uses simplified coloured blocks and entity shapes. It does not record client textures,
resource packs, skins, exact block shapes/states, inventory contents, chat, sound, screen video,
private cheat menus or X-ray rendering. Events and poses are sampled, so a fast action may fall
between observations. A server-observed attack/damage marker does not reconstruct every client
animation or prove an illegal hit. Orbit cameras can reveal captured nearby blocks/entities that
were outside the player's visible screen; this does not establish what the player could see.

Interpolation is a display aid between eligible adjacent samples. It is suppressed for gaps,
world transitions, large jumps and paths crossing recorded solid or unknown cells. Entity positions
remain sampled. The viewer identifies stale/missing world snapshots and never invents unseen terrain.
Use event timestamps and original samples for an investigation; visual playback is not a new cheat verdict.

## Budgets and configuration

Defaults under `recordings:` in the modern `config.yml`:

```yaml
recordings:
  enabled: true
  automatic: true
  pre-seconds: 10
  post-seconds: 5
  maximum-players: 16
  maximum-pending: 16
  radius: 4
  vertical-radius: 3
  maximum-entities: 12
  sample-budget-micros: 3000
  maximum-clips: 1000
  maximum-disk-mb: 128
  retention-days: 7
```

Changes to these infrastructure settings require a server restart. This preserves one capture
contract for each active clip. Pre/post duration accepts 1–10 seconds; player and pending budgets
accept 1–16; radius 1–4; vertical radius 1–3; entity count 0–12; cooperative sampling budget
500–5,000 microseconds; retained count 10–1,000; disk budget 8–512 MiB; retention 1–30 days.

`web.allow-moderation` must also be enabled to start captures from the website. Turning it off
does not remove retained clips or turn off automatic case recording. Recorder health appears in
**Server health**, including sampling skips, dropped capture triggers and persistence failures.

At defaults, the world volume is at most 9×7×9 cells per snapshot. The rolling buffer covers at most
16 tracked players at once, and up to 16 clips may collect their post-trigger context. This is a
bounded first implementation, not continuous full-world recording or a guarantee that every player
on a large server is always buffered. Capacity misses are reported; a refused automatic capture does
not stop normal anti-cheat evidence collection. A newly tracked player cannot have a complete prior
10 seconds of footage.

The sampling deadline is cooperative: it stops further sampling between API operations. It cannot
interrupt one Bukkit call or guarantee a maximum server tick time. World/entity collection runs on
Paper's main thread; serialization, reads, atomic writes and retention run on a bounded background
worker. No unloaded chunks are deliberately loaded for a recording. Validate the overhead on the
actual server workload before increasing any allowed budget.

Each encoded clip is capped at 1.5 MiB, within the web relay's 2 MiB result-body bound. If necessary,
whole observations are omitted and the result is marked partial; JSON is never byte-truncated.
Recordings use their own retention limits. A case may remain after its visual clip has expired.

## Capture state and failure handling

`recording` means the initial snapshot is committed but post-trigger recording or final persistence
has not completed. `ready` means the final clip was committed without a recorded completeness loss;
it still has all the inherent sampling and scene limits above. `partial` means available observations
were saved with explicit completeness warnings. It never means that missing observations were rebuilt.

Short prehistory, disconnects, shutdowns, sampling gaps, missing scene cells, event/byte limits and
other capture omissions can produce partial data. After a restart, a committed initial snapshot from
an interrupted recording is recovered as partial. A storage failure must be reported rather than
shown as successful playback. Keep normal server backups if evidence must be preserved beyond retention.

The website automatically checks pending clips for a bounded period and then offers a manual check.
Close a viewer to stop its animation, listeners and pending UI refreshes. A stale response cannot
replace a newly opened dialog or another server's investigation.

The public console's examples are labelled **synthetic demo** throughout. They are generated in the
browser, never sent to Minecraft and never used as live evidence. Existing cases with movement-only
traces cannot be retroactively converted into world recordings.

See [Website integration](WEBSITE-INTEGRATION.md) for the routes and version-1 clip schema.

## Verification for this implementation

The September 24, 2026 development build passed 199 Java tests, six universal-source permission
contract tests and 224 website/API/renderer tests. Seven isolated native checks ran on Paper 1.21.11
with PacketEvents 2.13.0 and a generated Minecraft client. They verified actual pre/post movement,
changing stone/gold/air snapshots, nearby entities, trigger/teleport events, request idempotency,
manual-capture policy, automatic case association, deterministic replay compatibility and persistence
through a real Paper restart. A second check captured and retrieved a ready clip through the updated
persistent local console and confirmed the same-ID retry returned the existing recording.

The native harness is `scripts/visual-replay-live-smoke.mjs`; it requires the existing local Paper,
dependency and test-client fixtures and creates an isolated loopback server. The exact tested core
SHA256 is `31536a9ee90b3547816891e075afb609ad6e9193097b195772a901308217fa69`.
These checks do not qualify other Minecraft versions, large player populations, every gameplay
mechanic or long-running production performance.
