23 : m_ioContext(std::make_unique<asio::io_context>()),
24 m_socket(std::make_unique<asio::ip::udp::socket>(*m_ioContext)), m_port(0), m_tickRate(60), m_serverCaps(0),
25 m_running(false), m_started(false), m_nextSessionId(1), m_nextLobbyId(1),
26 m_packetHandler(std::make_unique<
rnp::HandlerPacket>()), m_pingInterval(std::chrono::seconds(5)),
27 m_clientTimeout(std::chrono::seconds(30)), m_componentId(
utl::NETWORK_SERVER),
28 m_eventBus(
utl::EventBus::getInstance())
77 asio::ip::udp::endpoint endpoint(asio::ip::make_address(
m_host),
m_port);
84 m_socket->set_option(asio::ip::udp::socket::reuse_address(
true));
102 catch (
const std::exception &e)
124 for (
auto &[sessionId, client] :
m_clients)
126 if (client.isConnected)
132 header.sessionId = sessionId;
154 auto joinStart = std::chrono::steady_clock::now();
159 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - joinStart).count() <
169 std::this_thread::sleep_for(std::chrono::milliseconds(10));
189 catch (
const std::exception &e)
227 if (it ==
m_clients.end() || !it->second.isConnected)
235 m_sendQueue.emplace(data, it->second.endpoint, reliable);
243 for (
const auto &client :
m_clients | std::views::values)
245 if (client.isConnected)
247 m_sendQueue.emplace(data, client.endpoint, reliable);
254 std::uint32_t lobbyId = 0;
272 std::vector<std::uint8_t> packet;
283 if (it->second.currentLobbyId != 0)
285 lobbyId = it->second.currentLobbyId;
312 return std::ranges::count_if(
m_clients, [](
const auto &pair) {
return pair.second.isConnected; });
318 std::vector<std::uint32_t> sessions;
319 for (
const auto &[sessionId, client] :
m_clients)
321 if (client.isConnected)
323 sessions.push_back(sessionId);
363 [
this](
const std::vector<rnp::EventRecord> &events,
const rnp::PacketContext &context)
394 utl::Logger::log(
"AsioServer: Cannot start receive - server not running or socket closed",
401 [
this](
const std::error_code ec,
const std::size_t bytesReceived)
405 utl::Logger::log(
"AsioServer: Received " + std::to_string(bytesReceived) +
" bytes from " +
406 m_senderEndpoint.address().to_string() +
":" +
407 std::to_string(m_senderEndpoint.port()),
408 utl::LogLevel::INFO);
409 handleReceive(bytesReceived);
412 else if (
m_running.load() && ec != asio::error::operation_aborted)
414 utl::Logger::log(
"AsioServer: Receive error - " + ec.message(), utl::LogLevel::WARNING);
415 std::this_thread::sleep_for(std::chrono::milliseconds(100));
420 utl::Logger::log(
"AsioServer: Server stopped or operation aborted, ending receive loop",
421 utl::LogLevel::INFO);
428 utl::Logger::log(
"AsioServer: Processing received packet of " + std::to_string(bytesReceived) +
" bytes",
432 constexpr std::size_t PACKET_HEADER_SIZE = 7;
433 if (bytesReceived < PACKET_HEADER_SIZE)
435 utl::Logger::log(
"AsioServer: Received packet too small (need " + std::to_string(PACKET_HEADER_SIZE) +
436 " bytes, got " + std::to_string(bytesReceived) +
")",
443 context.
receiveTime = std::chrono::steady_clock::now();
452 if (data.size() >= PACKET_HEADER_SIZE)
458 ", Session ID: " + std::to_string(header.
sessionId),
468 std::to_string(
static_cast<int>(result)),
492 if (handlersRun == 0)
495 std::this_thread::sleep_for(std::chrono::milliseconds(1));
498 catch (
const std::exception &e)
504 std::this_thread::sleep_for(std::chrono::milliseconds(100));
514 std::random_device rd;
515 std::mt19937 gen(rd());
516 std::uniform_int_distribution<std::uint32_t> dis(1, UINT32_MAX);
518 std::uint32_t sessionId = 0;
519 while (sessionId == 0 ||
m_clients.contains(sessionId))
521 sessionId = dis(gen);
529 return endpoint.address().to_string() +
":" + std::to_string(endpoint.port());
533 const asio::ip::udp::endpoint &destination)
535 utl::Logger::log(
"AsioServer: Sending " + std::to_string(data.size()) +
" bytes to " +
536 destination.address().to_string() +
":" + std::to_string(destination.port()),
550 size_t bytesSent =
m_socket->send_to(asio::buffer(data), destination);
551 utl::Logger::log(
"AsioServer: Successfully sent " + std::to_string(bytesSent) +
" bytes",
554 catch (
const std::exception &e)
558 utl::Logger::log(
"AsioServer: Failed to send packet - " + std::string(e.what()),
572 const size_t currentClientCount =
573 std::ranges::count_if(
m_clients, [](
const auto &pair) {
return pair.second.isConnected; });
721 auto now = std::chrono::steady_clock::now();
722 auto pingTime = std::chrono::milliseconds(packet.
sendTimeMs);
723 auto currentTime = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
724 it->second.latency =
static_cast<std::uint32_t
>((currentTime - pingTime).count());
731 void AsioServer::sendPong(std::uint32_t nonce,
const asio::ip::udp::endpoint &destination, std::uint32_t sessionId)
737 header.sessionId = sessionId;
741 pong.sendTimeMs =
static_cast<std::uint32_t
>(
742 std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch())
761 header.sessionId = sessionId;
780 const asio::ip::udp::endpoint &destination, std::uint32_t sessionId)
785 header.length =
static_cast<std::uint16_t
>(
sizeof(
rnp::PacketError) + description.length());
786 header.sessionId = sessionId;
789 error.
errorCode =
static_cast<std::uint16_t
>(errorCode);
790 error.msgLen =
static_cast<std::uint16_t
>(description.length());
791 error.description = description;
801 const auto now = std::chrono::steady_clock::now();
807 for (
auto &[sessionId, client] :
m_clients)
809 if (client.isConnected)
816 header.sessionId = sessionId;
819 ping.
nonce = ++client.lastPingSent;
820 ping.sendTimeMs =
static_cast<std::uint32_t
>(
821 std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count());
834 std::vector<std::uint32_t> timedOutClients;
837 for (
const auto &[sessionId, client] :
m_clients)
841 timedOutClients.push_back(sessionId);
847 for (std::uint32_t sessionId : timedOutClients)
870 for (
const auto &event : events)
901 if (event.
data.size() >=
sizeof(uint32_t))
903 uint32_t sessionId = 0;
904 std::memcpy(&sessionId, event.
data.data(),
sizeof(uint32_t));
906 std::vector<uint8_t> messageData(event.
data.begin() +
sizeof(uint32_t), event.
data.end());
940 utl::Logger::log(
"AsioServer: Received " + std::to_string(events.size()) +
" entity events from session " +
945 for (
const auto &eventRecord : events)
950 std::to_string(eventRecord.data.size()),
955 event.data = eventRecord.data;
987 if (clientIt ==
m_clients.end() || !clientIt->second.isConnected)
1004 std::uint32_t lobbyId = 0;
1005 bool success =
false;
1011 if (clientIt ==
m_clients.end() || !clientIt->second.isConnected)
1018 std::to_string(clientIt->second.currentLobbyId),
1021 if (clientIt->second.currentLobbyId != 0)
1028 std::string lobbyName;
1049 clientIt->second.currentLobbyId = lobbyId;
1060 if (success && lobbyId > 0)
1072 " for lobby " + std::to_string(packet.
lobbyId),
1075 bool joinSuccess =
false;
1083 if (clientIt ==
m_clients.end() || !clientIt->second.isConnected)
1092 if (clientIt->second.currentLobbyId != 0)
1095 " already in lobby " + std::to_string(clientIt->second.currentLobbyId),
1103 utl::Logger::log(
"AsioServer: joinLobby returned status: " + std::to_string(
static_cast<int>(joinStatus)),
1108 clientIt->second.currentLobbyId = packet.
lobbyId;
1110 " successfully joined lobby " + std::to_string(packet.
lobbyId),
1117 std::to_string(packet.
lobbyId) +
1118 " - status: " + std::to_string(
static_cast<int>(joinStatus)),
1136 std::to_string(
static_cast<int>(lobbyInfo.
currentPlayers)) +
"/" +
1137 std::to_string(
static_cast<int>(lobbyInfo.
maxPlayers)),
1159 std::uint32_t lobbyId = 0;
1165 if (clientIt ==
m_clients.end() || !clientIt->second.isConnected)
1172 if (clientIt->second.currentLobbyId == 0)
1178 lobbyId = clientIt->second.currentLobbyId;
1179 clientIt->second.currentLobbyId = 0;
1204 for (
const auto &lobby :
m_lobbies | std::views::values)
1208 std::to_string(
static_cast<int>(lobbyInfo.
currentPlayers)) +
"/" +
1209 std::to_string(
static_cast<int>(lobbyInfo.
maxPlayers)) +
" players",
1211 response.
lobbies.push_back(lobbyInfo);
1216 std::vector<std::uint8_t> packet;
1228 " lobbies, packet size: " + std::to_string(packetSerializer.
getData().size()),
1235 std::uint8_t gameMode)
1240 Lobby lobby(lobbyId, name, hostSession, maxPlayers, gameMode);
1245 utl::Logger::log(
"AsioServer: Created lobby " + std::to_string(lobbyId) +
" '" + name +
"' hosted by " +
1246 std::to_string(hostSession),
1261 utl::Logger::log(
"AsioServer: joinLobby - Lobby " + std::to_string(lobbyId) +
" not found",
1266 Lobby &lobby = lobbyIt->second;
1268 "AsioServer: joinLobby - Lobby found, current players: " + std::to_string(lobby.
playerSessions.size()) +
1269 "/" + std::to_string(lobby.
maxPlayers) +
", status: " + std::to_string(
static_cast<int>(lobby.
status)),
1291 utl::Logger::log(
"AsioServer: Player " + std::to_string(sessionId) +
" joined lobby " +
1292 std::to_string(lobbyId) +
" (now " + std::to_string(lobby.
playerSessions.size()) +
"/" +
1293 std::to_string(
static_cast<int>(lobby.
maxPlayers)) +
" players)",
1302 for (
auto &[lobbyId, lobby] :
m_lobbies)
1304 if (
auto playerIt = std::ranges::find(lobby.playerSessions, sessionId);
1305 playerIt != lobby.playerSessions.end())
1307 lobby.playerSessions.erase(playerIt);
1309 utl::Logger::log(
"AsioServer: Player " + std::to_string(sessionId) +
" left lobby " +
1310 std::to_string(lobbyId),
1316 auto clientIt =
m_clients.find(sessionId);
1319 clientIt->second.currentLobbyId = 0;
1321 std::to_string(sessionId),
1327 if (lobby.hostSessionId == sessionId)
1329 if (!lobby.playerSessions.empty())
1331 lobby.hostSessionId = lobby.playerSessions[0];
1332 utl::Logger::log(
"AsioServer: New host for lobby " + std::to_string(lobbyId) +
" is " +
1333 std::to_string(lobby.hostSessionId),
1339 utl::Logger::log(
"AsioServer: Lobby " + std::to_string(lobbyId) +
" is now empty",
1355 std::vector<std::uint32_t> lobbyIds;
1358 for (
const auto &[lobbyId, lobby] :
m_lobbies)
1360 lobbyIds.push_back(lobbyId);
1365 for (std::uint32_t lobbyId : lobbyIds)
1375 for (
auto &[sessionId, client] :
m_clients)
1377 if (client.currentLobbyId != 0)
1379 utl::Logger::log(
"AsioServer: Clearing lobby association for session " + std::to_string(sessionId),
1381 client.currentLobbyId = 0;
1393 std::vector<std::uint32_t> playerSessions;
1402 playerSessions = lobbyIt->second.playerSessions;
1408 header.
length =
static_cast<std::uint16_t
>(gameOverData.size());
1413 std::vector<std::uint8_t> packetData = serializer.
getData();
1414 packetData.insert(packetData.end(), gameOverData.begin(), gameOverData.end());
1418 for (std::uint32_t sessionId : playerSessions)
1420 auto clientIt =
m_clients.find(sessionId);
1421 if (clientIt !=
m_clients.end() && clientIt->second.isConnected)
1423 utl::Logger::log(
"AsioServer: Sending GAME_OVER to session " + std::to_string(sessionId),
1443 std::vector<std::uint8_t> data;
1448 const std::vector<std::uint8_t> &lobbyUpdateData = serializer.
getData();
1451 for (std::uint32_t sessionId : lobbyIt->second.playerSessions)
1455 header.
length =
static_cast<std::uint16_t
>(lobbyUpdateData.size());
1458 std::vector<std::uint8_t> playerPacket;
1465 auto clientIt =
m_clients.find(sessionId);
1472 utl::Logger::log(
"AsioServer: Broadcasted lobby update for lobby " + std::to_string(lobbyId),
1487 std::size_t nameLen = std::min(lobby.
lobbyName.size(),
static_cast<std::size_t
>(31));
1493 for (std::size_t i = 0; i < lobby.
playerSessions.size() && i < 8; ++i)
1498 std::size_t playerNameLen = std::min(clientIt->second.playerName.size(),
static_cast<std::size_t
>(31));
1499 std::memcpy(info.
playerNames[i].data(), clientIt->second.playerName.c_str(), playerNameLen);
1512 response.
success = success ? 1 : 0;
1513 response.
errorCode =
static_cast<std::uint16_t
>(errorCode);
1520 std::vector<std::uint8_t> packet;
1527 utl::Logger::log(
"AsioServer: Sent lobby create response to session " + std::to_string(sessionId) +
1528 " (success: " + (success ?
"true" :
"false") +
")",
1537 response.
success = success ? 1 : 0;
1538 response.
errorCode =
static_cast<std::uint16_t
>(errorCode);
1539 if (success && lobbyInfo)
1549 std::vector<std::uint8_t> packet;
1556 utl::Logger::log(
"AsioServer: Sent lobby join response to session " + std::to_string(sessionId) +
1557 " (success: " + (success ?
"true" :
"false") +
")",
1567 if (it->second.playerSessions.empty())
1569 utl::Logger::log(
"AsioServer: Cleaning up empty lobby " + std::to_string(it->first),
1584 " for lobby " + std::to_string(packet.
lobbyId),
1591 if (clientIt ==
m_clients.end() || !clientIt->second.isConnected)
1597 if (clientIt->second.currentLobbyId != packet.
lobbyId)
1615 if (lobbyIt->second.hostSessionId != context.
sessionId)
1629 std::vector<std::uint32_t> playerSessions;
1635 playerSessions = lobbyIt->second.playerSessions;
1636 utl::Logger::log(
"AsioServer: Player sessions in lobby: " + std::to_string(playerSessions.size()),
1643 std::vector<std::uint8_t> sessionsData;
1644 sessionsData.resize(
sizeof(std::uint32_t) * playerSessions.size());
1645 for (
size_t i = 0; i < playerSessions.size(); ++i)
1647 std::memcpy(sessionsData.data() + i *
sizeof(std::uint32_t), &playerSessions[i],
sizeof(std::uint32_t));
1649 startEvent.
data = sessionsData;
1652 utl::Logger::log(
"AsioServer: Sent SERVER_START to RTypeServer with " + std::to_string(playerSessions.size()) +
1675 std::vector<std::uint8_t> data;
1679 const std::vector<std::uint8_t> &gameStartData = serializer.
getData();
1682 for (std::uint32_t sessionId : lobbyIt->second.playerSessions)
1686 header.
length =
static_cast<std::uint16_t
>(gameStartData.size());
1689 std::vector<std::uint8_t> playerPacket;
1696 auto clientIt =
m_clients.find(sessionId);
1703 utl::Logger::log(
"AsioServer: Broadcasted game start for lobby " + std::to_string(lobbyId),
Asio-based UDP server implementation for R-Type multiplayer game networking.
Thread-safe event bus implementation for inter-component communication.
Event structures and types for event-driven communication.
This file contains the Logger class.
This file contains the network protocol.
Security utilities and input validation.
void onPing(PingHandler handler)
Register PING packet handler.
void onPong(PongHandler handler)
Register PONG packet handler.
void onLobbyJoin(LobbyJoinHandler handler)
Register LOBBY_JOIN packet handler.
void onLobbyLeave(LobbyLeaveHandler handler)
Register LOBBY_LEAVE packet handler.
HandlerResult processPacket(const std::vector< std::uint8_t > &data, const PacketContext &context)
Process a received packet.
void onLobbyListRequest(LobbyListRequestHandler handler)
Register LOBBY_LIST_REQUEST packet handler.
void onConnect(ConnectHandler handler)
Register CONNECT packet handler.
void onStartGameRequest(StartGameRequestHandler handler)
Register START_GAME_REQUEST packet handler.
void onLobbyCreate(LobbyCreateHandler handler)
Register LOBBY_CREATE packet handler.
void onEntityEvent(EntityEventHandler handler)
Register ENTITY_EVENT packet handler.
void onDisconnect(DisconnectHandler handler)
Register DISCONNECT packet handler.
void clearSession(std::uint32_t sessionId)
Clear rate limiting data for a session.
Binary serializer for RNP protocol packets.
void serializePingPong(const PacketPingPong &packet)
Serialize PING/PONG packet.
void serializeLobbyCreateResponse(const PacketLobbyCreateResponse &packet)
Serialize LOBBY_CREATE_RESPONSE packet.
PacketHeader deserializeHeader()
Deserialize packet header.
void serializeLobbyListResponse(const PacketLobbyListResponse &packet)
Serialize LOBBY_LIST_RESPONSE packet.
void serializeHeader(const PacketHeader &header)
Serialize packet header.
void serializeConnectAccept(const PacketConnectAccept &packet)
Serialize CONNECT_ACCEPT packet.
void serializeGameStart(const PacketGameStart &packet)
Serialize GAME_START packet.
void serializeDisconnect(const PacketDisconnect &packet)
Serialize DISCONNECT packet.
void serializeLobbyJoinResponse(const PacketLobbyJoinResponse &packet)
Serialize LOBBY_JOIN_RESPONSE packet.
const std::vector< std::uint8_t > & getData() const
Get the serialized data.
void serializeError(const PacketError &packet)
Serialize ERROR packet.
void serializeLobbyUpdate(const PacketLobbyUpdate &packet)
Serialize LOBBY_UPDATE packet.
std::uint16_t m_tickRate
Server tick rate in Hz.
rnp::HandlerResult handlePing(const rnp::PacketPingPong &packet, const rnp::PacketContext &context)
Handle PING packet.
std::unique_ptr< asio::io_context > m_ioContext
ASIO I/O context for async operations.
rnp::HandlerResult handleLobbyJoin(const rnp::PacketLobbyJoin &packet, const rnp::PacketContext &context)
Handle LOBBY_JOIN packet.
void init(const std::string &host, std::uint16_t port) override
void disconnectClient(std::uint32_t sessionId) override
void setupPacketHandlers()
Initialize packet handlers.
void sendToClient(std::uint32_t sessionId, const std::vector< std::uint8_t > &data, bool reliable=false) override
rnp::HandlerResult handleEntityEvent(const std::vector< rnp::EventRecord > &events, const rnp::PacketContext &context) const
Handle entity event packet (including player inputs)
void cleanupEmptyLobbies()
Clean up empty lobbies.
std::uint32_t m_nextLobbyId
Next available lobby ID.
rnp::HandlerResult handleConnect(const rnp::PacketConnect &packet, const rnp::PacketContext &context)
Handle CONNECT packet.
~AsioServer() override
Destructor.
void sendConnectAccept(std::uint32_t sessionId, const asio::ip::udp::endpoint &destination)
Send CONNECT_ACCEPT response.
std::string m_host
Server bind address (e.g., "0.0.0.0")
void handleReceive(std::size_t bytesReceived)
Handle received packet.
rnp::LobbyInfo lobbyToLobbyInfo(const Lobby &lobby)
Convert Lobby to LobbyInfo for network transmission.
void setServerCapabilities(std::uint32_t caps) override
void setTickRate(std::uint16_t tickRate) override
std::string endpointToString(const asio::ip::udp::endpoint &endpoint)
Get endpoint string representation.
std::vector< std::uint32_t > getConnectedSessions() const override
rnp::HandlerResult handlePong(const rnp::PacketPingPong &packet, const rnp::PacketContext &context)
Handle PONG packet.
bool isRunning() const override
std::unique_ptr< std::thread > m_networkThread
Dedicated network thread.
std::atomic< bool > m_started
Server started state.
void startReceive()
Start receiving packets asynchronously.
void handleGameOverEvent(const utl::Event &event)
Handle GAME_OVER event from game server.
asio::ip::udp::endpoint m_senderEndpoint
Endpoint of last packet sender.
void sendError(rnp::ErrorCode errorCode, const std::string &description, const asio::ip::udp::endpoint &destination, std::uint32_t sessionId)
Send ERROR packet.
LobbyStatus joinLobby(std::uint32_t lobbyId, std::uint32_t sessionId)
Join player to lobby.
void sendPong(std::uint32_t nonce, const asio::ip::udp::endpoint &destination, std::uint32_t sessionId)
Send PONG response.
std::unordered_map< std::uint32_t, ClientSession > m_clients
Map of session ID to client session.
void networkThreadLoop() const
Network thread main loop.
std::chrono::milliseconds m_clientTimeout
Client timeout duration (15000ms)
std::uint16_t m_port
Server listening port (default: 4567)
std::mutex m_sendQueueMutex
Mutex for send queue access.
std::uint32_t m_serverCaps
Server capability flags.
void sendPacketImmediate(const std::vector< std::uint8_t > &data, const asio::ip::udp::endpoint &destination)
Send packet immediately.
std::uint32_t createLobby(const std::string &lobbyName, std::uint32_t hostSessionId, std::uint8_t maxPlayers, std::uint8_t gameMode)
Create new lobby.
std::mutex m_lobbiesMutex
Mutex for thread-safe lobby access.
void broadcastGameStart(std::uint32_t lobbyId)
Broadcast game start notification to all lobby members.
void sendLobbyCreateResponse(std::uint32_t sessionId, std::uint32_t lobbyId, bool success, rnp::ErrorCode errorCode=rnp::ErrorCode::INTERNAL_ERROR)
Send lobby create response.
std::mutex m_socketMutex
Mutex for socket operations.
void handleBroadcastEvent(const utl::Event &event)
Handle broadcast event from EventBus.
std::mutex m_clientsMutex
Mutex for thread-safe client access.
std::unordered_map< std::uint32_t, Lobby > m_lobbies
Map of lobby ID to lobby data.
std::queue< QueuedPacket > m_sendQueue
Queue of packets waiting to be sent.
rnp::HandlerResult handleLobbyCreate(const rnp::PacketLobbyCreate &packet, const rnp::PacketContext &context)
Handle LOBBY_CREATE packet.
rnp::HandlerResult handleLobbyListRequest(const rnp::PacketContext &context)
Handle LOBBY_LIST_REQUEST packet.
std::atomic< bool > m_running
Server running state (atomic for thread safety)
std::array< std::uint8_t, MAX_LEN_RECV_BUFFER > m_recvBuffer
Buffer for receiving UDP packets.
void sendToAllClients(const std::vector< std::uint8_t > &data, bool reliable=false) override
std::uint32_t m_componentId
Component ID for event bus registration.
void broadcastLobbyUpdate(std::uint32_t lobbyId)
Broadcast lobby update to all lobby members.
void processSendQueue()
Process send queue.
std::unordered_map< std::string, std::uint32_t > m_endpointToSession
Map of endpoint string to session ID.
rnp::HandlerResult handleLobbyLeave(const rnp::PacketContext &context)
Handle LOBBY_LEAVE packet.
void updateClientManagement()
Update client timeouts and send pings.
rnp::HandlerResult handleDisconnect(const rnp::PacketDisconnect &packet, const rnp::PacketContext &context)
Handle DISCONNECT packet.
std::unique_ptr< asio::ip::udp::socket > m_socket
UDP socket for network communication.
std::chrono::milliseconds m_pingInterval
Interval between ping sweeps (5000ms)
void leaveLobby(std::uint32_t sessionId)
Remove player from lobby.
void sendLobbyJoinResponse(std::uint32_t sessionId, std::uint32_t lobbyId, bool success, rnp::ErrorCode errorCode, const rnp::LobbyInfo *lobbyInfo=nullptr)
Send lobby join response.
std::chrono::steady_clock::time_point m_lastPingTime
Timestamp of last ping sweep.
std::size_t getClientCount() const override
rnp::HandlerResult handleStartGameRequest(const rnp::PacketStartGameRequest &packet, const rnp::PacketContext &context)
Handle START_GAME_REQUEST packet.
void broadcastGameOverToLobby(std::uint32_t lobbyId)
Broadcast game start to all players in lobby.
void handleSendToClientEvent(const utl::Event &event)
Handle send to client event from EventBus.
std::unique_ptr< rnp::HandlerPacket > m_packetHandler
RNP packet handler instance.
void sendLobbyList(std::uint32_t sessionId)
Send lobby list to client.
void processEventBusEvents()
Process EventBus events for network operations.
void handleSendEntityEventToClients(const utl::Event &event)
Handle send entity event to clients from EventBus.
utl::EventBus & m_eventBus
std::uint32_t generateSessionId() const
Generate unique session ID.
bool publish(const Event &event)
Publish an event to the bus.
std::vector< Event > consumeForTarget(std::uint32_t targetId, std::uint32_t maxEvents=100)
Consume events targeted to specific component.
void registerComponent(std::uint32_t componentId, const std::string &name)
Register component name for better debugging.
void subscribe(std::uint32_t componentId, EventType type)
Subscribe component to specific event types.
Event structure for inter-component communication.
std::vector< std::uint8_t > data
Serialized event data.
static void log(const std::string &message, const LogLevel &logLevel)
HandlerResult
Packet processing result.
constexpr std::size_t MAX_PAYLOAD
constexpr size_t MAX_CLIENTS
LobbyStatus
Status codes for lobby operations.
@ IN_GAME
Game in progress.
@ NOT_FOUND
Requested lobby does not exist.
@ FULL
Lobby has reached maximum capacity.
@ SUCCESS
Operation completed successfully.
@ ALREADY_IN_LOBBY
Client is already in a lobby.
static constexpr std::uint32_t GAME_LOGIC
static constexpr std::uint32_t NETWORK_SERVER
Lobby information structure.
std::uint32_t hostSessionId
std::array< char, 32 > lobbyName
std::array< std::array< char, 32 >, 8 > playerNames
std::uint8_t currentPlayers
CONNECT_ACCEPT packet payload.
std::array< char, 32 > playerName
Context information for packet processing.
std::chrono::steady_clock::time_point receiveTime
std::string senderAddress
DISCONNECT packet payload.
GAME_START packet payload.
LOBBY_CREATE_RESPONSE packet payload.
LOBBY_CREATE packet payload.
std::array< char, 32 > lobbyName
LOBBY_JOIN_RESPONSE packet payload.
LOBBY_JOIN packet payload.
LOBBY_LIST_RESPONSE packet payload.
std::vector< LobbyInfo > lobbies
LOBBY_UPDATE packet payload.
PING/PONG packet payload.
START_GAME_REQUEST packet payload (client requests to start game)
Represents an active client connection session.
bool isConnected
Connection state flag.
std::chrono::steady_clock::time_point lastSeen
Timestamp of last received packet.
std::uint32_t clientCaps
Client capability flags (reserved)
std::uint32_t sessionId
Unique session identifier assigned by server.
std::string playerName
Player's display name.
asio::ip::udp::endpoint endpoint
Client's network endpoint (IP:port)
Represents a game lobby (room) where players gather before starting a game.
std::uint32_t hostSessionId
Session ID of the lobby host.
rnp::LobbyStatus status
Current lobby status.
std::uint8_t maxPlayers
Maximum number of players allowed (1-8)
std::vector< std::uint32_t > playerSessions
List of player session IDs in this lobby.
std::uint32_t lobbyId
Unique lobby identifier.
std::string lobbyName
Human-readable lobby name.
std::uint8_t gameMode
Game mode identifier.
Represents a packet queued for asynchronous transmission.
asio::ip::udp::endpoint destination
Target endpoint.
std::vector< std::uint8_t > data
Serialized packet data.