Skip to main content

Overview

Minecraft Community Edition supports both split-screen local multiplayer and network multiplayer. The game uses a client-server architecture where one instance acts as the authoritative server and others connect as clients.

Multiplayer Architecture

Client-Server Model

// Server side
class MinecraftServer {
    ServerConnection* connection;       // Network listener
    PlayerList* players;                // Connected players
    ServerLevelArray levels;            // Authoritative worlds
};

// Client side
class MultiPlayerLevel : public Level {
    vector<ClientConnection*> connections;  // Server connections
    MultiPlayerChunkCache* chunkCache;      // Received chunks
};
Location: MinecraftServer.cpp:69 and MultiPlayerLevel.cpp:26

Network Flow

┌─────────────┐      Packets      ┌─────────────┐
│   Client    │ ─────────────────> │   Server    │
│             │                    │             │
│ LocalPlayer │ <───────────────── │ServerPlayer │
└─────────────┘   Updates/Sync    └─────────────┘
      │                                  │
      ▼                                  ▼
 MultiPlayerLevel               ServerLevel (x3)

Split-Screen Local Multiplayer

Local Player Management

Up to 4 players can play on the same console:
class Minecraft {
    shared_ptr<MultiplayerLocalPlayer> localplayers[XUSER_MAX_COUNT];
    GameMode* localgameModes[XUSER_MAX_COUNT];
    ItemInHandRenderer* localitemInHandRenderers[XUSER_MAX_COUNT];
    int localPlayerIdx;  // Currently active player
};
Location: Minecraft.h (referenced in Minecraft.cpp:861)

Adding Local Players

bool Minecraft::addLocalPlayer(int idx) {
    // Create temporary player for connecting screen
    localplayers[idx] = make_shared<MultiplayerLocalPlayer>(
        this, level, user, NULL
    );
    localgameModes[idx] = NULL;
    
    // Add to network session
    g_NetworkManager.AddLocalPlayerByUserIndex(idx);
    
    updatePlayerViewportAssignments();
    
    return true;
}
Location: Minecraft.cpp:989

Viewport Assignment

Players are assigned screen regions based on count: 1 Player: Full screen
VIEWPORT_TYPE_FULLSCREEN
2 Players: Split horizontally or vertically
if (splitScreenVertical) {
    VIEWPORT_TYPE_SPLIT_LEFT
    VIEWPORT_TYPE_SPLIT_RIGHT
} else {
    VIEWPORT_TYPE_SPLIT_TOP
    VIEWPORT_TYPE_SPLIT_BOTTOM
}
3-4 Players: Quadrants
VIEWPORT_TYPE_QUADRANT_TOP_LEFT
VIEWPORT_TYPE_QUADRANT_TOP_RIGHT
VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT
VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT
Location: Minecraft.cpp:883-986

Network Multiplayer

Connection Establishment

class ServerConnection {
public:
    void listen();  // Accept incoming connections
    void tick();    // Process network packets
};

class ClientConnection {
public:
    void connect(string host, int port);
    void sendPacket(shared_ptr<Packet> packet);
    void tick();  // Handle received packets
};
Default Port: 25565 (Minecraft standard) Location: Referenced in MinecraftServer.cpp:168

Player Connection Lifecycle

1. Connection Request
ClientConnection* connection = new ClientConnection();
connection->connect(serverIp, port);
2. Login Handshake
// Client sends login packet
LoginPacket* login = new LoginPacket();
login->username = playerName;
login->protocolVersion = VERSION;
connection->send(login);
3. World Sync
// Server sends level data
LevelDataPacket* levelData = new LevelDataPacket();
levelData->seed = level->getSeed();
levelData->gameType = level->getGameType();
connection->send(levelData);

// Server sends spawn chunks
for (ChunkPos pos : spawnChunks) {
    connection->send(new ChunkDataPacket(pos));
}
4. Player Spawn
// Server spawns player
ServerPlayer* player = new ServerPlayer(server, level, username);
player->moveTo(spawnX, spawnY, spawnZ);
level->addEntity(player);

// Broadcast to other players
players->broadcastAll(
    new AddPlayerPacket(player)
);
5. Disconnect
void ClientConnection::disconnect(DisconnectReason reason) {
    sendAndDisconnect(
        new DisconnectPacket(reason)
    );
}

Player Synchronization

Server Player

