1 client realtime authority store and frame projection
forgejo-actions edited this page 2026-07-15 12:43:13 +00:00

Client Realtime Authority Store And Frame Projection

The client realtime state separates server-owned facts, local prediction, transport state, transient ingress events, and frame-safe read models. This keeps low-latency presentation possible without letting an optimistic UI value become authoritative gameplay state.

Ownership And Data Flow

RealtimeSessionState is the transport-thread shared state behind RealtimeSessionHandle. Its major ownership groups are:

  • transport: endpoint, session token, health, reconnect/transfer state, runtime profile, packet status, and telemetry;
  • world: authoritative local player baseline, AOI players and buckets, replica directory, snapshot staging, clock sync, environment, and cutscene sync;
  • authority: typed gameplay snapshots, authoritative event journal, and AuthoritySnapshotStore indexes and diagnostics;
  • prediction: movement reconciliation, pending gameplay predictions, last-sent state, and optimistic UI overlays;
  • ui_events: bounded or drain-once ingress such as chat, action results, combat events, rewards, and overlays;
  • outbound: client command queues and wakeup state.

Network reducers own writes to server-derived state. Gameplay and presentation systems consume projections or drain explicitly owned event queues. They must not manufacture authority by writing projected values back into authority.

Authoritative Snapshots And Store

RealtimeGameplayAuthoritySnapshots retains the typed snapshots used by consumers: stats, combat, inventory, currencies, equipment, quest, gameplay conditions, and farming tiles. Its AuthoritySnapshotStore adds indexed access and provenance:

  • per-domain revision and last applied event metadata;
  • stale-domain tracking;
  • inventory by item id, currency by id, equipment by slot, and quest by quest id;
  • gameplay-action results and denials by request id;
  • a projected index of pending predictions by request id.

Each authoritative packet is reduced through its packet-specific reducer. The reducer updates the typed snapshot, records an authoritative event and packet label, and applies the matching store domain. Snapshot-owned revisions, such as equipment or quest revision, are compared with the client event revision by taking the larger value.

The authoritative event revision is client-local ordering metadata, not a replacement for domain revisions. The journal is capped at 128 envelopes.

Optimistic Overlays

RealtimeOptimisticUiOverlay contains optional gameplay, appearance, inventory, stats, equipment, and equipped-tool values. Projection merges use the optimistic value first only for domains that define an overlay. The underlying authoritative snapshot and store remain unchanged.

For example, predicted loadout application can immediately project inventory, stats, equipment, and equipped tool while authority.inventory, authority.player_stats, authority.equipment, and their store revisions remain untouched. When matching authoritative snapshots arrive, reducers clear the relevant overlay before publishing the authoritative value.

Equipment projection deliberately exposes all three views:

  • equipment: merged value for normal presentation;
  • authoritative_equipment: latest server value;
  • optimistic_equipment: pending UI value, if any.

Gameplay-action results remove the pending prediction and reconcile request-specific overlay state. A result also records the gameplay-action domain and marks Prediction stale; downstream reconciliation and later snapshots establish the fresh view.

Frame Projection Data Flow

The per-frame path is:

stream/datagram ingress
  -> packet reducer or AOI staging window
  -> RealtimeSessionState authority/world/prediction
  -> flush at most one staged AOI snapshot for this render frame
  -> RealtimeFrameProjection
  -> scene authority, dialogue, gameplay UI, and other Bevy consumers

tick_multiplayer_ui_state polls the async job and transport, then flushes buffered AOI snapshots. publish_realtime_frame_projection_system runs afterward and replaces the Bevy resource only when its value changed.

RealtimeFrameProjection contains optional transport, world, and gameplay projections plus copied chat events. With no realtime handle it is empty. World projection merges optimistic local gameplay/appearance over the authoritative local player but leaves visible remote players authoritative. Gameplay projection merges only the supported optimistic domains and clones an AuthoritySnapshotStore augmented with the current pending-prediction journal.

