Multiplayer Demo

Server-authoritative multiplayer with QUIC transport and avatar state synchronization.

The multiplayer demo shows Aether's networking layer in action. A server-authoritative architecture synchronizes avatar state between connected clients over QUIC, demonstrating the transport, tick loop, and state reconciliation subsystems.

What It Demonstrates

  • QUIC transport via aether-network for reliable, low-latency communication between server and clients.
  • Server-authoritative tick loop running at a configurable rate (default 60 Hz) that validates and broadcasts world state.
  • Avatar state synchronization including head position, head rotation, and left/right hand transforms -- the core data needed for social VR presence.
  • Client-side prediction where the client sends input at 50ms intervals and receives authoritative world snapshots from the server.
  • Graceful shutdown via Ctrl+C signal handling on the server.

How to Run

The demo consists of two binaries: a server and a client. Start the server first, then connect one or more clients.

Terminal 1 -- Start the server:

cargo run -p multiplayer-demo --bin mp-server

Terminal 2 -- Connect a client:

cargo run -p multiplayer-demo --bin mp-client

To connect to a remote server, pass the address as an argument or set the environment variable:

cargo run -p multiplayer-demo --bin mp-client -- 192.168.1.10:7777
# or
AETHER_SERVER_ADDR=192.168.1.10:7777 cargo run -p multiplayer-demo --bin mp-client

Server Configuration

The server reads configuration from environment variables:

VariableDefaultDescription
AETHER_SERVER_PORT7777Port the QUIC server binds to
AETHER_TICK_RATE60Simulation tick rate in Hz
AETHER_MAX_PLAYERS20Maximum concurrent player connections

Architecture Overview

Client                         Server
  |                              |
  |--- AvatarState (input) ----->|
  |                              |  validate & apply
  |                              |  step tick loop
  |<--- WorldState (snapshot) ---|
  |                              |

The server (server_main.rs) creates a MultiplayerServer from a MultiplayerConfig loaded from environment variables. It listens on the configured port and runs the tick loop until a shutdown signal is received.

The client (client_main.rs) creates a MultiplayerClient, connects to the server, and enters a loop that:

  1. Sleeps for 50ms (the input send interval).
  2. Computes a simulated avatar position walking in a circle.
  3. Sends an AvatarState containing head and hand transforms.
  4. Every 60 ticks (~3 seconds), logs the received WorldState including the tick number and all connected avatar positions.

Subsystems Showcased

CrateRole in this demo
aether-networkQUIC transport, client/server connection management
aether-multiplayerMultiplayerServer, MultiplayerClient, AvatarState, WorldState

Key Code Walkthrough

The client simulates circular movement by incrementing an angle each tick and computing positions from trigonometry:

let avatar = AvatarState {
    head_position: [angle.cos() * radius, 1.7, angle.sin() * radius],
    head_rotation: [0.0, (angle / 2.0).sin(), 0.0, (angle / 2.0).cos()],
    left_hand_position: [angle.cos() * radius - 0.3, 1.0, angle.sin() * radius - 0.3],
    right_hand_position: [angle.cos() * radius + 0.3, 1.0, angle.sin() * radius - 0.3],
    // ...
};

This shows the minimal data contract between client and server: position and rotation for head and both hands, matching the tracked points of a VR headset.

Source Location

All source files live under examples/multiplayer-demo/src/:

  • server_main.rs -- server entry point, QUIC listener, tick loop
  • client_main.rs -- client entry point, connection, input send loop