12 const asio::ip::address addr = asio::ip::make_address(host);
13 const udp::endpoint ep(addr, port);
15 m_socket.open(ep.protocol());
16 m_socket.set_option(asio::socket_base::reuse_address(
true));
22 m_workGuard = std::make_unique<asio::executor_work_guard<asio::io_context::executor_type>>(
23 asio::make_work_guard(m_ioContext));
27 m_ioThread = std::thread(
34 catch (
const std::exception &e)
36 std::cerr <<
"[AsioServer] IO context exception: " << e.what() <<
"\n";
45 asio::post(m_ioContext,
57 if (m_ioThread.joinable())
67 m_socket.async_receive_from(asio::buffer(m_recvBuffer), m_remoteEndpoint,
68 [
this](
const asio::error_code &ec,
const std::size_t n) { handleReceive(ec, n); });
75 std::vector<uint8_t> data(m_recvBuffer.begin(), m_recvBuffer.begin() + bytesTransferred);
76 processPacket(m_remoteEndpoint, data);
79 else if (error == asio::error::operation_aborted)
85 std::cerr <<
"[AsioServer] Erreur de réception: " << error.message() <<
"\n";
94 std::cerr <<
"[AsioServer] Erreur d'envoi: " << error.message() <<
"\n";
104 std::vector<uint8_t> payload;
105 if (header.
length > 0 && data.size() >= 16 + header.
length)
107 payload.assign(data.begin() + 16, data.begin() + 16 + header.
length);
113 auto it = m_clients.find(sender);
114 if (it != m_clients.end() && it->second.sessionId != header.
sessionId)
124 handleReliablePacket(sender, header);
128 sendAck(sender, header.
sequence, 0);
135 if (payload.size() >= 5)
137 std::uint8_t nameLen = payload[0];
138 if (payload.size() >= 1 + nameLen + 4)
140 std::string playerName(payload.begin() + 1, payload.begin() + 1 + nameLen);
141 std::uint32_t clientCaps = (
static_cast<std::uint32_t
>(payload[1 + nameLen]) << 24) |
142 (
static_cast<std::uint32_t
>(payload[1 + nameLen + 1]) << 16) |
143 (
static_cast<std::uint32_t
>(payload[1 + nameLen + 2]) << 8) |
144 static_cast<std::uint32_t
>(payload[1 + nameLen + 3]);
146 std::uint32_t sessionId = m_nextSessionId++;
147 addClient(sender, playerName, clientCaps, sessionId);
148 sendConnectAccept(sender, sessionId);
149 std::cout <<
"[AsioServer] Client connecté: " << playerName <<
" ("
150 << sender.address().to_string() <<
":" << sender.port()
151 <<
") - Session: " << sessionId <<
"\n";
158 if (payload.size() >= 2)
160 std::uint16_t reason =
161 (
static_cast<std::uint16_t
>(payload[0]) << 8) |
static_cast<std::uint16_t
>(payload[1]);
162 std::cout <<
"[AsioServer] Client déconnecté: " << sender.address().to_string() <<
":"
163 << sender.port() <<
" - Reason: " << reason <<
"\n";
165 removeClient(sender);
170 processAck(sender, payload);
180 for (
const auto &[endpoint, clientInfo] : m_clients)
182 if (endpoint != sender && clientInfo.connected)
184 sendEntityEvent(endpoint, 0, events);
188 catch (
const std::exception &e)
190 std::cerr <<
"[AsioServer] Erreur parsing ENTITY_EVENT: " << e.what() <<
"\n";
197 if (payload.size() >= 2)
199 const std::uint8_t direction = payload[0];
200 const std::uint8_t shooting = payload[1];
207 const std::uint16_t playerId = getPlayerId(sender);
208 ev.
data.push_back(
static_cast<std::uint8_t
>(playerId & 0xFF));
209 ev.
data.push_back(
static_cast<std::uint8_t
>((playerId >> 8) & 0xFF));
210 ev.
data.push_back(direction);
211 ev.
data.push_back(shooting);
213 std::vector<rnp::EventRecord> batch;
214 batch.emplace_back(std::move(ev));
215 broadcastEvents(batch);
221 if (payload.size() >= 8)
223 std::uint32_t nonce = (
static_cast<std::uint32_t
>(payload[0]) << 24) |
224 (
static_cast<std::uint32_t
>(payload[1]) << 16) |
225 (
static_cast<std::uint32_t
>(payload[2]) << 8) |
226 static_cast<std::uint32_t
>(payload[3]);
227 std::uint32_t sendTime = (
static_cast<std::uint32_t
>(payload[4]) << 24) |
228 (
static_cast<std::uint32_t
>(payload[5]) << 16) |
229 (
static_cast<std::uint32_t
>(payload[6]) << 8) |
230 static_cast<std::uint32_t
>(payload[7]);
231 sendPong(sender, nonce, sendTime);
244 if (it != m_packetHandlers.end())
246 it->second(sender, header, payload);
249 catch (
const std::exception &e)
251 std::cerr <<
"[AsioServer] Erreur de traitement du paquet: " << e.what() <<
"\n";
257 std::uint32_t clientCaps, std::uint32_t sessionId)
260 info.endpoint = endpoint;
261 info.playerName = playerName;
262 info.lastSequence = 0;
263 info.connected =
true;
264 info.playerId = m_nextPlayerId++;
265 info.sessionId = sessionId;
266 info.clientCaps = clientCaps;
267 m_clients[endpoint] = info;
274 auto it = m_clients.find(endpoint);
275 if (it != m_clients.end())
277 return it->second.playerId;
284 auto it = m_clients.find(endpoint);
285 if (it != m_clients.end())
287 return it->second.sessionId;
298 std::vector<uint8_t> payload;
301 payload.push_back(
static_cast<uint8_t
>((sessionId >> 24) & 0xFF));
302 payload.push_back(
static_cast<uint8_t
>((sessionId >> 16) & 0xFF));
303 payload.push_back(
static_cast<uint8_t
>((sessionId >> 8) & 0xFF));
304 payload.push_back(
static_cast<uint8_t
>(sessionId & 0xFF));
307 payload.push_back(
static_cast<uint8_t
>((m_tickRateHz >> 8) & 0xFF));
308 payload.push_back(
static_cast<uint8_t
>(m_tickRateHz & 0xFF));
311 payload.push_back(
static_cast<uint8_t
>((m_mtuPayloadBytes >> 8) & 0xFF));
312 payload.push_back(
static_cast<uint8_t
>(m_mtuPayloadBytes & 0xFF));
315 payload.push_back(
static_cast<uint8_t
>((m_serverCaps >> 24) & 0xFF));
316 payload.push_back(
static_cast<uint8_t
>((m_serverCaps >> 16) & 0xFF));
317 payload.push_back(
static_cast<uint8_t
>((m_serverCaps >> 8) & 0xFF));
318 payload.push_back(
static_cast<uint8_t
>(m_serverCaps & 0xFF));
320 header.
length = payload.size();
324 header.
sequence = ++m_sequenceNumber;
327 std::vector<uint8_t> buffer =
rnp::serialize(header, payload.data());
329 m_socket.async_send_to(asio::buffer(buffer), client,
330 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
331 { handleSend(error, bytesTransferred); });
340 std::vector<uint8_t> payload;
343 payload.push_back(
static_cast<uint8_t
>((cumulative >> 24) & 0xFF));
344 payload.push_back(
static_cast<uint8_t
>((cumulative >> 16) & 0xFF));
345 payload.push_back(
static_cast<uint8_t
>((cumulative >> 8) & 0xFF));
346 payload.push_back(
static_cast<uint8_t
>(cumulative & 0xFF));
349 payload.push_back(
static_cast<uint8_t
>((ackBits >> 24) & 0xFF));
350 payload.push_back(
static_cast<uint8_t
>((ackBits >> 16) & 0xFF));
351 payload.push_back(
static_cast<uint8_t
>((ackBits >> 8) & 0xFF));
352 payload.push_back(
static_cast<uint8_t
>(ackBits & 0xFF));
354 header.
length = payload.size();
357 header.
sequence = ++m_sequenceNumber;
360 std::vector<uint8_t> buffer =
rnp::serialize(header, payload.data());
362 m_socket.async_send_to(asio::buffer(buffer), client,
363 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
364 { handleSend(error, bytesTransferred); });
371 header.
length = worldData.size();
374 header.
sequence = ++m_sequenceNumber;
377 std::vector<uint8_t> buffer =
rnp::serialize(header, worldData.data());
379 m_socket.async_send_to(asio::buffer(buffer), client,
380 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
381 { handleSend(error, bytesTransferred); });
385 const std::vector<rnp::EntityState> &entities)
391 std::vector<uint8_t> payload;
394 payload.push_back(
static_cast<uint8_t
>((serverTick >> 24) & 0xFF));
395 payload.push_back(
static_cast<uint8_t
>((serverTick >> 16) & 0xFF));
396 payload.push_back(
static_cast<uint8_t
>((serverTick >> 8) & 0xFF));
397 payload.push_back(
static_cast<uint8_t
>(serverTick & 0xFF));
400 std::uint16_t entityCount =
static_cast<std::uint16_t
>(entities.size());
401 payload.push_back(
static_cast<uint8_t
>((entityCount >> 8) & 0xFF));
402 payload.push_back(
static_cast<uint8_t
>(entityCount & 0xFF));
405 for (
const auto &entity : entities)
408 payload.push_back(
static_cast<uint8_t
>((entity.id >> 24) & 0xFF));
409 payload.push_back(
static_cast<uint8_t
>((entity.id >> 16) & 0xFF));
410 payload.push_back(
static_cast<uint8_t
>((entity.id >> 8) & 0xFF));
411 payload.push_back(
static_cast<uint8_t
>(entity.id & 0xFF));
414 payload.push_back(
static_cast<uint8_t
>((entity.type >> 8) & 0xFF));
415 payload.push_back(
static_cast<uint8_t
>(entity.type & 0xFF));
418 const uint8_t *xBytes =
reinterpret_cast<const uint8_t *
>(&entity.x);
419 const uint8_t *yBytes =
reinterpret_cast<const uint8_t *
>(&entity.y);
420 const uint8_t *vxBytes =
reinterpret_cast<const uint8_t *
>(&entity.vx);
421 const uint8_t *vyBytes =
reinterpret_cast<const uint8_t *
>(&entity.vy);
424 for (
int i = 3; i >= 0; --i)
425 payload.push_back(xBytes[i]);
426 for (
int i = 3; i >= 0; --i)
427 payload.push_back(yBytes[i]);
428 for (
int i = 3; i >= 0; --i)
429 payload.push_back(vxBytes[i]);
430 for (
int i = 3; i >= 0; --i)
431 payload.push_back(vyBytes[i]);
434 payload.push_back(entity.stateFlags);
437 header.
length = payload.size();
440 header.
sequence = ++m_sequenceNumber;
443 std::vector<uint8_t> buffer =
rnp::serialize(header, payload.data());
445 m_socket.async_send_to(asio::buffer(buffer), client,
446 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
447 { handleSend(error, bytesTransferred); });
456 header.
length =
static_cast<std::uint16_t
>(eventsPayload.size());
459 header.
sequence = ++m_sequenceNumber;
462 std::vector<uint8_t> buffer =
rnp::serialize(header, eventsPayload.data());
464 m_socket.async_send_to(asio::buffer(buffer), client,
465 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
466 { handleSend(error, bytesTransferred); });
470 const std::vector<rnp::EventRecord> &events)
475 std::vector<uint8_t> payload;
478 payload.push_back(
static_cast<uint8_t
>((serverTick >> 24) & 0xFF));
479 payload.push_back(
static_cast<uint8_t
>((serverTick >> 16) & 0xFF));
480 payload.push_back(
static_cast<uint8_t
>((serverTick >> 8) & 0xFF));
481 payload.push_back(
static_cast<uint8_t
>(serverTick & 0xFF));
484 std::uint16_t eventCount =
static_cast<std::uint16_t
>(events.size());
485 payload.push_back(
static_cast<uint8_t
>((eventCount >> 8) & 0xFF));
486 payload.push_back(
static_cast<uint8_t
>(eventCount & 0xFF));
489 payload.insert(payload.end(), eventsPayload.begin(), eventsPayload.end());
493 header.
length =
static_cast<std::uint16_t
>(payload.size());
496 header.
sequence = ++m_sequenceNumber;
499 std::vector<uint8_t> buffer =
rnp::serialize(header, payload.data());
501 m_socket.async_send_to(asio::buffer(buffer), client,
502 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
503 { handleSend(error, bytesTransferred); });
513 header.
sequence = ++m_sequenceNumber;
518 m_socket.async_send_to(asio::buffer(buffer), client,
519 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
520 { handleSend(error, bytesTransferred); });
529 std::vector<uint8_t> payload;
532 payload.push_back(
static_cast<uint8_t
>((nonce >> 24) & 0xFF));
533 payload.push_back(
static_cast<uint8_t
>((nonce >> 16) & 0xFF));
534 payload.push_back(
static_cast<uint8_t
>((nonce >> 8) & 0xFF));
535 payload.push_back(
static_cast<uint8_t
>(nonce & 0xFF));
538 payload.push_back(
static_cast<uint8_t
>((sendTimeMs >> 24) & 0xFF));
539 payload.push_back(
static_cast<uint8_t
>((sendTimeMs >> 16) & 0xFF));
540 payload.push_back(
static_cast<uint8_t
>((sendTimeMs >> 8) & 0xFF));
541 payload.push_back(
static_cast<uint8_t
>(sendTimeMs & 0xFF));
543 header.
length = payload.size();
546 header.
sequence = ++m_sequenceNumber;
549 std::vector<uint8_t> buffer =
rnp::serialize(header, payload.data());
551 m_socket.async_send_to(asio::buffer(buffer), client,
552 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
553 { handleSend(error, bytesTransferred); });
562 const std::string &errorMessage)
568 std::vector<uint8_t> payload;
569 std::uint16_t code =
static_cast<std::uint16_t
>(errorCode);
570 payload.push_back(
static_cast<uint8_t
>((code >> 8) & 0xFF));
571 payload.push_back(
static_cast<uint8_t
>(code & 0xFF));
573 std::uint16_t msgLen =
static_cast<std::uint16_t
>(errorMessage.size());
574 payload.push_back(
static_cast<uint8_t
>((msgLen >> 8) & 0xFF));
575 payload.push_back(
static_cast<uint8_t
>(msgLen & 0xFF));
577 payload.insert(payload.end(), errorMessage.begin(), errorMessage.end());
579 header.
length = payload.size();
582 header.
sequence = ++m_sequenceNumber;
585 std::vector<uint8_t> buffer =
rnp::serialize(header, payload.data());
587 m_socket.async_send_to(asio::buffer(buffer), client,
588 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
589 { handleSend(error, bytesTransferred); });
594 for (
const auto &[endpoint, clientInfo] : m_clients)
596 if (clientInfo.connected)
598 m_socket.async_send_to(asio::buffer(data), endpoint,
599 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
600 { handleSend(error, bytesTransferred); });
611 header.
length =
static_cast<std::uint16_t
>(payload.size());
614 header.
sequence = ++m_sequenceNumber;
616 for (
const auto &[endpoint, clientInfo] : m_clients)
618 if (clientInfo.connected)
621 const std::vector<uint8_t> frame =
rnp::serialize(header, payload.data());
623 m_socket.async_send_to(asio::buffer(frame), endpoint,
624 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
625 { handleSend(error, bytesTransferred); });
635 std::vector<uint8_t> payload;
638 payload.push_back(
static_cast<uint8_t
>((serverTick >> 24) & 0xFF));
639 payload.push_back(
static_cast<uint8_t
>((serverTick >> 16) & 0xFF));
640 payload.push_back(
static_cast<uint8_t
>((serverTick >> 8) & 0xFF));
641 payload.push_back(
static_cast<uint8_t
>(serverTick & 0xFF));
644 std::uint16_t eventCount =
static_cast<std::uint16_t
>(events.size());
645 payload.push_back(
static_cast<uint8_t
>((eventCount >> 8) & 0xFF));
646 payload.push_back(
static_cast<uint8_t
>(eventCount & 0xFF));
649 payload.insert(payload.end(), eventsPayload.begin(), eventsPayload.end());
653 header.
length =
static_cast<std::uint16_t
>(payload.size());
656 header.
sequence = ++m_sequenceNumber;
658 for (
const auto &[endpoint, clientInfo] : m_clients)
660 if (clientInfo.connected)
663 const std::vector<uint8_t> frame =
rnp::serialize(header, payload.data());
665 m_socket.async_send_to(asio::buffer(frame), endpoint,
666 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
667 { handleSend(error, bytesTransferred); });
674 m_packetHandlers[type] = handler;
681 auto it = m_clients.find(sender);
682 if (it != m_clients.end())
684 it->second.lastSequence = header.
sequence;
690 if (payload.size() < 8)
696 std::uint32_t cumulative = (
static_cast<std::uint32_t
>(payload[0]) << 24) |
697 (
static_cast<std::uint32_t
>(payload[1]) << 16) |
698 (
static_cast<std::uint32_t
>(payload[2]) << 8) |
static_cast<std::uint32_t
>(payload[3]);
701 std::uint32_t ackBits = (
static_cast<std::uint32_t
>(payload[4]) << 24) |
702 (
static_cast<std::uint32_t
>(payload[5]) << 16) |
703 (
static_cast<std::uint32_t
>(payload[6]) << 8) |
static_cast<std::uint32_t
>(payload[7]);
706 m_pendingReliable.erase(cumulative);
709 for (
int i = 0; i < 32; ++i)
711 if (ackBits & (1 << i))
713 m_pendingReliable.erase(cumulative - i - 1);
717 m_clientLastAck[sender] = cumulative;
724 for (
const auto &[seq, data] : m_pendingReliable)
727 for (
const auto &[endpoint, clientInfo] : m_clients)
729 if (clientInfo.connected)
731 m_socket.async_send_to(asio::buffer(data), endpoint,
732 [
this](
const asio::error_code &error, std::size_t bytesTransferred)
733 { handleSend(error, bytesTransferred); });
This file contains the server network implementation for Asio.
void sendError(const asio::ip::udp::endpoint &client, rnp::ErrorCode errorCode, const std::string &errorMessage)
void processAck(const asio::ip::udp::endpoint &sender, const std::vector< uint8_t > &payload)
void handleReliablePacket(const asio::ip::udp::endpoint &sender, const rnp::PacketHeader &header)
void sendEvents(const asio::ip::udp::endpoint &client, const std::vector< rnp::EventRecord > &events)
std::function< void(const asio::ip::udp::endpoint &, const rnp::PacketHeader &, const std::vector< uint8_t > &)> PacketHandler
void setPacketHandler(rnp::PacketType type, PacketHandler handler)
void broadcastEntityEvents(std::uint32_t serverTick, const std::vector< rnp::EventRecord > &events)
void handleReceive(const asio::error_code &error, std::size_t bytesTransferred)
void sendPong(const asio::ip::udp::endpoint &client, std::uint32_t nonce, std::uint32_t sendTimeMs)
struct { asio::ip::udp::endpoint endpoint; std::string playerName; uint32_t lastSequence; bool connected; std::uint16_t playerId; std::uint32_t sessionId; std::uint32_t clientCaps; } ClientInfo
void broadcastEvents(const std::vector< rnp::EventRecord > &events)
void sendConnectAccept(const asio::ip::udp::endpoint &client, std::uint32_t sessionId)
void removeClient(const asio::ip::udp::endpoint &endpoint)
void processPacket(const asio::ip::udp::endpoint &sender, const std::vector< uint8_t > &data)
void handleSend(const asio::error_code &error, std::size_t bytesTransferred)
void init(const std::string &host, uint16_t port) override
std::uint32_t getSessionId(const asio::ip::udp::endpoint &endpoint) const
void broadcastToAll(const std::vector< uint8_t > &data)
std::uint16_t getPlayerId(const asio::ip::udp::endpoint &endpoint) const
void addClient(const asio::ip::udp::endpoint &endpoint, const std::string &playerName, std::uint32_t clientCaps, std::uint32_t sessionId)
void sendAck(const asio::ip::udp::endpoint &client, std::uint32_t cumulative, std::uint32_t ackBits)
void sendEntityEvent(const asio::ip::udp::endpoint &client, std::uint32_t serverTick, const std::vector< rnp::EventRecord > &events)
void sendWorldState(const asio::ip::udp::endpoint &client, std::uint32_t serverTick, const std::vector< rnp::EntityState > &entities)
void retransmitReliable()
PacketType
Packet types according to RNP specification.
std::vector< uint8_t > serialize(const PacketHeader &header, const uint8_t *payload=nullptr)
Serialize packet with header and optional payload (Big Endian)
PacketHeader deserializeHeader(const uint8_t *data, const std::size_t size)
Deserialize packet header (Big Endian)
std::vector< EventRecord > deserializeEvents(const std::uint8_t *payload, const std::size_t length)
Deserialize ENTITY_EVENT payload into event records Format per event: type(1) | entity_id(4,...
std::vector< std::uint8_t > serializeEvents(const std::vector< EventRecord > &events)
Serialize events in ENTITY_EVENT format (TLV with entity_id) Format per event: type(1) | entity_id(4,...
Event record for ENTITY_EVENT packets (TLV format)
std::vector< std::uint8_t > data