Network Architecture
This documentation describes the client-side network architecture that has been implemented for the R-Type project.
🎯 Overview
The client network architecture follows the same pattern as the rest of the project: abstract interfaces + concrete implementations. This allows easily changing the networking library (Boost.Asio → other) without impacting client code.
┌─────────────────────────────────────────────────────────┐
│ Client Game Loop │
└───────────────────────────┬─────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ INetworkClient (Interface) │
│ • connect/disconnect • send messages │
│ • callbacks • state management │
└───────────────────────────┬─────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ NetworkClientAsio (Implementation) │
│ • UDP Socket (Boost.Asio) • Async I/O │
│ • Network Thread • Message Queue │
└───────────────────────────┬─────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Game Server │
│ (localhost:8080) │
└─────────────────────────────────────────────────────────┘
🏗️ Detailed Architecture
1. Abstract Interface (INetworkClient)
┌─────────────────────────────────────────┐
│ INetworkClient │
├─────────────────────────────────────────┤
│ + connect(address, port) : bool │
│ + disconnect() : void │
│ + isConnected() : bool │
│ + getState() : NetworkState │
│ │
│ + sendLogin(username) : bool │
│ + sendInput(inputMask) : bool │
│ + sendDisconnect() : bool │
│ + sendAck(sequenceId) : bool │
│ + update() : void │
│ │
│ + setOnConnectedCallback(...) │
│ + setOnDisconnectedCallback(...) │
│ + setOnLoginResponseCallback(...) │
│ + setOnEntitySpawnCallback(...) │
│ + setOnEntityPositionCallback(...) │
│ + setOnEntityDeadCallback(...) │
│ + setOnScoreUpdateCallback(...) │
│ + setOnErrorCallback(...) │
└─────────────────────────────────────────┘
Responsibilities:
- 🔌 Connection/disconnection management
- 📤 Sending messages to server
- 📥 Receiving messages from server
- 🔄 Callbacks for network events
- 📊 Connection state management
2. Boost.Asio Implementation (NetworkClientAsio)
┌─────────────────────────────────────────┐
│ NetworkClientAsio │
├─────────────────────────────────────────┤
│ - _ioContext : io_context │
│ - _socket : udp::socket │
│ - _serverEndpoint : udp::endpoint │
│ - _networkThread : thread │
│ - _state : NetworkState │
│ - _sequenceId : uint32_t │
│ - _pendingMessages : queue │
│ - _messageQueueMutex : mutex │
├─────────────────────────────────────────┤
│ + connect(...) : bool │
│ + sendMessage(...) : bool │
│ + processReceivedData(...) : void │
│ + runNetworkThread() : void │
└─────────────────────────────────────────┘
3. Utilities (NetworkMessage)
┌─────────────────────────────────────────┐
│ NetworkMessage │
├─────────────────────────────────────────┤
│ Static Methods: │
│ + createLoginPacket(...) │
│ + createInputPacket(...) │
│ + createDisconnectPacket(...) │
│ + createAckPacket(...) │
│ │
│ + validatePacket(...) │
│ + getPacketSize(...) │
│ + getSequenceId(...) │
│ + getOpCode(...) │
│ │
│ + inputMaskToString(...) │
│ + entityTypeToString(...) │
│ + opCodeToString(...) │
└─────────────────────────────────────────┘
📦 Supported Network Protocol
Client → Server Messages (C2S)
C2S_LOGIN (1):
┌─────────────────┬─────────────────┐
│ Header │ LoginPacket │
├─────────────────┼─────────────────┤
│ opCode: 1 │ username[8] │
│ packetSize: 15 │ │
│ sequenceId: X │ │
└─────────────────┴─────────────────┘
C2S_INPUT (4):
┌─────────────────┬─────────────────┐
│ Header │ InputPacket │
├─────────────────┼─────────────────┤
│ opCode: 4 │ inputMask: byte │
│ packetSize: 8 │ (UP|DOWN|...) │
│ sequenceId: X │ │
└─────────────────┴─────────────────┘
C2S_DISCONNECT (3):
┌─────────────────┐
│ Header Only │
├─────────────────┤
│ opCode: 3 │
│ packetSize: 7 │
│ sequenceId: X │
└─────────────────┘
Server → Client Messages (S2C)
S2C_LOGIN_OK (10):
┌─────────────────┬─────────────────────────┐
│ Header │ LoginResponsePacket │
├─────────────────┼─────────────────────────┤
│ opCode: 10 │ playerId: uint32 │
│ packetSize: 15 │ mapWidth: uint16 │
│ sequenceId: X │ mapHeight: uint16 │
└─────────────────┴─────────────────────────┘
S2C_ENTITY_NEW (11):
┌─────────────────┬─────────────────────────┐
│ Header │ EntitySpawnPacket │
├─────────────────┼─────────────────────────┤
│ opCode: 11 │ entityId: uint32 │
│ packetSize: 20 │ type: byte │
│ sequenceId: X │ x: float, y: float │
└─────────────────┴─────────────────────────┘
S2C_ENTITY_POS (12):
┌─────────────────┬─────────────────────────┐
│ Header │ EntityPositionPacket │
├─────────────────┼─────────────────────────┤
│ opCode: 12 │ entityId: uint32 │
│ packetSize: 19 │ x: float, y: float │
│ sequenceId: X │ │
└─────────────────┴─────────────────────────┘