r-type  0.0.0
R-Type main
Loading...
Searching...
No Matches
asioServer.cpp
Go to the documentation of this file.
1#include <cstring>
2#include <iostream>
3
5
6using asio::ip::udp;
7
8srv::AsioServer::AsioServer() : m_socket(m_ioContext), m_recvBuffer() {}
9
10void srv::AsioServer::init(const std::string &host, const uint16_t port)
11{
12 const asio::ip::address addr = asio::ip::make_address(host);
13 const udp::endpoint ep(addr, port);
14
15 m_socket.open(ep.protocol());
16 m_socket.set_option(asio::socket_base::reuse_address(true));
17 m_socket.bind(ep);
18}
19
21{
22 m_workGuard = std::make_unique<asio::executor_work_guard<asio::io_context::executor_type>>(
23 asio::make_work_guard(m_ioContext));
24
25 startReceive();
26
27 m_ioThread = std::thread(
28 [this]
29 {
30 try
31 {
32 m_ioContext.run();
33 }
34 catch (const std::exception &e)
35 {
36 std::cerr << "[AsioServer] IO context exception: " << e.what() << "\n";
37 }
38 });
39}
40
42{
43 if (m_workGuard)
44 {
45 asio::post(m_ioContext,
46 [this]
47 {
48 asio::error_code ec;
49 m_socket.close(ec);
50 });
51
52 m_workGuard.reset();
53 }
54
55 m_ioContext.stop();
56
57 if (m_ioThread.joinable())
58 {
59 m_ioThread.join();
60 }
61}
62
64
66{
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); });
69}
70
71void srv::AsioServer::handleReceive(const asio::error_code &error, const std::size_t bytesTransferred)
72{
73 if (!error)
74 {
75 std::vector<uint8_t> data(m_recvBuffer.begin(), m_recvBuffer.begin() + bytesTransferred);
76 processPacket(m_remoteEndpoint, data);
77 startReceive();
78 }
79 else if (error == asio::error::operation_aborted)
80 {
81 return;
82 }
83 else
84 {
85 std::cerr << "[AsioServer] Erreur de réception: " << error.message() << "\n";
86 startReceive();
87 }
88}
89
90void srv::AsioServer::handleSend(const asio::error_code &error, std::size_t bytesTransferred)
91{
92 if (error)
93 {
94 std::cerr << "[AsioServer] Erreur d'envoi: " << error.message() << "\n";
95 }
96}
97
98void srv::AsioServer::processPacket(const asio::ip::udp::endpoint &sender, const std::vector<uint8_t> &data)
99{
100 try
101 {
102 rnp::PacketHeader header = rnp::deserializeHeader(data.data(), data.size());
103
104 std::vector<uint8_t> payload;
105 if (header.length > 0 && data.size() >= 16 + header.length)
106 {
107 payload.assign(data.begin() + 16, data.begin() + 16 + header.length);
108 }
109
110 // Vérifier la session ID (sauf pour CONNECT)
111 if (static_cast<rnp::PacketType>(header.type) != rnp::PacketType::CONNECT)
112 {
113 auto it = m_clients.find(sender);
114 if (it != m_clients.end() && it->second.sessionId != header.sessionId)
115 {
116 sendError(sender, rnp::ErrorCode::UNAUTHORIZED_SESSION, "Invalid session ID");
117 return;
118 }
119 }
120
121 // Gérer les flags de fiabilité
122 if (header.flags & static_cast<std::uint16_t>(rnp::PacketFlags::RELIABLE))
123 {
124 handleReliablePacket(sender, header);
125 }
126 if (header.flags & static_cast<std::uint16_t>(rnp::PacketFlags::ACK_REQ))
127 {
128 sendAck(sender, header.sequence, 0);
129 }
130
131 switch (static_cast<rnp::PacketType>(header.type))
132 {
134 {
135 if (payload.size() >= 5)
136 {
137 std::uint8_t nameLen = payload[0];
138 if (payload.size() >= 1 + nameLen + 4)
139 {
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]);
145
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";
152 }
153 }
154 break;
155 }
157 {
158 if (payload.size() >= 2)
159 {
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";
164 }
165 removeClient(sender);
166 break;
167 }
169 {
170 processAck(sender, payload);
171 break;
172 }
174 {
175 try
176 {
177 const std::vector<rnp::EventRecord> events = rnp::deserializeEvents(payload.data(), payload.size());
178
179 // Broadcast les events aux autres clients
180 for (const auto &[endpoint, clientInfo] : m_clients)
181 {
182 if (endpoint != sender && clientInfo.connected)
183 {
184 sendEntityEvent(endpoint, 0, events);
185 }
186 }
187 }
188 catch (const std::exception &e)
189 {
190 std::cerr << "[AsioServer] Erreur parsing ENTITY_EVENT: " << e.what() << "\n";
191 }
192 break;
193 }
195 {
196 // Support legacy PLAYER_INPUT
197 if (payload.size() >= 2)
198 {
199 const std::uint8_t direction = payload[0];
200 const std::uint8_t shooting = payload[1];
201
204 ev.entityId = getPlayerId(sender);
205 ev.data.reserve(4);
206
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);
212
213 std::vector<rnp::EventRecord> batch;
214 batch.emplace_back(std::move(ev));
215 broadcastEvents(batch);
216 }
217 break;
218 }
220 {
221 if (payload.size() >= 8)
222 {
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);
232 }
233 else
234 {
235 sendPong(sender);
236 }
237 break;
238 }
239 default:
240 break;
241 }
242
243 auto it = m_packetHandlers.find(static_cast<rnp::PacketType>(header.type));
244 if (it != m_packetHandlers.end())
245 {
246 it->second(sender, header, payload);
247 }
248 }
249 catch (const std::exception &e)
250 {
251 std::cerr << "[AsioServer] Erreur de traitement du paquet: " << e.what() << "\n";
252 sendError(sender, rnp::ErrorCode::INVALID_PAYLOAD, "Erreur de traitement du paquet");
253 }
254}
255
256void srv::AsioServer::addClient(const asio::ip::udp::endpoint &endpoint, const std::string &playerName,
257 std::uint32_t clientCaps, std::uint32_t sessionId)
258{
259 ClientInfo info;
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;
268}
269
270void srv::AsioServer::removeClient(const asio::ip::udp::endpoint &endpoint) { m_clients.erase(endpoint); }
271
272std::uint16_t srv::AsioServer::getPlayerId(const asio::ip::udp::endpoint &endpoint) const
273{
274 auto it = m_clients.find(endpoint);
275 if (it != m_clients.end())
276 {
277 return it->second.playerId;
278 }
279 return 0;
280}
281
282std::uint32_t srv::AsioServer::getSessionId(const asio::ip::udp::endpoint &endpoint) const
283{
284 auto it = m_clients.find(endpoint);
285 if (it != m_clients.end())
286 {
287 return it->second.sessionId;
288 }
289 return 0;
290}
291
292void srv::AsioServer::sendConnectAccept(const asio::ip::udp::endpoint &client, std::uint32_t sessionId)
293{
294 rnp::PacketHeader header;
295 header.type = static_cast<std::uint8_t>(rnp::PacketType::CONNECT_ACCEPT);
296
297 // Payload: session_id(4, BE) | tick_rate_hz(2, BE) | mtu_payload_bytes(2, BE) | server_caps(4, BE)
298 std::vector<uint8_t> payload;
299
300 // session_id (4 bytes, big endian)
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));
305
306 // tick_rate_hz (2 bytes, big endian)
307 payload.push_back(static_cast<uint8_t>((m_tickRateHz >> 8) & 0xFF));
308 payload.push_back(static_cast<uint8_t>(m_tickRateHz & 0xFF));
309
310 // mtu_payload_bytes (2 bytes, big endian)
311 payload.push_back(static_cast<uint8_t>((m_mtuPayloadBytes >> 8) & 0xFF));
312 payload.push_back(static_cast<uint8_t>(m_mtuPayloadBytes & 0xFF));
313
314 // server_caps (4 bytes, big endian)
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));
319
320 header.length = payload.size();
321 header.flags =
322 static_cast<std::uint16_t>(rnp::PacketFlags::RELIABLE) | static_cast<std::uint16_t>(rnp::PacketFlags::ACK_REQ);
323 header.reserved = 0;
324 header.sequence = ++m_sequenceNumber;
325 header.sessionId = sessionId;
326
327 std::vector<uint8_t> buffer = rnp::serialize(header, payload.data());
328
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); });
332}
333
334void srv::AsioServer::sendAck(const asio::ip::udp::endpoint &client, std::uint32_t cumulative, std::uint32_t ackBits)
335{
336 rnp::PacketHeader header;
337 header.type = static_cast<std::uint8_t>(rnp::PacketType::ACK);
338
339 // Payload: cumulative_ack(4, BE) | ack_bits(4, BE)
340 std::vector<uint8_t> payload;
341
342 // cumulative_ack (4 bytes, big endian)
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));
347
348 // ack_bits (4 bytes, big endian)
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));
353
354 header.length = payload.size();
355 header.flags = 0;
356 header.reserved = 0;
357 header.sequence = ++m_sequenceNumber;
358 header.sessionId = getSessionId(client);
359
360 std::vector<uint8_t> buffer = rnp::serialize(header, payload.data());
361
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); });
365}
366
367void srv::AsioServer::sendWorldState(const asio::ip::udp::endpoint &client, const std::vector<uint8_t> &worldData)
368{
369 rnp::PacketHeader header;
370 header.type = static_cast<std::uint8_t>(rnp::PacketType::WORLD_STATE);
371 header.length = worldData.size();
372 header.flags = 0;
373 header.reserved = 0;
374 header.sequence = ++m_sequenceNumber;
375 header.sessionId = getSessionId(client);
376
377 std::vector<uint8_t> buffer = rnp::serialize(header, worldData.data());
378
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); });
382}
383
384void srv::AsioServer::sendWorldState(const asio::ip::udp::endpoint &client, std::uint32_t serverTick,
385 const std::vector<rnp::EntityState> &entities)
386{
387 rnp::PacketHeader header;
388 header.type = static_cast<std::uint8_t>(rnp::PacketType::WORLD_STATE);
389
390 // Payload: server_tick(4, BE) | entity_count(2, BE) | entities...
391 std::vector<uint8_t> payload;
392
393 // server_tick (4 bytes, big endian)
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));
398
399 // entity_count (2 bytes, big endian)
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));
403
404 // Pour chaque entité: id(4) | type(2) | x(4) | y(4) | vx(4) | vy(4) | state_flags(1)
405 for (const auto &entity : entities)
406 {
407 // id (4 bytes, big endian)
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));
412
413 // type (2 bytes, big endian)
414 payload.push_back(static_cast<uint8_t>((entity.type >> 8) & 0xFF));
415 payload.push_back(static_cast<uint8_t>(entity.type & 0xFF));
416
417 // x, y, vx, vy (floats en big endian)
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);
422
423 // Note: Assuming little endian system, reverse for big endian network order
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]);
432
433 // state_flags (1 byte)
434 payload.push_back(entity.stateFlags);
435 }
436
437 header.length = payload.size();
438 header.flags = 0;
439 header.reserved = 0;
440 header.sequence = ++m_sequenceNumber;
441 header.sessionId = getSessionId(client);
442
443 std::vector<uint8_t> buffer = rnp::serialize(header, payload.data());
444
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); });
448}
449
450void srv::AsioServer::sendEvents(const asio::ip::udp::endpoint &client, const std::vector<rnp::EventRecord> &events)
451{
452 const std::vector<uint8_t> eventsPayload = rnp::serializeEvents(events);
453
454 rnp::PacketHeader header;
455 header.type = static_cast<std::uint8_t>(rnp::PacketType::ENTITY_EVENT);
456 header.length = static_cast<std::uint16_t>(eventsPayload.size());
457 header.flags = 0;
458 header.reserved = 0;
459 header.sequence = ++m_sequenceNumber;
460 header.sessionId = getSessionId(client);
461
462 std::vector<uint8_t> buffer = rnp::serialize(header, eventsPayload.data());
463
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); });
467}
468
469void srv::AsioServer::sendEntityEvent(const asio::ip::udp::endpoint &client, std::uint32_t serverTick,
470 const std::vector<rnp::EventRecord> &events)
471{
472 const std::vector<uint8_t> eventsPayload = rnp::serializeEvents(events);
473
474 // Payload: server_tick(4, BE) | event_count(2, BE) | events...
475 std::vector<uint8_t> payload;
476
477 // server_tick (4 bytes, big endian)
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));
482
483 // event_count (2 bytes, big endian)
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));
487
488 // Events serialized
489 payload.insert(payload.end(), eventsPayload.begin(), eventsPayload.end());
490
491 rnp::PacketHeader header;
492 header.type = static_cast<std::uint8_t>(rnp::PacketType::ENTITY_EVENT);
493 header.length = static_cast<std::uint16_t>(payload.size());
494 header.flags = 0;
495 header.reserved = 0;
496 header.sequence = ++m_sequenceNumber;
497 header.sessionId = getSessionId(client);
498
499 std::vector<uint8_t> buffer = rnp::serialize(header, payload.data());
500
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); });
504}
505
506void srv::AsioServer::sendPong(const asio::ip::udp::endpoint &client)
507{
508 rnp::PacketHeader header;
509 header.type = static_cast<std::uint8_t>(rnp::PacketType::PONG);
510 header.length = 0;
511 header.flags = 0;
512 header.reserved = 0;
513 header.sequence = ++m_sequenceNumber;
514 header.sessionId = getSessionId(client);
515
516 std::vector<uint8_t> buffer = rnp::serialize(header);
517
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); });
521}
522
523void srv::AsioServer::sendPong(const asio::ip::udp::endpoint &client, std::uint32_t nonce, std::uint32_t sendTimeMs)
524{
525 rnp::PacketHeader header;
526 header.type = static_cast<std::uint8_t>(rnp::PacketType::PONG);
527
528 // Payload: nonce(4, BE) | send_time_ms(4, BE)
529 std::vector<uint8_t> payload;
530
531 // nonce (4 bytes, big endian)
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));
536
537 // send_time_ms (4 bytes, big endian)
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));
542
543 header.length = payload.size();
544 header.flags = 0;
545 header.reserved = 0;
546 header.sequence = ++m_sequenceNumber;
547 header.sessionId = getSessionId(client);
548
549 std::vector<uint8_t> buffer = rnp::serialize(header, payload.data());
550
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); });
554}
555
556void srv::AsioServer::sendError(const asio::ip::udp::endpoint &client, const std::string &errorMessage)
557{
558 sendError(client, rnp::ErrorCode::INTERNAL_ERROR, errorMessage);
559}
560
561void srv::AsioServer::sendError(const asio::ip::udp::endpoint &client, rnp::ErrorCode errorCode,
562 const std::string &errorMessage)
563{
564 rnp::PacketHeader header;
565 header.type = static_cast<std::uint8_t>(rnp::PacketType::PACKET_ERROR);
566
567 // Payload: error_code(2, BE) | msg_len(2, BE) | message
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));
572
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));
576
577 payload.insert(payload.end(), errorMessage.begin(), errorMessage.end());
578
579 header.length = payload.size();
580 header.flags = 0;
581 header.reserved = 0;
582 header.sequence = ++m_sequenceNumber;
583 header.sessionId = getSessionId(client);
584
585 std::vector<uint8_t> buffer = rnp::serialize(header, payload.data());
586
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); });
590}
591
592void srv::AsioServer::broadcastToAll(const std::vector<uint8_t> &data)
593{
594 for (const auto &[endpoint, clientInfo] : m_clients)
595 {
596 if (clientInfo.connected)
597 {
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); });
601 }
602 }
603}
604
605void srv::AsioServer::broadcastEvents(const std::vector<rnp::EventRecord> &events)
606{
607 const std::vector<uint8_t> payload = rnp::serializeEvents(events);
608
609 rnp::PacketHeader header;
610 header.type = static_cast<std::uint8_t>(rnp::PacketType::ENTITY_EVENT);
611 header.length = static_cast<std::uint16_t>(payload.size());
612 header.flags = 0;
613 header.reserved = 0;
614 header.sequence = ++m_sequenceNumber;
615
616 for (const auto &[endpoint, clientInfo] : m_clients)
617 {
618 if (clientInfo.connected)
619 {
620 header.sessionId = clientInfo.sessionId;
621 const std::vector<uint8_t> frame = rnp::serialize(header, payload.data());
622
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); });
626 }
627 }
628}
629
630void srv::AsioServer::broadcastEntityEvents(std::uint32_t serverTick, const std::vector<rnp::EventRecord> &events)
631{
632 const std::vector<uint8_t> eventsPayload = rnp::serializeEvents(events);
633
634 // Payload: server_tick(4, BE) | event_count(2, BE) | events...
635 std::vector<uint8_t> payload;
636
637 // server_tick (4 bytes, big endian)
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));
642
643 // event_count (2 bytes, big endian)
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));
647
648 // Events serialized
649 payload.insert(payload.end(), eventsPayload.begin(), eventsPayload.end());
650
651 rnp::PacketHeader header;
652 header.type = static_cast<std::uint8_t>(rnp::PacketType::ENTITY_EVENT);
653 header.length = static_cast<std::uint16_t>(payload.size());
654 header.flags = 0;
655 header.reserved = 0;
656 header.sequence = ++m_sequenceNumber;
657
658 for (const auto &[endpoint, clientInfo] : m_clients)
659 {
660 if (clientInfo.connected)
661 {
662 header.sessionId = clientInfo.sessionId;
663 const std::vector<uint8_t> frame = rnp::serialize(header, payload.data());
664
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); });
668 }
669 }
670}
671
673{
674 m_packetHandlers[type] = handler;
675}
676
677void srv::AsioServer::handleReliablePacket(const asio::ip::udp::endpoint &sender, const rnp::PacketHeader &header)
678{
679 // Store for potential retransmission (simplified implementation)
680 // In production, you'd want more sophisticated tracking
681 auto it = m_clients.find(sender);
682 if (it != m_clients.end())
683 {
684 it->second.lastSequence = header.sequence;
685 }
686}
687
688void srv::AsioServer::processAck(const asio::ip::udp::endpoint &sender, const std::vector<uint8_t> &payload)
689{
690 if (payload.size() < 8)
691 {
692 return;
693 }
694
695 // cumulative_ack (4 bytes, big endian)
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]);
699
700 // ack_bits (4 bytes, big endian)
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]);
704
705 // Remove acknowledged packets from pending reliable
706 m_pendingReliable.erase(cumulative);
707
708 // Process ack bits for selective acknowledgment
709 for (int i = 0; i < 32; ++i)
710 {
711 if (ackBits & (1 << i))
712 {
713 m_pendingReliable.erase(cumulative - i - 1);
714 }
715 }
716
717 m_clientLastAck[sender] = cumulative;
718}
719
721{
722 // Simplified retransmission logic
723 // In production, track timestamps and implement exponential backoff
724 for (const auto &[seq, data] : m_pendingReliable)
725 {
726 // Retransmit to all clients (would need per-client tracking in production)
727 for (const auto &[endpoint, clientInfo] : m_clients)
728 {
729 if (clientInfo.connected)
730 {
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); });
734 }
735 }
736 }
737}
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)
~AsioServer() override
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 start() override
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 stop() override
void retransmitReliable()
ErrorCode
Error codes.
Definition Protocol.hpp:67
PacketType
Packet types according to RNP specification.
Definition Protocol.hpp:24
std::vector< uint8_t > serialize(const PacketHeader &header, const uint8_t *payload=nullptr)
Serialize packet with header and optional payload (Big Endian)
Definition Protocol.hpp:330
PacketHeader deserializeHeader(const uint8_t *data, const std::size_t size)
Deserialize packet header (Big Endian)
Definition Protocol.hpp:345
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,...
Definition Protocol.hpp:253
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,...
Definition Protocol.hpp:217
Event record for ENTITY_EVENT packets (TLV format)
Definition Protocol.hpp:104
std::uint32_t entityId
Definition Protocol.hpp:106
std::vector< std::uint8_t > data
Definition Protocol.hpp:107
Packet header according to RNP specification (Big Endian) Total size: 16 bytes.
Definition Protocol.hpp:115
std::uint32_t sessionId
Definition Protocol.hpp:121
std::uint8_t type
Definition Protocol.hpp:116
std::uint16_t length
Definition Protocol.hpp:117
std::uint32_t sequence
Definition Protocol.hpp:120
std::uint16_t flags
Definition Protocol.hpp:118
std::uint16_t reserved
Definition Protocol.hpp:119