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-networkfor 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:
| Variable | Default | Description |
|---|---|---|
AETHER_SERVER_PORT | 7777 | Port the QUIC server binds to |
AETHER_TICK_RATE | 60 | Simulation tick rate in Hz |
AETHER_MAX_PLAYERS | 20 | Maximum 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:
- Sleeps for 50ms (the input send interval).
- Computes a simulated avatar position walking in a circle.
- Sends an
AvatarStatecontaining head and hand transforms. - Every 60 ticks (~3 seconds), logs the received
WorldStateincluding the tick number and all connected avatar positions.
Subsystems Showcased
| Crate | Role in this demo |
|---|---|
aether-network | QUIC transport, client/server connection management |
aether-multiplayer | MultiplayerServer, 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 loopclient_main.rs-- client entry point, connection, input send loop