The authoritative representation:
class ServerPlayer : public Player {
    ClientConnection* connection;
    ChunkPos lastChunk;
    
public:
    void tick() override;
    void sendInventory();
    void broadcastMove();
};
Updates Sent:
  • Position and rotation
  • Health and hunger
  • Inventory changes
  • Experience
  • Effects (potion, fire, drowning)

Client Player

Client-side prediction and rendering:
class MultiplayerLocalPlayer : public LocalPlayer {
    ClientConnection* connection;
    
public:
    void tick() override;
    void sendInput();
    void applyServerUpdate();
};
Updates Sent:
  • Input (movement, jumping, crouching)
  • Block breaking/placing
  • Item usage
  • Inventory actions

World Synchronization

Chunk Packets

Chunks are sent as the player moves:
class ChunkDataPacket : public Packet {
public:
    int x, z;                    // Chunk coordinates
    bool groundUp;               // Full chunk
    int availableSections;       // Section bitmask
    byte* data;                  // Compressed chunk data
    int dataLength;
};
Compression:
  • Chunks are zlib compressed
  • Reduces network bandwidth by ~80%
  • Client decompresses on receive
Location: Referenced in MultiPlayerLevel.cpp:876

Chunk Unloading

void MultiPlayerLevel::setChunkVisible(int x, int z, bool visible) {
    if (visible) {
        chunkCache->create(x, z);
    } else {
        chunkCache->drop(x, z);
        setTilesDirty(x*16, 0, z*16, 
                      x*16+15, maxBuildHeight, z*16+15);
    }
}
Location: MultiPlayerLevel.cpp:389

Block Updates

Single Block:
class TileUpdatePacket : public Packet {
public:
    int x, y, z;
    int tile;
    int data;
};
Multiple Blocks:
class ChunkTilesUpdatePacket : public Packet {
public:
    int xChunk, zChunk;
    vector<short> offsets;   // Relative positions
    vector<byte> tiles;      // Block IDs
    vector<byte> data;       // Block data
};

Block Change Tracking

Client changes are reverted pending server confirmation:
struct ResetInfo {
    int x, y, z;
    int ticks;      // Time until reset
    int tile;       // Original block
    int data;
};

vector<ResetInfo> updatesToReset;

if (--r.ticks == 0) {
    Level::setTileAndDataNoUpdate(r.x, r.y, r.z, r.tile, r.data);
}
Location: MultiPlayerLevel.cpp:16-24 and MultiPlayerLevel.cpp:127-150

Entity Synchronization

Entity Spawning

class AddEntityPacket : public Packet {
public:
    int entityId;
    eINSTANCEOF type;
    int x, y, z;           // Position (* 32 for fixed point)
    byte yRot, xRot;       // Rotation
};
Location: Referenced in tracking system

Movement Packets

Small Movement (relative):
class MoveEntityPacket : public Packet {
public:
    int entityId;
    byte dx, dy, dz;       // Delta * 32
};
Large Movement (absolute):
class TeleportEntityPacket : public Packet {
public:
    int entityId;
    int x, y, z;           // Absolute * 32
    byte yRot, xRot;
};

Entity Data Updates

class SetEntityDataPacket : public Packet {
public:
    int entityId;
    map<int, DataItem*> data;  // Changed values only
};
Sent when:
  • Entity on fire state changes
  • Crouching/sprinting changes
  • Drowning bubbles change
  • Name tag changes (if supported)

Entity Removal

class RemoveEntityPacket : public Packet {
public:
    int entityId;
};

Connection Management

Client Connection

class ClientConnection {
    SavedDataStorage* savedDataStorage;  // Shared with server
    bool connected;
    int timeoutCounter;
    
public:
    void tick();
    void send(shared_ptr<Packet> packet);
    void handlePacket(shared_ptr<Packet> packet);
};
Timeout Detection:
if (++timeoutCounter > 20*30) {  // 30 seconds
    disconnect(DisconnectPacket::eDisconnect_Timeout);
}
Location: Referenced in MultiPlayerLevel.cpp:44

Server Connection

class ServerConnection {
    MinecraftServer* server;
    vector<ClientConnection*> connections;
    
public:
    void tick();  // Tick all connections
    void broadcast(shared_ptr<Packet> packet);
};
Location: MinecraftServer.cpp:168

Pending Connections

