22 : m_ioContext(std::make_unique<asio::io_context>()),
23 m_socket(std::make_unique<asio::ip::udp::socket>(*m_ioContext)), m_serverPort(0),
25 m_running(false), m_packetHandler(std::make_unique<
rnp::HandlerPacket>()), m_lastPingNonce(0), m_latency(0),
26 m_pingInterval(std::chrono::seconds(5)), m_connectionTimeout(std::chrono::seconds(30)), m_currentLobbyId(0),
27 m_eventBus(
utl::EventBus::getInstance()), m_componentId(
utl::NETWORK_CLIENT)
68 auto endpoints = resolver.resolve(host, std::to_string(port));
89 catch (
const std::exception &e)
111 std::this_thread::sleep_for(std::chrono::milliseconds(100));
235 [
this](
const std::vector<rnp::EventRecord> &events,
const rnp::PacketContext &context)
267 [
this](std::error_code ec, std::size_t bytesReceived)
271 handleReceive(bytesReceived);
276 utl::Logger::log(
"AsioClient: Receive error - " + ec.message(),
277 utl::LogLevel::WARNING);
286 constexpr std::size_t PACKET_HEADER_SIZE = 7;
287 if (bytesReceived < PACKET_HEADER_SIZE)
289 utl::Logger::log(
"AsioClient: Received packet too small (need " + std::to_string(PACKET_HEADER_SIZE) +
290 " bytes, got " + std::to_string(bytesReceived) +
")",
301 context.
receiveTime = std::chrono::steady_clock::now();
307 if (data.size() >= PACKET_HEADER_SIZE)
319 std::to_string(
static_cast<int>(result)),
332 m_ioContext->run_for(std::chrono::milliseconds(100));
339 catch (
const std::exception &e)
341 utl::Logger::log(
"AsioClient: Network thread exception - " + std::string(e.what()),
343 std::this_thread::sleep_for(std::chrono::milliseconds(100));
358 utl::Logger::log(
"AsioClient: Sending " + std::to_string(data.size()) +
" bytes to " +
367 utl::Logger::log(
"AsioClient: Successfully sent " + std::to_string(bytesSent) +
" bytes",
370 catch (
const std::exception &e)
397 std::string reasonStr =
"Unknown";
402 reasonStr =
"Client request";
405 reasonStr =
"Timeout";
408 reasonStr =
"Protocol error";
411 reasonStr =
"Server shutdown";
414 reasonStr =
"Server full";
417 reasonStr =
"Banned";
420 reasonStr =
"Unspecified";
436 auto now = std::chrono::steady_clock::now();
437 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now -
m_lastPingTime);
438 m_latency =
static_cast<std::uint32_t
>(duration.count());
457 std::string errorStr =
"Unknown error";
462 errorStr =
"Invalid payload";
465 errorStr =
"Unauthorized session";
468 errorStr =
"Rate limited";
471 errorStr =
"Internal server error";
474 errorStr =
"Unknown error";
488 ", Entities: " + std::to_string(packet.
entityCount),
503 header.sessionId = 0;
508 std::memset(
connect.playerName.data(), 0,
connect.playerName.size());
563 ping.sendTimeMs =
static_cast<std::uint32_t
>(
564 std::chrono::duration_cast<std::chrono::milliseconds>(
m_lastPingTime.time_since_epoch()).count());
587 pong.sendTimeMs =
static_cast<std::uint32_t
>(
588 std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch())
616 auto now = std::chrono::steady_clock::now();
642 static auto lastConnectAttempt = std::chrono::steady_clock::now();
643 if (now - lastConnectAttempt > std::chrono::seconds(2))
646 lastConnectAttempt = now;
653 static std::random_device rd;
654 static std::mt19937 gen(rd());
655 static std::uniform_int_distribution<std::uint32_t> dis(1, UINT32_MAX);
662 for (
const auto &e : events)
665 std::to_string(
static_cast<std::uint32_t
>(e.type)),
677 std::string playerName = serializer.
readString(32);
678 std::string serverIP = serializer.
readString(15);
679 unsigned short serverPortStr = std::stoi(serializer.
readString(5).c_str());
680 utl::Logger::log(
"AsioClient: Received REQUEST_CONNECT event - Player: " + playerName +
681 ", Server: " + serverIP +
":" + std::to_string(serverPortStr),
686 connect(serverIP, serverPortStr);
706 header.
length =
static_cast<std::uint16_t
>(e.data.size());
711 packetSerializer.
writeBytes(e.data.data(), e.data.size());
725 if (e.data.size() ==
sizeof(std::uint32_t))
728 std::uint32_t lobbyId;
729 std::memcpy(&lobbyId, e.data.data(),
sizeof(std::uint32_t));
738 std::uint8_t maxPlayers = lobbyCreate.
maxPlayers;
739 std::uint8_t gameMode = lobbyCreate.
gameMode;
740 utl::Logger::log(
"AsioClient: Received LOBBY_CREATE event - Name: " + lobbyName +
741 ", Max Players: " + std::to_string(maxPlayers) +
742 ", Game Mode: " + std::to_string(gameMode),
751 std::uint32_t lobbyId = serializer.
readUInt32();
769 utl::Logger::log(
"AsioClient: Unhandled event type: " + std::to_string(
static_cast<int>(e.type)),
780 utl::Logger::log(
"AsioClient: Received " + std::to_string(events.size()) +
" entity events from server",
805 std::vector<std::uint8_t> packet;
809 std::cout <<
"Sending lobby list request packet of size " << serializer.
getSize() << std::endl;
831 ", Max Players: " + std::to_string(lobbyPacket.
maxPlayers) +
832 ", Game Mode: " + std::to_string(lobbyPacket.
gameMode),
835 std::vector<std::uint8_t> data;
842 utl::Logger::log(
"AsioClient: Lobby create header - Type: " + std::to_string(header.
type) +
", Length: " +
843 std::to_string(header.
length) +
", Session ID: " + std::to_string(header.
sessionId),
848 std::cout <<
"Sending lobby create packet of size " << dataSerializer.
getSize() << std::endl;
876 std::vector<std::uint8_t> packet;
905 std::vector<std::uint8_t> packet;
922 utl::Logger::log(
"AsioClient: Requesting to start game for lobby " + std::to_string(lobbyId),
933 std::vector<std::uint8_t> packet;
987 "AsioClient: Received lobby create response - success: " + std::string(packet.
success ?
"true" :
"false") +
988 ", lobbyId: " + std::to_string(packet.
lobbyId),
1009 "AsioClient: Received lobby join response - success: " + std::string(packet.
success ?
"true" :
"false") +
1010 ", lobbyId: " + std::to_string(packet.
lobbyId),
1058 gameStartEvent.
data =
1059 std::vector<std::uint8_t>(
reinterpret_cast<const std::uint8_t *
>(&packet),
Asio-based UDP client implementation for R-Type multiplayer game networking.
Event structures and types for event-driven communication.
Network packet handler for RNP protocol.
This file contains the Logger class.
This file contains the network protocol.
Network packet serializer for RNP protocol.
void sendDisconnect()
Send DISCONNECT packet to terminate connection.
std::chrono::milliseconds m_connectionTimeout
Timeout duration (15000ms)
std::string m_serverHost
Server hostname or IP address.
void setupPacketHandlers()
Setup packet handlers for all RNP packet types.
rnp::HandlerResult handleLobbyJoinResponse(const rnp::PacketLobbyJoinResponse &packet, const rnp::PacketContext &context)
Handle LOBBY_JOIN_RESPONSE packet.
void joinLobby(std::uint32_t lobbyId)
Join an existing lobby.
void setPlayerName(const std::string &playerName) override
Set player name for connection.
void sendPacketImmediate(const std::vector< std::uint8_t > &data)
Send packet immediately via UDP socket.
rnp::HandlerResult handlePing(const rnp::PacketPingPong &packet, const rnp::PacketContext &context)
Handle PING packet.
std::uint16_t m_serverTickRate
Server tick rate in Hz.
void setOnLobbyJoined(std::function< void(std::uint32_t, bool, rnp::ErrorCode, const rnp::LobbyInfo *)> callback)
Set callback for lobby join response.
std::unique_ptr< asio::ip::udp::socket > m_socket
UDP socket for network communication.
std::uint32_t getSessionId() const override
Get assigned session ID.
std::uint32_t m_clientCaps
Client capability flags.
std::array< std::uint8_t, 1024 > m_recvBuffer
Buffer for receiving UDP packets.
std::uint32_t m_sessionId
Assigned session ID from server.
rnp::HandlerResult handleDisconnect(const rnp::PacketDisconnect &packet, const rnp::PacketContext &context)
Handle DISCONNECT packet.
void networkThreadLoop() const
Main network thread loop.
std::uint32_t m_componentId
Component ID for event bus.
void disconnect() override
Disconnect from server.
std::atomic< bool > m_running
Network thread running state (atomic)
std::function< void(std::uint32_t, bool, rnp::ErrorCode, const rnp::LobbyInfo *)> m_onLobbyJoined
Lobby joined callback.
static rnp::HandlerResult handleError(const rnp::PacketError &packet, const rnp::PacketContext &context)
Handle ERROR packet.
rnp::HandlerResult handlePong(const rnp::PacketPingPong &packet, const rnp::PacketContext &context)
Handle PONG packet.
void sendPing()
Send PING packet for latency measurement.
rnp::HandlerResult handleLobbyUpdate(const rnp::PacketLobbyUpdate &packet, const rnp::PacketContext &context) const
Handle LOBBY_UPDATE packet.
std::function< void(std::uint32_t, bool, rnp::ErrorCode)> m_onLobbyCreated
Lobby created callback.
rnp::HandlerResult handleWorldState(const rnp::PacketWorldState &packet, const rnp::PacketContext &context) const
Handle WORLD_STATE packet.
rnp::HandlerResult handleConnectAccept(const rnp::PacketConnectAccept &packet, const rnp::PacketContext &context)
Handle CONNECT_ACCEPT packet.
void processSendQueue()
Process outgoing packet queue.
bool isConnected() const override
Check if client is connected to server.
rnp::HandlerResult handleLobbyCreateResponse(const rnp::PacketLobbyCreateResponse &packet, const rnp::PacketContext &context)
Handle LOBBY_CREATE_RESPONSE packet.
std::uint32_t m_latency
Round-trip time in milliseconds.
asio::ip::udp::endpoint m_senderEndpoint
Endpoint of last packet sender.
std::uint32_t m_currentLobbyId
Current lobby ID, 0 if not in lobby.
void setOnGameStart(std::function< void(std::uint32_t, std::uint32_t)> callback)
Set callback for game start notification.
std::uint16_t getServerTickRate() const override
Get server tick rate.
~AsioClient() override
Destructor.
std::atomic< ConnectionState > m_connectionState
Current connection state (atomic)
void update() override
Update client state (called each frame)
void setOnLobbyCreated(std::function< void(std::uint32_t, bool, rnp::ErrorCode)> callback)
Set callback for lobby creation response.
void sendPong(std::uint32_t nonce)
Send PONG response to server PING.
void sendToServer(const std::vector< std::uint8_t > &data, bool reliable=false) override
Send custom packet to server.
void leaveLobby()
Leave current lobby.
ConnectionState getConnectionState() const override
Get current connection state.
std::chrono::steady_clock::time_point m_lastServerResponse
Timestamp of last server packet.
void setOnLobbyListReceived(std::function< void(const std::vector< rnp::LobbyInfo > &)> callback)
Set callback for lobby list received.
void requestStartGame(std::uint32_t lobbyId)
Request to start the game (host only)
void sendConnect()
Send CONNECT packet to initiate connection.
std::function< void(std::uint32_t, std::uint32_t)> m_onGameStart
Game start callback.
rnp::HandlerResult handleLobbyListResponse(const rnp::PacketLobbyListResponse &packet, const rnp::PacketContext &context) const
Handle LOBBY_LIST_RESPONSE packet.
rnp::HandlerResult handleGameStart(const rnp::PacketGameStart &packet, const rnp::PacketContext &context) const
Handle GAME_START packet.
static std::uint32_t generatePingNonce()
Generate random ping nonce.
void requestLobbyList()
Request list of available lobbies from server.
std::chrono::steady_clock::time_point m_lastPingTime
Timestamp of last PING.
std::uint16_t m_serverPort
Server port number.
std::function< void(const rnp::LobbyInfo &)> m_onLobbyUpdated
Lobby updated callback.
void processBusEvent()
Process events from event bus.
std::unique_ptr< std::thread > m_networkThread
Dedicated network thread.
std::unique_ptr< rnp::HandlerPacket > m_packetHandler
RNP packet handler instance.
std::uint32_t m_lastPingNonce
Nonce of last PING sent.
void setOnLobbyUpdated(std::function< void(const rnp::LobbyInfo &)> callback)
Set callback for lobby updates.
std::string m_playerName
Player display name.
std::function< void(const std::vector< rnp::LobbyInfo > &)> m_onLobbyListReceived
Lobby list callback.
void connect(const std::string &host, std::uint16_t port) override
Connect to game server.
asio::ip::udp::endpoint m_serverEndpoint
Resolved server endpoint.
rnp::HandlerResult handleEntityEvent(const std::vector< rnp::EventRecord > &events, const rnp::PacketContext &context) const
Handle ENTITY_EVENT packet.
std::chrono::milliseconds m_pingInterval
Interval between pings (5000ms)
std::queue< QueuedPacket > m_sendQueue
Queue of packets waiting to be sent.
void handleReceive(std::size_t bytesReceived)
Handle received packet data.
ConnectionStats m_stats
Connection statistics.
void updateConnectionManagement()
Update connection management state.
std::unique_ptr< asio::io_context > m_ioContext
ASIO I/O context for async operations.
void startReceive()
Start asynchronous receive operation.
utl::EventBus & m_eventBus
Event bus reference.
std::mutex m_sendQueueMutex
Mutex for send queue access.
std::uint32_t getLatency() const override
Get current latency to server.
void setClientCapabilities(std::uint32_t caps) override
Set client capability flags.
void createLobby(rnp::PacketLobbyCreate lobbyCreate)
Create a new lobby on server.
void onLobbyListResponse(LobbyListResponseHandler handler)
Register LOBBY_LIST_RESPONSE packet handler.
void onPing(PingHandler handler)
Register PING packet handler.
void onPong(PongHandler handler)
Register PONG packet handler.
HandlerResult processPacket(const std::vector< std::uint8_t > &data, const PacketContext &context)
Process a received packet.
void onWorldState(WorldStateHandler handler)
Register WORLD_STATE packet handler.
void onConnectAccept(ConnectAcceptHandler handler)
Register CONNECT_ACCEPT packet handler.
void onError(ErrorHandler handler)
Register ERROR packet handler.
void onLobbyUpdate(LobbyUpdateHandler handler)
Register LOBBY_UPDATE packet handler.
void onEntityEvent(EntityEventHandler handler)
Register ENTITY_EVENT packet handler.
void onLobbyJoinResponse(LobbyJoinResponseHandler handler)
Register LOBBY_JOIN_RESPONSE packet handler.
void onLobbyCreateResponse(LobbyCreateResponseHandler handler)
Register LOBBY_CREATE_RESPONSE packet handler.
void onGameStart(GameStartHandler handler)
Register GAME_START packet handler.
void onDisconnect(DisconnectHandler handler)
Register DISCONNECT packet handler.
Binary serializer for RNP protocol packets.
void serializePingPong(const PacketPingPong &packet)
Serialize PING/PONG packet.
void writeBytes(const void *data, std::size_t size)
Write raw bytes.
PacketHeader deserializeHeader()
Deserialize packet header.
void serializeStartGameRequest(const PacketStartGameRequest &packet)
Serialize START_GAME_REQUEST packet.
void serializeHeader(const PacketHeader &header)
Serialize packet header.
PacketLobbyCreate deserializeLobbyCreate()
Deserialize LOBBY_CREATE packet.
void serializeLobbyCreate(const PacketLobbyCreate &packet)
Serialize LOBBY_CREATE packet.
void serializeConnect(const PacketConnect &packet)
Serialize CONNECT packet.
void serializeDisconnect(const PacketDisconnect &packet)
Serialize DISCONNECT packet.
std::uint32_t readUInt32()
Read a 32-bit integer (network byte order)
std::string readString(std::size_t maxLength)
Read a string with length prefix.
const std::vector< std::uint8_t > & getData() const
Get the serialized data.
std::size_t getSize() const
Get the current size of serialized data.
void serializeLobbyJoin(const PacketLobbyJoin &packet)
Serialize LOBBY_JOIN packet.
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)
ConnectionState
Connection state enumeration.
HandlerResult
Packet processing result.
DisconnectReason
Disconnect reason codes.
static constexpr std::uint32_t RENDERING_ENGINE
std::uint32_t packetsSent
Total number of packets sent.
std::uint32_t packetsReceived
Total number of packets received.
std::chrono::steady_clock::time_point connectionTime
Timestamp when connection was established.
std::uint32_t bytesTransferred
Total bytes transferred (sent + received)
Represents a packet queued for asynchronous transmission to server.
std::vector< std::uint8_t > data
Serialized packet data.
Lobby information structure.
CONNECT_ACCEPT packet payload.
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)
WORLD_STATE packet payload.
std::uint16_t entityCount