Server-Authoritative Hazards

Problem

In multiplayer games, clients cannot be trusted to resolve critical state changes such as dealing damage, updating scores, or resolving hazard collisions. However, waiting for server confirmation before displaying visual feedback makes the game feel unresponsive, laggy, and disjointed for the local player.

Pattern

The server retains absolute authority over the canonical simulation and critical state changes. Simultaneously, the client employs local prediction to immediately play visual/audio feedback (juice) and update its local predictive state. If the server rejects the action, the client reconciles its state gracefully.

When to Use

  • Implementing damage dealing, taking damage, health reduction, or death states.
  • Handling score updates, item collection, and win/loss conditions.
  • Spawning, moving, or resolving dynamic environmental hazards and hitboxes.
  • Any mechanic where competitive integrity is required.

Recipe

1. Strict Server Authority

  • Concept: The server executes the canonical simulation. Only the server has the privilege to change an entity’s health, score, or living status via the unifiedGameState.
  • Implementation: Expose read-only state to the client. When an event requires state mutation (like damage), the client dispatches a genie_inject_event. The server processes this event in its tick loop, mutates the authoritative state, and broadcasts the updated state back to all connected clients.

2. Immediate Client Prediction

  • Concept: When a local player takes an action (e.g., attacks, jumps, or dashes), the client immediately plays local visual and audio feedback and predicts the outcome locally without waiting for the server’s RPC response.
  • Implementation: Implement a local prediction layer. If the player presses “Attack”, immediately trigger the attack animation, spawn slash VFX, and deduct local cooldowns. If the attack visually connects, play hit-stop and sound effects locally, even before the server confirms the damage.

3. Server Event Validation

  • Concept: The server must rigorously validate all incoming genie_inject_event actions to prevent cheating, spoofing, or desync exploitation.
  • Implementation: Before applying damage or state changes, the server checks: Is the attacker alive? Is the ability off cooldown? Are the attacker and target within mathematically valid range (accounting for network latency buffers)? Does the attacker have line of sight? Only if all checks pass does the server apply the change.

4. Graceful Reconciliation

  • Concept: If the server’s authoritative state differs from the client’s predicted state, the client must snap back to the server’s state smoothly, overriding its local prediction.
  • Implementation: Maintain a history buffer of past inputs and predicted states on the client. When the server state arrives, compare it to the historical state at that specific tick. If they diverge (e.g., an attack was rejected due to range validation failure), rewind the client to the server state and quickly interpolate back to the present, overriding the false prediction.

5. Deterministic Hazards

  • Concept: For predictable hazards (like moving platforms, swinging pendulums, or rotating firebars), both the server and client simulate them deterministically based on a shared clock.
  • Implementation: Do not send position updates for predictable hazards over the network. Instead, initialize them with a shared seed, a synchronized match clock, and a deterministic mathematical function (e.g., sine wave). Both client and server will naturally calculate the exact same position for the hazard at any given tick, allowing perfect hit detection without network overhead.

Anti-Patterns

  • Client-Side Hit Detection: Trusting the client to explicitly declare “I hit Player B” without server validation of range, cooldowns, and collision. This is the fastest route to a compromised, hackable game.
  • Rubberbanding and Harsh Snapping: Forcing immediate, un-interpolated corrections on the client when a misprediction occurs. This causes jarring teleportation and frustration.
  • Oversharing State (Bandwidth Bloat): Sending unnecessary transform data for deterministically moving platforms or rotating hazards over the network every tick instead of relying on synchronized mathematical simulation.
  • Delayed Visual Feedback: Waiting for the server’s RPC response before playing the local attack animation, spawning particles, or playing a sound effect. This makes the game feel incredibly sluggish and unresponsive.
  • Ignoring Network Latency: Failing to implement rollback or historical hitboxing on the server, meaning players with higher ping can never successfully land an attack on a moving target.

Acceptance Checks

  • Server Arbiter: Clients absolutely cannot artificially alter their score, health, or status; the server is definitively the ultimate arbiter of the unifiedGameState.
  • Zero-Ping Illusion: Actions are predicted locally, providing immediate visual and audio responsiveness (the “zero-ping illusion”).
  • Rigorous Validation: The server explicitly validates all critical events (genie_inject_event) for range, cooldown, and alive-state before broadcasting state changes.
  • Smooth Reconciliation: Discrepancies between the client’s prediction and the server’s authoritative state are reconciled gracefully with interpolation, not jarring snaps.
  • Bandwidth Efficiency: Predictable environmental hazards are simulated deterministically on both client and server using a synchronized clock, requiring zero per-tick network updates.

Reference

  • Sister Brawl: Employs strict server-authoritative logic for all combat interactions. When a player presses attack, the client predicts the swing and plays immediate VFX. However, the server ultimately validates the horizontal distance (ATTACK_RANGE), vertical alignment, and ability cooldowns before actually applying damage, decrementing health, and updating the unifiedGameState.

Ask Docs

AI assistant to help answer questions about the documentation. Answers are read-only and cite docs/source.

Hi! How can I help you with the documentation today? Answers are read-only and cite docs/source.

Ctrl+Enter to send