The projection is a frame snapshot, not a mutation API. Destructive queues such as gameplay action results and combat rewards keep explicit owners and are not generalized into the copied frame resource.

Lifecycle And State Transitions

Session activation

Activation installs the session token, runtime profile, local authoritative player, environment, and transport state. A fresh activation clears prediction and AOI phase state. Resume activation retains only unacknowledged movement and gameplay predictions, advances the event revision to at least the resume revision, and still clears the old AOI baseline.

Normal authoritative update

The packet reducer updates a typed snapshot, records event provenance, refreshes the store domain, and clears a matching overlay where defined. The next frame projection exposes the merged result.

Transfer preparation

Transfer changes endpoint and token, marks transport Transferring, clears AOI/replica and snapshot-staging state, resets the last snapshot id, and clears pending trigger resolutions. Destination activation establishes the new local baseline.

Server disconnect

Disconnect clears prediction and replicated AOI phase state. Player combat and gameplay-condition snapshots are removed and their store domains marked stale. Other typed snapshots are not individually erased by this transition, so consumers must gate authority use on live transport/frame state. Full connection cleanup later drops the realtime handle.

Extending An Authoritative Domain

When adding a new server-owned client domain:

  1. Add the typed snapshot to the appropriate world/protocol contract and realtime authority aggregate.
  2. Add descriptor/dispatch metadata so the packet has a stable authoritative event kind and packet label.
  3. Implement one reducer that updates the typed value and records store provenance.
  4. Add an AuthoritySnapshotDomain and store index only when consumers need lookup, revision, stale, or incident diagnostics.
  5. Define whether prediction is allowed. If it is, add an overlay and explicit reconciliation/clear behavior; do not reuse the authoritative field for prediction.
  6. Add the projected value to RealtimeGameplayProjection or RealtimeWorldProjection and consume it from RealtimeFrameProjection in frame systems.
  7. Test authoritative application, optimistic non-mutation, reconciliation, disconnect/transfer behavior, and frame projection.

Rules And Invariants

  • Server packet reducers are the write boundary for authoritative client state.
  • An optimistic overlay may change presentation but must not advance an authority-domain revision or populate an authoritative index.
  • Authoritative arrival wins by clearing its matching overlay.
  • Frame consumers must check transport health before treating projected data as live authority.
  • AOI snapshots are monotonic by snapshot id and are limited to one staged application per render frame.
  • Pending predictions appear in the projected store without being inserted into the underlying authoritative store.
  • Event queues with one destructive consumer must be drained once and fanned out with Bevy messages when multiple readers need them.
  • Transfer and disconnect must clear old AOI replicas before a new world baseline is presented.

Validation And Debugging

Focused regression tests include:

cargo test -p aether realtime_session_state_builds_typed_world_and_gameplay_projections
cargo test -p aether predicted_loadout_projects_optimistic_view_without_authority_mutation
cargo test -p aether authority_snapshot_store_indexes_quests_and_pending_actions_by_request
cargo test -p aether gameplay_projection_projects_pending_predictions_from_journal
cargo test -p aether server_disconnect_transition_resets_prediction_authority_and_interest_phase_state

For a stale or wrong value, compare these layers in order:

  1. transport.last_server_packet and transport.last_message: did the expected reducer run?
  2. The typed field under authority: did decode and assignment succeed?
  3. domain_revision, last_applied_event, and stale_domains: did store provenance move?
  4. optimistic_ui: is a prediction intentionally masking the server value?
  5. RealtimeFrameProjection: was a changed projection published after polling and staged snapshot flush?
  6. The final consumer: is it using the frame projection or an unrelated local fallback?

A useful equipment diagnostic is to print merged, authoritative, and optimistic revisions together. If the merged value is wrong while the authoritative value is correct, inspect overlay clearing. If all are stale, inspect packet dispatch and reducer application. If session state is correct but the UI is stale, inspect frame resource change detection and the consumer's rebuild signature.

The client logs rejected gameplay actions with request id, request kind, predicted action, and server message. Expected range/contact denials are debug-level; other denials are warnings and are indexed in the authority store.