← All Workshops

MudEngine Part 6: Multiplayer

Step 8 / 18

Server Game State

The server needs to keep track of all connected players. We use global static state behind #[cfg(feature = "server")] — it is only compiled into the server binary, never into the WASM client.

The state has two parts:

  1. PLAYERS — a Mutex<HashMap<String, PlayerInfo>> mapping player IDs to their info
  2. BROADCAST — a tokio::sync::broadcast::Sender that fans out every message to all connected clients

This state lives in src/game/server.rs, along with the WebSocket endpoint we add in the next step. The file starts with the imports it needs (the #[get] macro, the WebSocket types, and the shared message types and EXITS), then defines the server-only state module:

mud-engine/src/game/server.rs
use dioxus::prelude::*;
use dioxus_fullstack::{Websocket, WebSocketOptions};

use super::messages::{ClientMessage, PlayerInfo, ServerMessage};
use super::room_data::EXITS;

// ── Server-only state ──

#[cfg(feature = "server")]
mod srv {
    use std::collections::HashMap;
    use std::sync::{LazyLock, Mutex};
    use tokio::sync::broadcast;

    use super::*;

    /// All connected players, keyed by their unique ID.
    pub static PLAYERS: LazyLock<Mutex<HashMap<String, PlayerInfo>>> =
        LazyLock::new(|| Mutex::new(HashMap::new()));

    /// Broadcast channel — every connected WebSocket subscribes.
    /// When a player moves, anyone sends, everyone receives.
    pub static BROADCAST: LazyLock<broadcast::Sender<ServerMessage>> =
        LazyLock::new(|| {
            let (tx, _) = broadcast::channel(64);
            tx
        });
}
💡 Why LazyLock and not a plain static?

Mutex::new() is not a const function, so we cannot write static PLAYERS: Mutex<...> = Mutex::new(HashMap::new()). LazyLock initializes the value on first access — the closure runs once and the result lives for the program's lifetime.

broadcast::channel(64) creates a sender/receiver pair with a buffer of 64 messages. If a client is too slow to keep up, they miss messages (the receiver gets a Lagged error). For our 9-room MUD this is more than enough.

🗺️ Grid reference
   Col 0      Col 1      Col 2
┌──────────┬──────────┬──────────┐
│ Forest   │ Hilltop  │ Abandoned│  Row 0
│ Path (0) │    (1)   │ Tower(2) │
├──────────┼──────────┼──────────┤
│ Dark     │ Town     │ Temple   │  Row 1
│ Forest(3)│ Square(4)│ Crt. (5) │
├──────────┼──────────┼──────────┤
│ River-   │ Old      │ Grave-   │  Row 2
│ bank (6) │ Bridge(7)│ yard (8) │
└──────────┴──────────┴──────────┘

Room index = row × 3 + col. All new players start at room 4 (Town Square, the center). The exit table on the server enforces that movement only works along actual connections — no walking through walls.

Step 8 / 18