Local players connecting to local server:
ClientConnection* m_pendingLocalConnections[XUSER_MAX_COUNT];
bool m_connectionFailed[XUSER_MAX_COUNT];

void Minecraft::addPendingLocalConnection(int idx, 
                                          ClientConnection* conn) {
    m_pendingLocalConnections[idx] = conn;
}
Location: Minecraft.cpp:1049

Packet Processing

Server-Side Handling

void ServerConnection::tick() {
    for (ClientConnection* conn : connections) {
        while (Packet* packet = conn->receive()) {
            switch(packet->getType()) {
                case PLAYER_INPUT:
                    handlePlayerInput(conn, packet);
                    break;
                case PLAYER_ACTION:
                    handlePlayerAction(conn, packet);
                    break;
                case USE_ITEM:
                    handleUseItem(conn, packet);
                    break;
            }
        }
    }
}

Client-Side Handling

void ClientConnection::tick() {
    while (Packet* packet = receive()) {
        switch(packet->getType()) {
            case CHUNK_DATA:
                handleChunkData(packet);
                break;
            case ADD_ENTITY:
                handleAddEntity(packet);
                break;
            case MOVE_ENTITY:
                handleMoveEntity(packet);
                break;
            case TILE_UPDATE:
                handleTileUpdate(packet);
                break;
        }
    }
}
Location: Connection tick methods in MultiPlayerLevel.cpp:118

Disconnect Handling

Disconnect Reasons

enum DisconnectReason {
    eDisconnect_None,
    eDisconnect_Quitting,
    eDisconnect_Timeout,
    eDisconnect_Kicked,
    eDisconnect_SignOut,
    eDisconnect_NetworkError
};

Graceful Disconnect

void MultiPlayerLevel::disconnect(bool sendDisconnect) {
    if (sendDisconnect) {
        for (ClientConnection* conn : connections) {
            conn->sendAndDisconnect(
                new DisconnectPacket(eDisconnect_Quitting)
            );
        }
    } else {
        for (ClientConnection* conn : connections) {
            conn->close();
        }
    }
}
Location: MultiPlayerLevel.cpp:606

Removing Players

void Minecraft::removeLocalPlayerIdx(int idx) {
    if (localgameModes[idx] != NULL) {
        MultiPlayerLevel* mpLevel = 
            (MultiPlayerLevel*)getLevel(localplayers[idx]->dimension);
        
        mpLevel->removeClientConnection(
            localplayers[idx]->connection, true
        );
        
        g_NetworkManager.RemoveLocalPlayerByUserIndex(idx);
        getLevel(localplayers[idx]->dimension)->removeEntity(
            localplayers[idx]
        );
        
        delete localgameModes[idx];
        localgameModes[idx] = NULL;
    }
    
    localplayers[idx] = nullptr;
    updatePlayerViewportAssignments();
}
Location: Minecraft.cpp:1163

Network Optimization

Slow Queue System

Reduces packet spam for less critical updates:
static int s_slowQueuePlayerIndex = 0;
static int s_slowQueueLastTime = 0;
static bool s_slowQueuePacketSent = false;

void MinecraftServer::cycleSlowQueueIndex() {
    s_slowQueuePlayerIndex = 
        (s_slowQueuePlayerIndex + 1) % players->count();
}
Used For:
  • Entity metadata updates
  • Non-critical inventory syncs
  • Effect particles
Location: MinecraftServer.cpp:63-65

Packet Batching

Multiple small packets combined:
ChunkTilesUpdatePacket* packet = new ChunkTilesUpdatePacket();
for (TileUpdate update : pendingUpdates) {
    packet->add(update.x, update.y, update.z, 
                update.tile, update.data);
}
broadcast(packet);

Update Frequency

Different update rates for different data:
  • Position: Every tick (20 TPS)
  • Health: On change only
  • Inventory: On change only
  • Time: Every 20 ticks (1 second)
  • Chunk visibility: On enter/exit range
Location: MinecraftServer.cpp:1477

Key Takeaways

  1. Client-Server Model: One authoritative server, multiple clients
  2. Split-Screen Support: Up to 4 local players with separate viewports
  3. Chunk Streaming: Dynamic loading as players explore
  4. Entity Tracking: Only entities in range are synchronized
  5. Prediction: Client predicts movement, server corrects
  6. Compression: Chunk data compressed for bandwidth efficiency

Build docs developers (and LLMs) love