← All Workshops

MudEngine Part 6: Multiplayer

Step 6 / 18

Shared Message Types

Both the client and the server need the same message types. These enums are what we send over the WebSocket connection.

ClientMessage flows from the player to the server:

  • Move { direction } — the player pressed a movement button

ServerMessage flows from the server to all connected players:

  • State — initial state sent when a player first joins (full player list + their own ID)
  • PlayerJoined — a new player entered the world
  • PlayerMoved — a player changed rooms
  • PlayerLeft — a player disconnected

We also define a PlayerInfo struct that holds a player's ID, name, and current room index.

These types are shared — compiled into both the server and the WASM client — so they live in the game module, not in any UI component. Create src/game/messages.rs with them:

mud-engine/src/game/messages.rs
use serde::{Deserialize, Serialize};

// ── Shared message types ──

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct PlayerInfo {
    pub id: String,
    pub name: String,
    pub room: usize,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ClientMessage {
    Move { direction: String },
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ServerMessage {
    State {
        players: Vec<PlayerInfo>,
        your_id: String,
    },
    PlayerJoined(PlayerInfo),
    PlayerMoved(PlayerInfo),
    PlayerLeft { id: String },
}
🎯 Why derive Clone + PartialEq?
  • Serialize/Deserialize — messages travel over the WebSocket as JSON; serde handles the encoding
  • Clone — messages arrive on the client and need to be stored in signals (like Signal<HashMap<String, PlayerInfo>>)
  • PartialEq — required by Dioxus props, though our game component doesn't use props directly
  • Debug — useful for logging and debugging

The message enums are "tagged" — serde encodes the variant name as a string field, making it easy to inspect with browser dev tools.

Step 6 / 18