Air-Trap 1.0.0
A multiplayer R-Type clone game engine built with C++23 and ECS architecture
Loading...
Searching...
No Matches
Packet.tpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** R-Type
4** File description:
5** Packet.tpp
6*/
7
8#pragma once
9#include <cstring>
10#include <stdexcept>
11#include <vector>
12#include <string>
13#include <type_traits>
14
15namespace rtp::net
16{
17 ///////////////////////////////////////////////////////////////////////////
18 // Simple Template Implementations
19 ///////////////////////////////////////////////////////////////////////////
20
21 template <typename T>
22 auto Packet::operator<<(T data) -> Packet &
23 {
24 T network_data = to_network(data);
25
26 size_t dataSize = sizeof(T);
27 size_t currentSize = body.size();
28 body.resize(currentSize + dataSize);
29
30 std::memcpy(body.data() + currentSize, &network_data, dataSize);
31
32 header.bodySize = static_cast<uint32_t>(body.size());
33
34 return *this;
35 }
36
37 template <typename T>
38 auto Packet::operator>>(T &data) -> Packet &
39 {
40 if (_readPos + sizeof(T) > body.size()) {
41 throw std::out_of_range("Packet read overflow");
42 }
43
44 T network_data{};
45 std::memcpy(&network_data, body.data() + _readPos, sizeof(T));
46 _readPos += sizeof(T);
47
48 data = from_network(network_data);
49
50 return *this;
51 }
52
53 //////////////////////////////////////////////////////////////////////////
54 // Specialized Template Implementations
55 //////////////////////////////////////////////////////////////////////////
56
57 template <typename T>
58 inline auto Packet::operator<<(const std::vector<T> &vec) -> Packet &
59 {
60 uint32_t vecSize = static_cast<uint32_t>(vec.size());
61 *this << vecSize;
62 for (const auto &item : vec) {
63 *this << item;
64 }
65 return *this;
66 }
67
68 template <typename T>
69 inline auto Packet::operator>>(std::vector<T> &vec) -> Packet &
70 {
71 uint32_t vecSize;
72 *this >> vecSize;
73
74 vec.clear();
75 if (vecSize > 4096) throw std::runtime_error("Vector too large");
76 vec.reserve(vecSize);
77
78 for (uint32_t i = 0; i < vecSize; ++i) {
79 T item{};
80 *this >> item;
81 vec.push_back(std::move(item));
82 }
83 return *this;
84 }
85
86 inline auto Packet::operator<<(std::string_view str) -> Packet &
87 {
88 uint32_t strSize = static_cast<uint32_t>(str.size());
89
90 *this << strSize;
91
92 size_t currentSize = body.size();
93 body.resize(currentSize + strSize);
94
95 std::memcpy(body.data() + currentSize, str.data(), strSize);
96
97 header.bodySize = static_cast<uint32_t>(body.size());
98
99 return *this;
100 }
101
102 inline auto Packet::operator>>(std::string &str) -> Packet &
103 {
104 uint32_t strSize;
105 *this >> strSize;
106
107 if (strSize > 4096) throw std::runtime_error("String too large");
108
109 if (_readPos + strSize > body.size()) {
110 throw std::out_of_range("Packet read overflow");
111 }
112
113 str.assign(reinterpret_cast<const char *>(body.data() + _readPos), strSize);
114 _readPos += strSize;
115 return *this;
116 }
117
118 //////////////////////////////////////////////////////////////////////////
119 // Batching Operations
120 //////////////////////////////////////////////////////////////////////////
121
122 template <>
123 inline auto Packet::operator<<(ConnectPayload data) -> Packet &
124 {
125 *this << data.sessionId;
126 return *this;
127 }
128
129 template <>
130 inline auto Packet::operator>>(ConnectPayload &data) -> Packet &
131 {
132 *this >> data.sessionId;
133 return *this;
134 }
135
136 template <>
137 inline auto Packet::operator<<(LoginPayload data) -> Packet &
138 {
139 *this << std::string_view(data.username, strnlen(data.username, sizeof(data.username)));
140 *this << std::string_view(data.password, strnlen(data.password, sizeof(data.password)));
141 *this << data.weaponKind;
142 return *this;
143 }
144
145 template <>
146 inline auto Packet::operator>>(LoginPayload &data) -> Packet &
147 {
148 std::string username;
149 std::string password;
150 *this >> username;
151 *this >> password;
152 std::strncpy(data.username, username.c_str(), sizeof(data.username));
153 data.username[sizeof(data.username) - 1] = '\0';
154 std::strncpy(data.password, password.c_str(), sizeof(data.password));
155 data.password[sizeof(data.password) - 1] = '\0';
156 *this >> data.weaponKind;
157 return *this;
158 }
159
160 template <>
161 inline auto Packet::operator<<(RegisterPayload data) -> Packet &
162 {
163 *this << std::string_view(data.username, strnlen(data.username, sizeof(data.username)));
164 *this << std::string_view(data.password, strnlen(data.password, sizeof(data.password)));
165 return *this;
166 }
167
168 template <>
169 inline auto Packet::operator>>(RegisterPayload &data) -> Packet &
170 {
171 std::string username;
172 std::string password;
173 *this >> username;
174 *this >> password;
175 std::strncpy(data.username, username.c_str(), sizeof(data.username));
176 data.username[sizeof(data.username) - 1] = '\0';
177 std::strncpy(data.password, password.c_str(), sizeof(data.password));
178 data.password[sizeof(data.password) - 1] = '\0';
179 return *this;
180 }
181
182 template <>
183 inline auto Packet::operator<<(LoginResponsePayload data) -> Packet &
184 {
185 *this << data.success;
186 *this << std::string_view(data.username, strnlen(data.username, sizeof(data.username)));
187 return *this;
188 }
189
190 template <>
191 inline auto Packet::operator>>(LoginResponsePayload &data) -> Packet &
192 {
193 *this >> data.success;
194 std::string username;
195 *this >> username;
196 std::strncpy(data.username, username.c_str(), sizeof(data.username));
197 data.username[sizeof(data.username) - 1] = '\0';
198 return *this;
199 }
200
201 template <>
202 inline auto Packet::operator<<(RegisterResponsePayload data) -> Packet &
203 {
204 *this << data.success;
205 *this << std::string_view(data.username, strnlen(data.username, sizeof(data.username)));
206 return *this;
207 }
208
209 template <>
210 inline auto Packet::operator>>(RegisterResponsePayload &data) -> Packet &
211 {
212 *this >> data.success;
213 std::string username;
214 *this >> username;
215 std::strncpy(data.username, username.c_str(), sizeof(data.username));
216 data.username[sizeof(data.username) - 1] = '\0';
217 return *this;
218 }
219
220 template <>
221 inline auto Packet::operator<<(RoomInfo data) -> Packet &
222 {
223 *this << data.roomId;
224 *this << std::string_view(data.roomName, strnlen(data.roomName, sizeof(data.roomName)));
225 *this << data.currentPlayers;
226 *this << data.maxPlayers;
227 *this << data.inGame;
228 *this << data.difficulty;
229 *this << data.speed;
230 *this << data.duration;
231 *this << data.seed;
232 *this << data.levelId;
233 return *this;
234 }
235
236 template <>
237 inline auto Packet::operator>>(RoomInfo &data) -> Packet &
238 {
239 *this >> data.roomId;
240
241 std::string roomName;
242 *this >> roomName;
243 std::strncpy(data.roomName, roomName.c_str(), sizeof(data.roomName));
244 data.roomName[sizeof(data.roomName) - 1] = '\0';
245
246 *this >> data.currentPlayers;
247 *this >> data.maxPlayers;
248 *this >> data.inGame;
249 *this >> data.difficulty;
250 *this >> data.speed;
251 *this >> data.duration;
252 *this >> data.seed;
253 *this >> data.levelId;
254 return *this;
255 }
256
257 template <>
258 inline auto Packet::operator<<(CreateRoomPayload data) -> Packet &
259 {
260 *this << std::string_view(data.roomName, strnlen(data.roomName, sizeof(data.roomName)));
261 *this << data.maxPlayers;
262 *this << data.difficulty;
263 *this << data.speed;
264 *this << data.levelId;
265 *this << data.seed;
266 *this << data.duration;
267 *this << data.roomType;
268 return *this;
269 }
270
271 template <>
272 inline auto Packet::operator>>(CreateRoomPayload &data) -> Packet &
273 {
274 std::string roomName;
275 *this >> roomName;
276 std::strncpy(data.roomName, roomName.c_str(), sizeof(data.roomName));
277 data.roomName[sizeof(data.roomName) - 1] = '\0';
278
279 *this >> data.maxPlayers;
280 *this >> data.difficulty;
281 *this >> data.speed;
282 *this >> data.levelId;
283 *this >> data.seed;
284 *this >> data.duration;
285 *this >> data.roomType;
286 return *this;
287 }
288
289 template <>
290 inline auto Packet::operator<<(JoinRoomPayload data) -> Packet &
291 {
292 *this << data.roomId;
293 *this << data.isSpectator;
294 return *this;
295 }
296
297 template <>
298 inline auto Packet::operator>>(JoinRoomPayload &data) -> Packet &
299 {
300 *this >> data.roomId;
301 *this >> data.isSpectator;
302 return *this;
303 }
304
305 // template <>
306 // inline auto Packet::operator<<(LeaveRoomPayload data) -> Packet &
307 // {
308 // *this << data.roomId;
309 // return *this;
310 // }
311
312 // template <>
313 // inline auto Packet::operator>>(LeaveRoomPayload &data) -> Packet &
314 // {
315 // *this >> data.roomId;
316 // return *this;
317 // }
318
319 template <>
320 inline auto Packet::operator<<(RoomSnapshotPayload data) -> Packet &
321 {
322 *this << data.roomId;
323 *this << data.currentPlayers;
324 *this << data.serverTick;
325 *this << data.entityCount;
326 *this << data.inGame;
327 return *this;
328 }
329
330 template <>
331 inline auto Packet::operator>>(RoomSnapshotPayload &data) -> Packet &
332 {
333 *this >> data.roomId;
334 *this >> data.currentPlayers;
335 *this >> data.serverTick;
336 *this >> data.entityCount;
337 *this >> data.inGame;
338 return *this;
339 }
340
341 template <>
342 inline auto Packet::operator<<(SetReadyPayload data) -> Packet &
343 {
344 *this << data.isReady;
345 return *this;
346 }
347
348 template <>
349 inline auto Packet::operator>>(SetReadyPayload &data) -> Packet &
350 {
351 *this >> data.isReady;
352 return *this;
353 }
354
355 template <>
356 inline auto Packet::operator<<(RoomChatPayload data) -> Packet &
357 {
358 *this << std::string_view(data.message, strnlen(data.message, sizeof(data.message)));
359 return *this;
360 }
361
362 template <>
363 inline auto Packet::operator>>(RoomChatPayload &data) -> Packet &
364 {
365 std::string msg;
366 *this >> msg;
367 std::strncpy(data.message, msg.c_str(), sizeof(data.message));
368 data.message[sizeof(data.message) - 1] = '\0';
369 return *this;
370 }
371
372 template <>
373 inline auto Packet::operator<<(RoomChatReceivedPayload data) -> Packet &
374 {
375 *this << data.sessionId;
376 *this << std::string_view(data.username, strnlen(data.username, sizeof(data.username)));
377 *this << std::string_view(data.message, strnlen(data.message, sizeof(data.message)));
378 return *this;
379 }
380
381 template <>
382 inline auto Packet::operator>>(RoomChatReceivedPayload &data) -> Packet &
383 {
384 *this >> data.sessionId;
385
386 std::string username;
387 std::string message;
388 *this >> username;
389 *this >> message;
390
391 std::strncpy(data.username, username.c_str(), sizeof(data.username));
392 data.username[sizeof(data.username) - 1] = '\0';
393
394 std::strncpy(data.message, message.c_str(), sizeof(data.message));
395 data.message[sizeof(data.message) - 1] = '\0';
396
397 return *this;
398 }
399
400 template <>
401 inline auto Packet::operator<<(EntitySpawnPayload data) -> Packet &
402 {
403 *this << data.netId;
404 *this << data.type;
405 *this << data.posX;
406 *this << data.posY;
407 *this << data.sizeX;
408 *this << data.sizeY;
409 *this << data.weaponKind;
410 return *this;
411 }
412
413 template <>
414 inline auto Packet::operator>>(EntitySpawnPayload &data) -> Packet &
415 {
416 *this >> data.netId;
417 *this >> data.type;
418 *this >> data.posX;
419 *this >> data.posY;
420 *this >> data.sizeX;
421 *this >> data.sizeY;
422 *this >> data.weaponKind;
423 return *this;
424 }
425
426 template <>
427 inline auto Packet::operator<<(EntityDeathPayload data) -> Packet &
428 {
429 *this << data.netId;
430 *this << data.type;
431 *this << data.position.x;
432 *this << data.position.y;
433 return *this;
434 }
435
436 template <>
437 inline auto Packet::operator>>(EntityDeathPayload &data) -> Packet &
438 {
439 *this >> data.netId;
440 *this >> data.type;
441 *this >> data.position.x;
442 *this >> data.position.y;
443 return *this;
444 }
445
446 template <>
447 inline auto Packet::operator<<(AmmoUpdatePayload data) -> Packet &
448 {
449 *this << data.current;
450 *this << data.max;
451 *this << data.isReloading;
452 *this << data.cooldownRemaining;
453 return *this;
454 }
455
456 template <>
457 inline auto Packet::operator>>(AmmoUpdatePayload &data) -> Packet &
458 {
459 *this >> data.current;
460 *this >> data.max;
461 *this >> data.isReloading;
462 *this >> data.cooldownRemaining;
463 return *this;
464 }
465
466 template <>
467 inline auto Packet::operator<<(BeamStatePayload data) -> Packet &
468 {
469 *this << data.ownerNetId;
470 *this << data.active;
471 *this << data.timeRemaining;
472 *this << data.length;
473 *this << data.offsetY;
474 return *this;
475 }
476
477 template <>
478 inline auto Packet::operator>>(BeamStatePayload &data) -> Packet &
479 {
480 *this >> data.ownerNetId;
481 *this >> data.active;
482 *this >> data.timeRemaining;
483 *this >> data.length;
484 *this >> data.offsetY;
485 return *this;
486 }
487
488 template <>
489 inline auto Packet::operator<<(ScoreUpdatePayload data) -> Packet &
490 {
491 *this << data.score;
492 return *this;
493 }
494
495 template <>
496 inline auto Packet::operator>>(ScoreUpdatePayload &data) -> Packet &
497 {
498 *this >> data.score;
499 return *this;
500 }
501
502 template <>
503 inline auto Packet::operator<<(GameOverPayload data) -> Packet &
504 {
505 *this << std::string_view(data.bestPlayer, strnlen(data.bestPlayer, sizeof(data.bestPlayer)));
506 *this << data.bestScore;
507 *this << data.playerScore;
508 return *this;
509 }
510
511 template <>
512 inline auto Packet::operator>>(GameOverPayload &data) -> Packet &
513 {
514 std::string bestPlayer;
515 *this >> bestPlayer;
516 std::strncpy(data.bestPlayer, bestPlayer.c_str(), sizeof(data.bestPlayer) - 1);
517 data.bestPlayer[sizeof(data.bestPlayer) - 1] = '\0';
518 *this >> data.bestScore;
519 *this >> data.playerScore;
520 return *this;
521 }
522
523 template <>
524 inline auto Packet::operator<<(HealthUpdatePayload data) -> Packet &
525 {
526 *this << data.current;
527 *this << data.max;
528 return *this;
529 }
530
531 template <>
532 inline auto Packet::operator>>(HealthUpdatePayload &data) -> Packet &
533 {
534 *this >> data.current;
535 *this >> data.max;
536 return *this;
537 }
538
539 template <>
540 inline auto Packet::operator<<(PingPayload data) -> Packet &
541 {
542 *this << data.clientTimeMs;
543 return *this;
544 }
545
546 template <>
547 inline auto Packet::operator>>(PingPayload &data) -> Packet &
548 {
549 *this >> data.clientTimeMs;
550 return *this;
551 }
552
553 template <>
554 inline auto Packet::operator<<(DebugModePayload data) -> Packet &
555 {
556 *this << data.enabled;
557 return *this;
558 }
559
560 template <>
561 inline auto Packet::operator>>(DebugModePayload &data) -> Packet &
562 {
563 *this >> data.enabled;
564 return *this;
565 }
566
567 // template <>
568 // inline auto Packet::operator<<(WorldSnapshotPayload data) -> Packet &
569 // {
570 // *this << data.serverTick;
571 // *this << data.entityCount;
572 // return *this;
573 // }
574
575 // template <>
576 // inline auto Packet::operator>>(WorldSnapshotPayload &data) -> Packet &
577 // {
578 // *this >> data.serverTick;
579 // *this >> data.entityCount;
580 // return *this;
581 // }
582
583 template <>
584 inline auto Packet::operator<<(EntitySnapshotPayload data) -> Packet &
585 {
586 *this << data.netId;
587 *this << data.position.x;
588 *this << data.position.y;
589 *this << data.velocity.x;
590 *this << data.velocity.y;
591 *this << data.rotation;
592 return *this;
593 }
594
595 template <>
596 inline auto Packet::operator>>(EntitySnapshotPayload &data) -> Packet &
597 {
598 *this >> data.netId;
599 *this >> data.position.x;
600 *this >> data.position.y;
601 *this >> data.velocity.x;
602 *this >> data.velocity.y;
603 *this >> data.rotation;
604 return *this;
605 }
606} // namespace rtp::net