R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
Replicator.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** Created by samuelBleau on 26/11/2025.
4** File description:
5** Replicator.cpp
6*/
7
8#include "Replicator.hpp"
9#include <chrono>
11#include "Events/UIEvent.hpp"
12
13Replicator::Replicator(EventBus &eventBus, bool isSpectator)
14 : _eventBus(eventBus), _isSpectator(isSpectator), _host(createClientHost()) {}
18
19bool Replicator::connect(const std::string &host, uint16_t port) {
20 if (!_host) {
21 return false;
22 }
23
24 _serverHost = host;
25 _serverPort = port;
26
27 // Create address for server
28 std::unique_ptr<IAddress> address = createAddress(host, port);
29
30 // Connect to server (asynchronous - will get CONNECT event later)
31 _serverPeer = _host->connect(*address, 2, 0);
32
33 if (!_serverPeer) {
34 return false;
35 }
36
37 // Start dedicated network thread
39
40 // Don't set _connected yet - wait for CONNECT event in network thread
41 _connected.store(false);
42 return true;
43}
44
46 // Stop network thread first
48
49 if (_serverPeer) {
50 // Only disconnect if peer is still valid and connected
51 auto state = _serverPeer->getState();
53 state == PeerState::CONNECTING) {
54 // Use disconnectNow() for instant disconnect instead of graceful disconnect()
56 }
57 _serverPeer = nullptr;
58 }
59 _connected.store(false);
60 _authenticated.store(false);
61}
62
64 return _connected.load();
65}
66
68 return _authenticated.load();
69}
70
72 if (_networkThread.joinable()) {
73 return; // Thread already running
74 }
75
76 // Create jthread with lambda that captures 'this' and receives stop_token from jthread
77 // The stop_token is automatically passed by jthread when the lambda signature accepts it
78 _networkThread = std::jthread([this](std::stop_token st) { networkThreadLoop(st); });
79}
80
82 _networkThread.request_stop();
83 // jthread joins automatically in destructor, but we can join explicitly if needed
84 if (_networkThread.joinable()) {
85 _networkThread.join();
86 }
87}
88
89void Replicator::networkThreadLoop(std::stop_token stopToken) {
90 while (!stopToken.stop_requested()) {
91 if (!_host) {
92 std::this_thread::sleep_for(std::chrono::milliseconds(10));
93 continue;
94 }
95
96 // Poll for network events (non-blocking)
97 auto eventOpt = _host->service(0);
98 if (!eventOpt) {
99 std::this_thread::sleep_for(std::chrono::milliseconds(1));
100 continue;
101 }
102
103 auto &event = *eventOpt;
104
105 switch (event.type) {
107 if (event.packet) {
108 auto messageType = NetworkMessages::getMessageType(event.packet->getData());
110 LOG_DEBUG("[Replicator] Network thread received packet type: ",
111 static_cast<int>(messageType));
112 }
113
114 // Update latency from ENet's built-in RTT calculation
115 if (_serverPeer) {
116 uint32_t enetRtt = _serverPeer->getRoundTripTime();
117
118 // Apply exponential moving average for smoother ping display
119 float smoothed = _smoothedLatency.load();
120 if (smoothed == 0.0f) {
121 // First measurement
122 smoothed = static_cast<float>(enetRtt);
123 } else {
124 // Smooth with previous values (30% new, 70% old)
125 smoothed = smoothed * (1.0f - PING_SMOOTHING_FACTOR) +
126 static_cast<float>(enetRtt) * PING_SMOOTHING_FACTOR;
127 }
128 _smoothedLatency.store(smoothed);
129 _latency.store(static_cast<uint32_t>(smoothed));
130 }
131
132 // Decode message type and push to queue
133 std::string messageContent;
134
135 // Parse based on message type
137 // Parse using proper HandshakeResponse wrapper
138 auto payload = NetworkMessages::getPayload(event.packet->getData());
139 try {
140 auto handshakeResp =
142 messageContent = handshakeResp.message;
143
144 if (handshakeResp.accepted) {
145 _authenticated.store(true);
146 _myPlayerId.store(handshakeResp.playerId);
147 LOG_INFO("✓ Authenticated! Player ID: ", handshakeResp.playerId,
148 ", Name: ", handshakeResp.playerName);
149
150 // Publish AUTH_SUCCESS with displayName from server
152 UIEvent(UIEventType::AUTH_SUCCESS, handshakeResp.playerName));
153 } else {
154 _authenticated.store(false);
155 LOG_ERROR("✗ Authentication failed: ", handshakeResp.message);
156 }
157 } catch (const std::exception &e) {
158 LOG_ERROR("Failed to parse HandshakeResponse: ", e.what());
159 messageContent = "Authentication error";
160 _authenticated.store(false);
161 }
162 } else if (messageType == NetworkMessages::MessageType::REGISTER_RESPONSE) {
163 // Parse RegisterResponse
164 auto payload = NetworkMessages::getPayload(event.packet->getData());
165 try {
166 auto registerResp = RType::Messages::S2C::RegisterResponse::deserialize(payload);
167 if (registerResp.success) {
168 LOG_INFO("✓ Registration successful: ", registerResp.message);
169 messageContent = "Registration successful: " + registerResp.message;
171 UIEvent(UIEventType::REGISTER_SUCCESS, registerResp.message));
172 } else {
173 LOG_WARNING("✗ Registration failed: ", registerResp.message);
174 messageContent = "Registration failed: " + registerResp.message;
176 UIEvent(UIEventType::REGISTER_FAILED, registerResp.message));
177 }
178 } catch (const std::exception &e) {
179 LOG_ERROR("Failed to parse RegisterResponse: ", e.what());
180 messageContent = "Registration error";
182 }
183 } else if (messageType == NetworkMessages::MessageType::LOGIN_RESPONSE) {
184 // Parse LoginResponse
185 auto payload = NetworkMessages::getPayload(event.packet->getData());
186 try {
187 auto loginResp = RType::Messages::S2C::LoginResponse::deserialize(payload);
188 if (loginResp.success) {
189 LOG_INFO("✓ Login successful: ", loginResp.message);
190 messageContent = "Login successful: " + loginResp.message;
191 // Store auto-matchmaking preference
192 _autoMatchmakingPreference = loginResp.autoMatchmaking;
193
194 // Publish event to apply the preference to the settings menu
196 loginResp.autoMatchmaking ? "1" : "0"));
197
198 // Publish AUTH_SUCCESS event with username (extract from message or store separately)
199 // For now, we'll extract it from the stored username during sendLoginAccount
200 // This is handled by storing _lastLoginUsername in sendLoginAccount
201 if (!_lastLoginUsername.empty()) {
203 }
204 } else {
205 LOG_WARNING("✗ Login failed: ", loginResp.message);
206 messageContent = "Login failed: " + loginResp.message;
208 }
209 } catch (const std::exception &e) {
210 LOG_ERROR("Failed to parse LoginResponse: ", e.what());
211 messageContent = "Login error";
213 }
214 } else if (messageType == NetworkMessages::MessageType::S2C_GAME_START) {
215 messageContent = "GameStart received";
216 }
217
218 NetworkEvent netEvent(NetworkMessageType::WORLD_STATE, event.packet->getData());
219 netEvent.setMessageContent(messageContent);
220 _incomingMessages.push(std::move(netEvent));
221 }
222 break;
223
225 _connected.store(true);
226 // Publish connection event
227 {
229 _incomingMessages.push(std::move(netEvent));
230 }
231 break;
232
234 _connected.store(false);
235 _authenticated.store(false);
236 _serverPeer = nullptr;
237 // Publish disconnection event
238 {
240 _incomingMessages.push(std::move(netEvent));
241 }
242 break;
243
244 default:
245 break;
246 }
247 }
248}
249
251 using namespace RType::Messages;
252
253 // Process all available messages from network thread
254 while (auto eventOpt = _incomingMessages.tryPop()) {
255 auto &netEvent = *eventOpt;
256
257 // Decode and log specific message types
258 auto messageType = NetworkMessages::getMessageType(netEvent.getData());
259
261 LOG_DEBUG("[Replicator] Popped message type: ", static_cast<int>(messageType));
262 }
263
265 // Decode GameStart message
266 auto payload = NetworkMessages::getPayload(netEvent.getData());
267 try {
268 auto gameStart = S2C::GameStart::deserialize(payload);
269
270 LOG_INFO("✓ GameStart received!");
271 LOG_INFO(" - Your entity ID: ", gameStart.yourEntityId);
272 LOG_INFO(" - Server tick: ", gameStart.initialState.serverTick);
273 LOG_INFO(" - Total entities: ", gameStart.initialState.entities.size());
274
275 // Count entities by type
276 int players = 0, enemies = 0, bullets = 0;
277 for (const auto &entity : gameStart.initialState.entities) {
278 if (entity.type == Shared::EntityType::Player)
279 players++;
280 else if (entity.type == Shared::EntityType::EnemyType1)
281 enemies++;
282 else if (entity.type == Shared::EntityType::PlayerBullet ||
283 entity.type == Shared::EntityType::EnemyBullet)
284 bullets++;
285 }
286
287 LOG_INFO(" - Players: ", players);
288 LOG_INFO(" - Enemies: ", enemies);
289 LOG_INFO(" - Bullets: ", bullets);
290 } catch (const std::exception &e) {
291 LOG_ERROR("Error decoding GameStart: ", e.what());
292 }
293 } else if (messageType == NetworkMessages::MessageType::S2C_ROOM_LIST) {
294 // Decode RoomList message
295 auto payload = NetworkMessages::getPayload(netEvent.getData());
296 try {
297 auto roomList = S2C::RoomList::deserialize(payload);
298
299 LOG_INFO("✓ RoomList received with ", roomList.rooms.size(), " rooms");
300
301 // The NetworkEvent will be published on EventBus with the room list data
302 // GameLoop will handle it and update Rendering
303 } catch (const std::exception &e) {
304 LOG_ERROR("Error decoding RoomList: ", e.what());
305 }
306 } else if (messageType == NetworkMessages::MessageType::S2C_ROOM_STATE) {
307 // Decode RoomState message
308 auto payload = NetworkMessages::getPayload(netEvent.getData());
309 try {
310 auto roomState = S2C::RoomState::deserialize(payload);
311
312 LOG_INFO("✓ RoomState received: ", roomState.roomName, " with ", roomState.players.size(),
313 " players");
314
315 // NetworkEvent will be published on EventBus
316 // GameLoop will handle it and update WaitingRoom
317 } catch (const std::exception &e) {
318 LOG_ERROR("Error decoding RoomState: ", e.what());
319 }
320 } else if (!netEvent.getMessageContent().empty()) {
321 LOG_DEBUG("Received from server: ", netEvent.getMessageContent());
322 }
323
324 // Publish on EventBus for game systems to process
325 _eventBus.publish(netEvent);
326 }
327}
328
329void Replicator::sendPacket(NetworkMessageType type, const std::vector<uint8_t> &data) {
330 (void)type;
331 if (!_serverPeer || !_connected.load()) {
332 return;
333 }
334
335 auto packet = createPacket(data, static_cast<uint32_t>(PacketFlag::RELIABLE));
336 _serverPeer->send(std::move(packet), 0);
337}
338
339bool Replicator::sendConnectRequest(const std::string &playerName, const std::string &username,
340 const std::string &password) {
341 if (!_serverPeer || !_connected.load()) {
342 return false;
343 }
344
345 // Create HandshakeRequest with authentication credentials
346 using namespace ConnectionMessages;
347 HandshakeRequestData handshakeData;
348 handshakeData.clientVersion = "1.0.0";
349 handshakeData.playerName = playerName;
350 handshakeData.username = username;
351 handshakeData.password = password;
352 handshakeData.timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
353 std::chrono::system_clock::now().time_since_epoch())
354 .count();
355
356 std::vector<uint8_t> payload = createHandshakeRequest(handshakeData);
357
358 // Wrap in network protocol
359 auto requestData =
361
362 // Send via ENet
363 auto packet = createPacket(requestData, static_cast<uint32_t>(PacketFlag::RELIABLE));
364 return _serverPeer->send(std::move(packet), 0);
365}
366
367bool Replicator::sendRegisterAccount(const std::string &username, const std::string &password) {
368 if (!_serverPeer || !_connected.load()) {
369 LOG_ERROR("Cannot send RegisterAccount: Not connected");
370 return false;
371 }
372
373 using namespace RType::Messages;
374
375 // Create RegisterAccount message
376 C2S::RegisterAccount request(username, password);
377 auto payload = request.serialize();
378
379 // Wrap in network protocol
380 auto requestData =
382
383 // Send via ENet
384 auto packet = createPacket(requestData, static_cast<uint32_t>(PacketFlag::RELIABLE));
385 return _serverPeer->send(std::move(packet), 0);
386}
387
388bool Replicator::sendLoginAccount(const std::string &username, const std::string &password) {
389 if (!_serverPeer || !_connected.load()) {
390 LOG_ERROR("Cannot send LoginAccount: Not connected");
391 return false;
392 }
393
394 // Store username for AUTH_SUCCESS event when response arrives
395 _lastLoginUsername = username;
396
397 using namespace RType::Messages;
398
399 // Create LoginAccount message
400 C2S::LoginAccount request(username, password);
401 auto payload = request.serialize();
402
403 // Wrap in network protocol
405
406 // Send via ENet
407 auto packet = createPacket(requestData, static_cast<uint32_t>(PacketFlag::RELIABLE));
408 return _serverPeer->send(std::move(packet), 0);
409}
410
412 if (!_serverPeer || !_connected.load()) {
413 return false;
414 }
415
416 using namespace RType::Messages;
417
418 // Create ListRooms message
419 C2S::ListRooms request;
420 auto payload = request.serialize();
421
422 // Wrap in network protocol
424
425 // Send via ENet
426 auto packet = createPacket(requestData, static_cast<uint32_t>(PacketFlag::RELIABLE));
427 return _serverPeer->send(std::move(packet), 0);
428}
429
430bool Replicator::sendCreateRoom(const std::string &roomName, uint32_t maxPlayers, bool isPrivate,
431 float gameSpeedMultiplier) {
432 if (!_serverPeer || !_connected.load()) {
433 return false;
434 }
435
436 using namespace RType::Messages;
437
438 // Create CreateRoom message with game speed multiplier
439 C2S::CreateRoom request(roomName, maxPlayers, isPrivate, gameSpeedMultiplier);
440 auto payload = request.serialize();
441
442 // Wrap in network protocol
444
445 // Send via ENet
446 auto packet = createPacket(requestData, static_cast<uint32_t>(PacketFlag::RELIABLE));
447 return _serverPeer->send(std::move(packet), 0);
448}
449
450bool Replicator::sendJoinRoom(const std::string &roomId) {
451 if (!_serverPeer || !_connected.load()) {
452 LOG_ERROR("Cannot send JoinRoom: Not connected");
453 return false;
454 }
455
456 LOG_INFO("Sending JoinRoom request for room: ", roomId);
457
458 using namespace RType::Messages;
459
460 // Create JoinRoom message
461 C2S::JoinRoom request(roomId);
462 auto payload = request.serialize();
463
464 // Wrap in network protocol
466
467 // Send via ENet
468 auto packet = createPacket(requestData, static_cast<uint32_t>(PacketFlag::RELIABLE));
469 return _serverPeer->send(std::move(packet), 0);
470}
471
473 if (!_serverPeer || !_connected.load()) {
474 LOG_ERROR("Cannot send AutoMatchmaking: Not connected");
475 return false;
476 }
477
478 LOG_INFO("Sending AutoMatchmaking request");
479
480 using namespace RType::Messages;
481
482 // Create AutoMatchmaking message with enabled=true
483 C2S::AutoMatchmaking request(true);
484 auto payload = request.serialize();
485
486 // Wrap in network protocol
487 auto requestData =
489
490 // Send via ENet
491 auto packet = createPacket(requestData, static_cast<uint32_t>(PacketFlag::RELIABLE));
492 return _serverPeer->send(std::move(packet), 0);
493}
494
496 if (!_serverPeer || !_connected.load()) {
497 LOG_ERROR("Cannot update auto-matchmaking preference: Not connected");
498 return false;
499 }
500
501 LOG_INFO("Updating auto-matchmaking preference: ", enabled ? "ON" : "OFF",
502 " (preference only, NOT triggering matchmaking)");
503
504 using namespace RType::Messages;
505
506 // Create AutoMatchmaking message with the preference
507 C2S::AutoMatchmaking request(enabled);
508 auto payload = request.serialize();
509
510 // Wrap in network protocol - using UPDATE_AUTO_MM_PREF to only update preference
511 auto requestData =
513
514 // Send via ENet
515 auto packet = createPacket(requestData, static_cast<uint32_t>(PacketFlag::RELIABLE));
516 return _serverPeer->send(std::move(packet), 0);
517}
518
520 if (!_serverPeer || !_connected.load()) {
521 LOG_ERROR("Cannot send StartGame: Not connected");
522 return false;
523 }
524
525 LOG_INFO("Sending StartGame request");
526
527 using namespace RType::Messages;
528
529 // Create StartGame message
530 C2S::StartGame request;
531 auto payload = request.serialize();
532
533 // Wrap in network protocol
535
536 // Send via ENet
537 auto packet = createPacket(requestData, static_cast<uint32_t>(PacketFlag::RELIABLE));
538 return _serverPeer->send(std::move(packet), 0);
539}
540
541uint32_t Replicator::getLatency() const {
542 return _latency.load();
543}
544
546 return _packetLoss;
547}
548
550 return _isSpectator;
551}
552
554 LOG_INFO("[Replicator] Requesting room list from server");
555 return sendListRooms();
556}
557
559 if (!_serverPeer || !_connected.load()) {
560 return false;
561 }
562
563 using namespace RType::Messages;
564
565 LOG_INFO("[Replicator] Leaving current room");
566
567 // Create LeaveRoom message
568 C2S::LeaveRoom request;
569 auto payload = request.serialize();
570
571 // Wrap in network protocol
573
574 // Send via ENet
575 auto packet = createPacket(requestData, static_cast<uint32_t>(PacketFlag::RELIABLE));
576 return _serverPeer->send(std::move(packet), 0);
577}
578
579bool Replicator::sendChatMessage(const std::string &message) {
580 if (!_serverPeer || !_connected.load()) {
581 LOG_ERROR("[Replicator] Cannot send chat message: Not connected");
582 return false;
583 }
584
585 using namespace RType::Messages;
586
587 LOG_INFO("[Replicator] Sending chat message: '", message, "'");
588
589 // Create ChatMessage
590 C2S::C2SChatMessage chatMsg(message);
591 auto payload = chatMsg.serialize();
592
593 LOG_DEBUG("[Replicator] Chat message serialized, payload size: ", payload.size());
594
595 // Wrap in network protocol
596 auto requestData =
598
599 LOG_DEBUG("[Replicator] Network packet created, total size: ", requestData.size());
600
601 // Send via ENet
602 auto packet = createPacket(requestData, static_cast<uint32_t>(PacketFlag::RELIABLE));
603 bool sent = _serverPeer->send(std::move(packet), 0);
604
605 LOG_INFO("[Replicator] Chat message sent: ", (sent ? "SUCCESS" : "FAILED"));
606
607 return sent;
608}
609
611 (void)event;
612 // TODO: Implement input event handling
613}
614
615void Replicator::processIncomingPacket(const std::vector<uint8_t> &packet) {
616 (void)packet;
617 // This method is now handled by networkThreadLoop
618 // Kept for backwards compatibility if needed
619}
@ RECEIVE
A packet was received.
@ CONNECT
A peer has connected.
@ DISCONNECT
A peer has disconnected.
@ RELIABLE
Packet must be received by the target peer and resent if dropped.
@ CONNECTION_SUCCEEDED
Connection has succeeded.
@ CONNECTING
Connection to peer is being established.
@ CONNECTED
Peer is connected.
#define LOG_INFO(...)
Definition Logger.hpp:181
#define LOG_DEBUG(...)
Definition Logger.hpp:180
#define LOG_ERROR(...)
Definition Logger.hpp:183
#define LOG_WARNING(...)
Definition Logger.hpp:182
std::unique_ptr< IPacket > createPacket(const std::vector< uint8_t > &data, uint32_t flags)
Create a network packet with the given data and flags.
std::unique_ptr< IAddress > createAddress(const std::string &host, uint16_t port)
Create a network address.
std::unique_ptr< IHost > createClientHost(size_t channelLimit, uint32_t incomingBandwidth, uint32_t outgoingBandwidth)
Create a host for client-side networking.
@ APPLY_AUTO_MATCHMAKING_PREF
Type-safe event publication/subscription system.
Definition EventBus.hpp:44
void publish(const T &event)
Publish an event to all subscribers.
Definition EventBus.hpp:116
virtual PeerState getState() const =0
Get the current state of this peer.
virtual bool send(std::unique_ptr< IPacket > packet, uint8_t channelID=0)=0
Send a packet to this peer.
virtual void disconnectNow(uint32_t data=0)=0
Force an immediate disconnect from this peer.
virtual uint32_t getRoundTripTime() const =0
Get the round-trip time (ping) to this peer.
Event representing a player input action.
Event representing a network message.
void setMessageContent(const std::string &content)
Set decoded message content.
std::vector< uint8_t > serialize() const
Chat message sent from client to server.
std::vector< uint8_t > serialize() const
Serialize to byte vector.
std::vector< uint8_t > serialize() const
std::vector< uint8_t > serialize() const
Definition JoinRoom.hpp:24
std::vector< uint8_t > serialize() const
Definition LeaveRoom.hpp:19
Request list of available rooms.
Definition ListRooms.hpp:20
std::vector< uint8_t > serialize() const
Definition ListRooms.hpp:24
Request to login with existing account.
std::vector< uint8_t > serialize() const
Serialize to Cap'n Proto binary format.
Request to register a new user account.
std::vector< uint8_t > serialize() const
Serialize to Cap'n Proto binary format.
static HandshakeResponse deserialize(const std::vector< uint8_t > &data)
static LoginResponse deserialize(const std::vector< uint8_t > &data)
Deserialize from Cap'n Proto binary format.
static RegisterResponse deserialize(const std::vector< uint8_t > &data)
Deserialize from Cap'n Proto binary format.
bool isConnected() const
Check if connected to server.
bool _isSpectator
uint16_t _serverPort
bool sendStartGame()
Send start game request to server.
bool sendLoginAccount(const std::string &username, const std::string &password)
Send login request to server.
bool sendListRooms()
Send list rooms request to server.
bool sendAutoMatchmaking()
Send auto-matchmaking request to server.
bool connect(const std::string &host, uint16_t port)
Connect to the game server.
void startNetworkThread()
Start the dedicated network thread.
void processMessages()
Process incoming network messages.
std::unique_ptr< IHost > _host
ThreadSafeQueue< NetworkEvent > _incomingMessages
Queue for messages from network thread.
void disconnect()
Disconnect from the server.
std::atomic< bool > _autoMatchmakingPreference
void networkThreadLoop(std::stop_token stopToken)
Network thread main loop.
Replicator(EventBus &eventBus, bool isSpectator=false)
Constructor with EventBus reference.
EventBus & _eventBus
uint32_t getPacketLoss() const
Get packet loss rate as percentage.
void onInputEvent(const InputEvent &event)
Handle an incoming packet from the network.
void processIncomingPacket(const std::vector< uint8_t > &packet)
bool sendRequestRoomList()
Request the list of available rooms from server.
std::jthread _networkThread
Dedicated network thread.
bool isSpectator() const
Check if in spectator mode.
void sendPacket(NetworkMessageType type, const std::vector< uint8_t > &data)
Send a packet to the server.
static constexpr float PING_SMOOTHING_FACTOR
bool sendRegisterAccount(const std::string &username, const std::string &password)
Send register account request to server.
uint32_t _packetLoss
std::atomic< uint32_t > _myPlayerId
bool sendLeaveRoom()
Send request to leave current room.
bool updateAutoMatchmakingPreference(bool enabled)
Update auto-matchmaking preference on server.
uint32_t getLatency() const
Get current latency in milliseconds.
~Replicator()
Destructor.
std::atomic< float > _smoothedLatency
IPeer * _serverPeer
bool sendCreateRoom(const std::string &roomName, uint32_t maxPlayers, bool isPrivate, float gameSpeedMultiplier=1.0f)
Send create room request to server.
std::string _lastLoginUsername
void stopNetworkThread()
Stop the dedicated network thread.
std::string _serverHost
std::atomic< bool > _authenticated
bool isAuthenticated() const
Check if authenticated with server.
bool sendConnectRequest(const std::string &playerName, const std::string &username, const std::string &password)
Send connect request to server with player name.
bool sendJoinRoom(const std::string &roomId)
Send join room request to server.
std::atomic< bool > _connected
bool sendChatMessage(const std::string &message)
Send chat message to server.
std::atomic< uint32_t > _latency
void push(T item)
Push an item to the queue.
std::optional< T > tryPop()
Try to pop an item without blocking.
NetworkMessageType
Types of network messages exchanged between client and server.
@ WORLD_STATE
Authoritative world state from server.
@ CONNECT
Client connection request.
@ DISCONNECT
Client disconnection notification.
Helper functions for connection protocol messages.
MessageType getMessageType(const std::vector< uint8_t > &packet)
Get message type from packet.
std::vector< uint8_t > createMessage(MessageType type, const std::vector< uint8_t > &payload)
Create a message with type and payload.
std::vector< uint8_t > getPayload(const std::vector< uint8_t > &packet)
Get payload from packet (without header)
All game messages for R-Type network protocol.
Definition Server.hpp:30
Request from host to start the game in their room.
Definition StartGame.hpp:20
std::vector< uint8_t > serialize() const
Definition StartGame.hpp:23