Air-Trap 1.0.0
A multiplayer R-Type clone game engine built with C++23 and ECS architecture
Loading...
Searching...
No Matches
GameManager.cpp
Go to the documentation of this file.
1
11
12#include <cctype>
13#include <cstring>
14#include <unordered_map>
15
16namespace rtp::server
17{
19 // Public API
21
23 : _networkManager(networkManager)
24 {
43
44 _networkSyncSystem = std::make_unique<NetworkSyncSystem>(_networkManager, _registry);
45 _movementSystem = std::make_unique<MovementSystem>(_registry);
46 _authSystem = std::make_unique<AuthSystem>(_networkManager, _registry);
47 _roomSystem = std::make_unique<RoomSystem>(_networkManager, _registry, *_networkSyncSystem);
48 _playerSystem = std::make_unique<PlayerSystem>(_networkManager, _registry);
49 _entitySystem = std::make_unique<EntitySystem>(_registry, _networkManager, *_networkSyncSystem);
50 _playerMouvementSystem = std::make_unique<PlayerMouvementSystem>(_registry);
51 _playerShootSystem = std::make_unique<PlayerShootSystem>(_registry, *_roomSystem, *_networkSyncSystem);
52 _enemyAISystem = std::make_unique<EnemyAISystem>(_registry);
53 _levelSystem = std::make_unique<LevelSystem>(_registry, *_entitySystem, *_roomSystem, *_networkSyncSystem);
54 _collisionSystem = std::make_unique<CollisionSystem>(_registry, *_roomSystem, *_networkSyncSystem);
55 _enemyShootSystem = std::make_unique<EnemyShootSystem>(_registry, *_roomSystem, *_networkSyncSystem);
56 _homingSystem = std::make_unique<HomingSystem>(_registry);
57 _boomerangSystem = std::make_unique<BoomerangSystem>(_registry);
58 _bulletCleanupSystem = std::make_unique<BulletCleanupSystem>(_registry, *_roomSystem, *_networkSyncSystem);
59
60 _levelSystem->registerLevelPath(1, "config/levels/level_01.json");
61 _levelSystem->registerLevelPath(2, "config/levels/level_02.json");
62 _levelSystem->registerLevelPath(3, "config/levels/level_03.json");
63 _levelSystem->registerLevelPath(4, "config/levels/level_04.json");
64
65 _roomSystem->setOnRoomStarted(
66 [this](uint32_t roomId) {
67 auto room = _roomSystem->getRoom(roomId);
68 if (!room) {
69 log::error("Room ID {} not found for start event", roomId);
70 return;
71 }
72
73 _levelSystem->startLevelForRoom(roomId, room->getLevelId());
74
75 const auto players = room->getPlayers();
76 std::vector<uint32_t> sessions;
77 sessions.reserve(players.size());
78 for (const auto& player : players) {
79 sessions.push_back(player->getId());
80 }
81
82 const LevelData* level = _levelSystem->getLevelData(roomId);
83 const Vec2f spawnPos = level
84 ? level->playerStart
85 : Vec2f{100.f, 100.f};
86
87 for (auto& player : players) {
88 player->setScore(0);
90 net::ScoreUpdatePayload scorePayload{0};
91 scorePacket << scorePayload;
92 _networkSyncSystem->sendPacketToSession(
93 player->getId(), scorePacket, net::NetworkMode::TCP);
94 auto entity = _entitySystem->createPlayerEntity(player, spawnPos);
95 uint32_t entityId = static_cast<uint32_t>(entity.index());
96 player->setEntityId(entityId);
97 log::info("Spawned Entity {} for Player {}", entity.index(), player->getId());
98 _networkSyncSystem->bindSessionToEntity(player->getId(), entity);
99 sendEntitySpawnToSessions(entity, sessions);
100
101 if (auto healthRes = _registry.get<ecs::components::Health>()) {
102 auto &healths = healthRes->get();
103 if (healths.has(entity)) {
106 healths[entity].currentHealth,
107 healths[entity].maxHealth
108 };
109 healthPacket << hp;
110 _networkSyncSystem->sendPacketToSession(
111 player->getId(), healthPacket, net::NetworkMode::TCP);
112 }
113 }
114 }
115 }
116 );
117
118
119 log::info("GameManager initialized");
120 }
121
123 {
124 log::info("GameManager destroyed");
125 }
126
128 {
129 const float dt = 1.0f / 60.0f;
130
131 while (true) {
132 auto start = std::chrono::high_resolution_clock::now();
133
135
136 _serverTick++;
137 if (!_gamePaused) {
138 const float scaledDt = dt * _gameSpeed;
139 _roomSystem->update(scaledDt);
140 _levelSystem->update(scaledDt);
141 _enemyAISystem->update(scaledDt);
142 _playerMouvementSystem->update(scaledDt);
143 _playerShootSystem->update(scaledDt);
144 _enemyShootSystem->update(scaledDt);
145 _homingSystem->update(scaledDt);
146 _boomerangSystem->update(scaledDt);
147 _movementSystem->update(scaledDt);
148 _collisionSystem->update(scaledDt);
149 _bulletCleanupSystem->update(scaledDt);
150 }
151 std::this_thread::sleep_for(std::chrono::milliseconds(16));
152 }
153 }
154
155 void startGame(Room &room)
156 {
157 log::info("Starting game in Room ID {}", room.getId());
158 /* Future feature */
159 }
160
162 // Private Methods
164
166 {
167 while (auto optionalEvent = _networkManager.pollEvent()) {
168 auto& event = optionalEvent.value();
169 switch (event.packet.header.opCode) {
170 using namespace net;
171 using enum OpCode;
172 case None:
173 break;
174 case Hello:
175 handlePlayerConnect(event.sessionId);
176 break;
177 case Disconnect:
178 handlePlayerDisconnect(event.sessionId);
179 break;
180 case LoginRequest:
181 handlePlayerLoginAuth(event.sessionId, event.packet);
182 break;
183 case RegisterRequest:
184 handlePlayerRegisterAuth(event.sessionId, event.packet);
185 break;
186 case InputTick:
187 _networkSyncSystem->handleInput(event.sessionId, event.packet);
188 break;
189 case ListRooms:
190 handleListRooms(event.sessionId);
191 break;
192 case CreateRoom:
193 handleCreateRoom(event.sessionId, event.packet);
194 break;
195 case JoinRoom:
196 handleJoinRoom(event.sessionId, event.packet);
197 break;
198 case LeaveRoom:
199 handleLeaveRoom(event.sessionId, event.packet);
200 break;
201 case SetReady:
202 handleSetReady(event.sessionId, event.packet);
203 break;
204 case UpdateSelectedWeapon: {
205 handleUpdateSelectedWeapon(event.sessionId, event.packet);
206 break;
207 }
208 case RoomChatSended:
209 handleRoomChatSended(event.sessionId, event.packet);
210 break;
211 case Ping:
212 handlePing(event.sessionId, event.packet);
213 break;
214 default:
215 handlePacket(event.sessionId, event.packet);
216 break;
217 }
218 }
219 }
220
221 void GameManager::handlePlayerConnect(uint32_t sessionId)
222 {
223 log::info("Client with Session ID {} connected, not logged yet", sessionId);
224 }
225
226 void GameManager::handlePlayerDisconnect(uint32_t sessionId)
227 {
228 uint32_t entityId = 0;
229
230 {
231 std::lock_guard lock(_mutex);
232 entityId = _playerSystem->removePlayer(sessionId);
233 _roomSystem->disconnectPlayer(sessionId);
234 _networkSyncSystem->handleDisconnect(sessionId);
235 }
236
237 if (entityId != 0) {
238 // Find the entity by scanning NetworkId sparse array for matching id
239 auto netsRes = _registry.get<ecs::components::NetworkId>();
241 if (netsRes) {
242 auto &nets = netsRes->get();
243 for (auto e : nets.entities()) {
244 if (nets[e].id == entityId) {
245 entity = e;
246 break;
247 }
248 }
249 }
250
251 if (!entity.isNull()) {
252 auto transformsRes = _registry.get<ecs::components::Transform>();
253 auto typesRes = _registry.get<ecs::components::EntityType>();
254 auto roomsRes = _registry.get<ecs::components::RoomId>();
255
256 if (transformsRes && typesRes && netsRes && roomsRes) {
257 auto &transforms = transformsRes->get();
258 auto &types = typesRes->get();
259 auto &nets = netsRes->get();
260 auto &rooms = roomsRes->get();
261 if (transforms.has(entity) && types.has(entity) && nets.has(entity) && rooms.has(entity)) {
262 auto room = _roomSystem->getRoom(rooms[entity].id);
263 if (room) {
264 const auto players = room->getPlayers();
265 if (!players.empty()) {
267 net::EntityDeathPayload payload{};
268 payload.netId = nets[entity].id;
269 payload.type = static_cast<uint8_t>(types[entity].type);
270 payload.position = transforms[entity].position;
271 packet << payload;
272
273 for (const auto& player : players) {
274 _networkSyncSystem->sendPacketToSession(player->getId(), packet, net::NetworkMode::TCP);
275 }
276 }
277 }
278 }
279 }
280
281 _registry.kill(entity);
282 }
283
284 net::Packet disconnectPlayer(net::OpCode::Disconnect);
285 disconnectPlayer << entityId;
287 }
288
289 log::info("Player with Session ID {} disconnected", sessionId);
290 }
291
292 void GameManager::handlePlayerLoginAuth(uint32_t sessionId, const net::Packet &packet)
293 {
294 log::info("Handling authentication for Session ID {}", sessionId);
295 auto [success, username, weaponKind] = _authSystem->handleLoginRequest(sessionId, packet);
296 if (!success) return;
297
298 PlayerPtr player;
299 {
300 std::lock_guard lock(_mutex);
301 player = _playerSystem->createPlayer(sessionId, username);
302 if (player) {
303 player->setWeaponKind(static_cast<rtp::ecs::components::WeaponKind>(weaponKind));
304 log::info("Player {} weapon set to {}", sessionId, static_cast<int>(weaponKind));
305 }
306 }
307
308 if (_roomSystem->joinLobby(player)) {
309 player->setState(PlayerState::InLobby);
310 } else {
311 log::error("Failed to join Lobby for Session ID {}", sessionId);
312 }
313 }
314
315 void GameManager::handlePlayerRegisterAuth(uint32_t sessionId, const net::Packet &packet)
316 {
317 log::info("Handling registration for Session ID {}", sessionId);
318 auto res = _authSystem->handleRegisterRequest(sessionId, packet);
319 if (!res.first) return;
320
321 PlayerPtr player;
322 {
323 std::lock_guard lock(_mutex);
324 player = _playerSystem->createPlayer(sessionId, res.second);
325 }
326
327 if (_roomSystem->joinLobby(player)) {
328 player->setState(PlayerState::InLobby);
329 } else {
330 log::error("Failed to join Lobby for Session ID {}", sessionId);
331 }
332 }
333
334 void GameManager::handleListRooms(uint32_t sessionId)
335 {
336 _roomSystem->listAllRooms(sessionId);
337 }
338
339 void GameManager::handleCreateRoom(uint32_t sessionId, const net::Packet &packet)
340 {
342 net::Packet tmp = packet;
343 tmp >> payload;
344
345 PlayerPtr player;
346 uint32_t newId = 0;
347 uint8_t success = 0;
348 {
349 std::lock_guard lock(_mutex);
350 player = _playerSystem->getPlayer(sessionId);
351 if (!player) {
353 response << static_cast<uint8_t>(0);
355 return;
356 }
357 newId = _roomSystem->createRoom(
358 sessionId,
359 std::string(payload.roomName),
360 static_cast<uint8_t>(payload.maxPlayers),
361 payload.difficulty,
362 payload.speed,
363 static_cast<Room::RoomType>(payload.roomType),
364 payload.levelId,
365 payload.seed,
366 payload.duration
367 );
368 success = (newId != 0) ? 1 : 0;
369 }
370 if (success) {
371 success = _roomSystem->joinRoom(player, newId, false) ? 1 : 0;
372
373 if (success && payload.roomType == static_cast<uint8_t>(net::roomType::Private) &&
374 payload.maxPlayers == 1) {
375 player->setReady(true);
376 log::info("Auto-ready player {} for solo game", sessionId);
377 }
378 }
380 response << success;
382 // entityId = _entitySystem->createPlayerEntity(player);
383 // _serverNetworkSystem->bindSessionToEntity(player->getId(), entityId);
384 }
385
386 void GameManager::handleJoinRoom(uint32_t sessionId, const net::Packet &packet)
387 {
388 net::JoinRoomPayload payload;
389 net::Packet tempPacket = packet;
390 tempPacket >> payload;
391
392 PlayerPtr player;
393 {
394 std::lock_guard lock(_mutex);
395 player = _playerSystem->getPlayer(sessionId);
396 }
397
398 const bool success = _roomSystem->joinRoom(player, payload.roomId, payload.isSpectator != 0);
399 if (!success)
400 return;
401
402 auto room = _roomSystem->getRoom(payload.roomId);
403 if (!room)
404 return;
405 if (room->getState() != Room::State::InGame)
406 return;
407
409 _networkManager.sendPacket(sessionId, startPacket, net::NetworkMode::TCP);
410 sendRoomEntitySpawnsToSession(payload.roomId, sessionId);
411 // entityId = _entitySystem->createPlayerEntity(player);
412 // _serverNetworkSystem->bindSessionToEntity(player->getId(), entityId);
413 }
414
415 void GameManager::handleLeaveRoom(uint32_t sessionId, const net::Packet &packet)
416 {
417 (void)packet;
418 PlayerPtr player;
419 {
420 std::lock_guard lock(_mutex);
421 player = _playerSystem->getPlayer(sessionId);
422 }
423
424 log::info("Handle Leave Room request from Session ID {}", sessionId);
425
426 _roomSystem->leaveRoom(player);
427 }
428
429 void GameManager::handleSetReady(uint32_t sessionId, const net::Packet &packet)
430 {
431 std::lock_guard lock(_mutex);
432
433 net::SetReadyPayload payload;
434 net::Packet tempPacket = packet;
435 tempPacket >> payload;
436 log::info("Handle Set Ready request from Session ID {}: isReady={}",
437 sessionId, payload.isReady);
438 _playerSystem->getPlayer(sessionId)->setReady(payload.isReady != 0);
439 }
440
441 void GameManager::handleUpdateSelectedWeapon(uint32_t sessionId, const net::Packet &packet)
442 {
443 net::Packet tmp = packet;
444 uint8_t kind = 0;
445 try {
446 tmp >> kind;
447 } catch (...) {
448 log::warning("Failed to parse UpdateSelectedWeapon packet from session {}", sessionId);
449 return;
450 }
451
452 std::lock_guard lock(_mutex);
453 PlayerPtr player = _playerSystem->getPlayer(sessionId);
454 if (!player) {
455 log::warning("UpdateSelectedWeapon: player for session {} not found", sessionId);
456 return;
457 }
458
459 player->setWeaponKind(static_cast<rtp::ecs::components::WeaponKind>(kind));
460 log::info("Player {} updated weapon to {}", sessionId, static_cast<int>(kind));
461
462 uint32_t entityId = player->getEntityId();
463 if (entityId != 0) {
464 ecs::Entity e(entityId, 0);
465 _entitySystem->applyWeaponToEntity(e, static_cast<rtp::ecs::components::WeaponKind>(kind));
466 }
467 }
468
469 void GameManager::handleRoomChatSended(uint32_t sessionId, const net::Packet &packet)
470 {
471 net::RoomChatPayload payload;
472 net::Packet tempPacket = packet;
473 tempPacket >> payload;
474
475 PlayerPtr player;
476 {
477 std::lock_guard lock(_mutex);
478 player = _playerSystem->getPlayer(sessionId);
479 }
480 if (!player)
481 return;
482
483 const uint32_t roomId = player->getRoomId();
484 if (roomId == 0)
485 return;
486
487 auto room = _roomSystem->getRoom(roomId);
488 if (!room)
489 return;
490
491 const std::string message(payload.message);
492 if (handleChatCommand(player, message)) {
493 return;
494 }
495 if (player->isMuted()) {
496 return;
497 }
498
499 net::RoomChatReceivedPayload chatPayload{};
500 chatPayload.sessionId = sessionId;
501 const std::string username = player->getUsername();
502 std::strncpy(chatPayload.username, username.c_str(), sizeof(chatPayload.username) - 1);
503 chatPayload.username[sizeof(chatPayload.username) - 1] = '\0';
504 std::strncpy(chatPayload.message, payload.message, sizeof(chatPayload.message) - 1);
505 chatPayload.message[sizeof(chatPayload.message) - 1] = '\0';
506
508 chatPacket << chatPayload;
509
510 const auto players = room->getPlayers();
511 for (const auto& p : players) {
512 _networkManager.sendPacket(p->getId(), chatPacket, net::NetworkMode::TCP);
513 }
514 }
515
516 void GameManager::handlePacket(uint32_t sessionId, const net::Packet &packet)
517 {
518 std::lock_guard lock(_mutex);
519 log::info("Received packet OpCode {} from Session {}", (int)net::OpCode::LoginRequest, sessionId);
520 log::debug("Unknown packet received OpCode {} from Session {}", (int)packet.header.opCode, sessionId);
521 }
522
523 void GameManager::handlePing(uint32_t sessionId, const net::Packet &packet)
524 {
525 net::PingPayload payload{};
526 net::Packet tempPacket = packet;
527 tempPacket >> payload;
528
530 response << payload;
532 }
533
534 bool GameManager::handleChatCommand(PlayerPtr player, const std::string& message)
535 {
536 if (message.empty() || message[0] != '/')
537 return false;
538
539 const uint32_t roomId = player->getRoomId();
540 if (roomId == 0)
541 return true;
542
543 auto room = _roomSystem->getRoom(roomId);
544 if (!room)
545 return true;
546
547 auto toLower = [](std::string s) {
548 for (char &c : s) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
549 return s;
550 };
551
552 const std::string msg = message;
553 const std::string cmd = toLower(msg.substr(0, msg.find(' ')));
554 const std::string arg = msg.find(' ') == std::string::npos
555 ? ""
556 : msg.substr(msg.find(' ') + 1);
557
558 if (cmd == "/help") {
559 sendChatToSession(player->getId(), "Commands: /help, /kick <name>, /ban <name>, /mute <name>,");
560 sendChatToSession(player->getId(), "/stop, /run, /speed <float>, /debug <true|false>");
561 sendChatToSession(player->getId(), "/debug enables invincibility + hitbox display");
562 sendChatToSession(player->getId(), "Examples: /speed 0.5 | /debug true | /kick player1");
563 return true;
564 }
565
566 if (cmd == "/stop") {
567 _gamePaused = true;
568 sendSystemMessageToRoom(roomId, "Game paused");
569 return true;
570 }
571 if (cmd == "/run") {
572 _gamePaused = false;
573 sendSystemMessageToRoom(roomId, "Game resumed");
574 return true;
575 }
576 if (cmd == "/speed") {
577 if (arg.empty()) {
578 sendChatToSession(player->getId(), "Usage: /speed <float>");
579 return true;
580 }
581 try {
582 float v = std::stof(arg);
583 if (v < 0.1f) v = 0.1f;
584 if (v > 4.0f) v = 4.0f;
585 _gameSpeed = v;
586 sendSystemMessageToRoom(roomId, "Game speed set to " + std::to_string(v));
587 } catch (...) {
588 sendChatToSession(player->getId(), "Invalid speed value");
589 }
590 return true;
591 }
592 if (cmd == "/debug") {
593 const std::string v = toLower(arg);
594 if (v != "true" && v != "false") {
595 sendChatToSession(player->getId(), "Usage: /debug <true|false>");
596 return true;
597 }
598 const bool enabled = (v == "true");
599
600 // Enable invincibility mode in CollisionSystem
601 _collisionSystem->setInvincible(enabled);
602
604 net::DebugModePayload payload{ static_cast<uint8_t>(enabled ? 1 : 0) };
605 packet << payload;
606 const auto players = room->getPlayers();
607 for (const auto& p : players) {
609 }
610 sendSystemMessageToRoom(roomId, std::string("Debug mode ") + (enabled ? "enabled (invincibility ON)" : "disabled (invincibility OFF)"));
611 return true;
612 }
613
614 if (cmd == "/kick" || cmd == "/mute" || cmd == "/ban") {
615 if (arg.empty()) {
616 sendChatToSession(player->getId(), std::string("Usage: ") + cmd + " <name>");
617 return true;
618 }
619 PlayerPtr target = _playerSystem->getPlayerByUsername(arg);
620 if (!target || target->getRoomId() != roomId) {
621 sendChatToSession(player->getId(), "Player not found in room");
622 return true;
623 }
624 if (cmd == "/kick") {
625 _roomSystem->leaveRoom(target);
627 response << static_cast<uint8_t>(1);
628 _networkManager.sendPacket(target->getId(), response, net::NetworkMode::TCP);
629 net::Packet kickedPacket(net::OpCode::Kicked);
630 _networkManager.sendPacket(target->getId(), kickedPacket, net::NetworkMode::TCP);
631 sendSystemMessageToRoom(roomId, target->getUsername() + " has been kicked");
632 return true;
633 }
634 if (cmd == "/ban") {
635 room->banUser(arg);
636 _roomSystem->leaveRoom(target);
638 response << static_cast<uint8_t>(1);
639 _networkManager.sendPacket(target->getId(), response, net::NetworkMode::TCP);
640 net::Packet kickedPacket(net::OpCode::Kicked);
641 _networkManager.sendPacket(target->getId(), kickedPacket, net::NetworkMode::TCP);
642 sendSystemMessageToRoom(roomId, target->getUsername() + " has been banned");
643 return true;
644 }
645 if (cmd == "/mute") {
646 const bool newMuted = !target->isMuted();
647 target->setMuted(newMuted);
649 target->getUsername() + (newMuted ? " has been muted" : " has been unmuted"));
650 return true;
651 }
652 }
653
654 sendChatToSession(player->getId(), "Unknown command. Use /help");
655 return true;
656 }
657
658 void GameManager::sendChatToSession(uint32_t sessionId, const std::string& message)
659 {
661 payload.sessionId = 0;
662 payload.username[0] = '\0';
663 std::strncpy(payload.message, message.c_str(), sizeof(payload.message) - 1);
664 payload.message[sizeof(payload.message) - 1] = '\0';
665
667 packet << payload;
669 }
670
671 void GameManager::sendSystemMessageToRoom(uint32_t roomId, const std::string& message)
672 {
673 auto room = _roomSystem->getRoom(roomId);
674 if (!room)
675 return;
676 const auto players = room->getPlayers();
677
679 payload.sessionId = 0;
680 payload.username[0] = '\0';
681 std::strncpy(payload.message, message.c_str(), sizeof(payload.message) - 1);
682 payload.message[sizeof(payload.message) - 1] = '\0';
683
685 packet << payload;
686
687 for (const auto& p : players) {
689 }
690 }
691
693 const std::vector<uint32_t>& sessions)
694 {
695 if (sessions.empty())
696 return;
697
698 auto transformRes = _registry.get<ecs::components::Transform>();
699 auto typeRes = _registry.get<ecs::components::EntityType>();
702 if (!transformRes || !typeRes || !netRes) {
703 log::error("Missing component array for EntitySpawn");
704 return;
705 }
706
707 auto &transforms = transformRes->get();
708 auto &types = typeRes->get();
709 auto &nets = netRes->get();
710 auto *boxes = boxRes ? &boxRes->get() : nullptr;
711 if (!transforms.has(entity) || !types.has(entity) || !nets.has(entity)) {
712 log::error("Entity {} missing Transform/EntityType/NetworkId", entity.index());
713 return;
714 }
715
716 const auto &transform = transforms[entity];
717 const auto &type = types[entity];
718 const auto &net = nets[entity];
719 float sizeX = 0.0f;
720 float sizeY = 0.0f;
721 if (boxes && boxes->has(entity)) {
722 const auto &box = (*boxes)[entity];
723 sizeX = box.width;
724 sizeY = box.height;
725 }
726 uint8_t weaponKind = 0;
727 if (auto weaponRes = _registry.get<ecs::components::SimpleWeapon>()) {
728 auto &weapons = weaponRes->get();
729 if (weapons.has(entity)) {
730 weaponKind = static_cast<uint8_t>(weapons[entity].kind);
731 }
732 }
733
735 net::EntitySpawnPayload payload = {
736 net.id,
737 static_cast<uint8_t>(type.type),
738 transform.position.x,
739 transform.position.y,
740 sizeX,
741 sizeY,
742 weaponKind
743 };
744 packet << payload;
745 _networkSyncSystem->sendPacketToSessions(sessions, packet, net::NetworkMode::TCP);
746 }
747
748 void GameManager::sendRoomEntitySpawnsToSession(uint32_t roomId, uint32_t sessionId)
749 {
750 auto view = _registry.zipView<
755 >();
757 auto *boxes = boxRes ? &boxRes->get() : nullptr;
758 std::unordered_map<uint32_t, ecs::Entity> netToEntity;
759 if (boxes) {
761 if (netRes) {
762 auto &nets = netRes->get();
763 for (auto e : nets.entities()) {
764 netToEntity[nets[e].id] = e;
765 }
766 }
767 }
768
769 for (auto&& [tf, net, type, room] : view) {
770 if (room.id != roomId)
771 continue;
772
773 float sizeX = 0.0f;
774 float sizeY = 0.0f;
775 if (boxes) {
776 auto it = netToEntity.find(net.id);
777 if (it != netToEntity.end() && boxes->has(it->second)) {
778 const auto &box = (*boxes)[it->second];
779 sizeX = box.width;
780 sizeY = box.height;
781 }
782 }
783
784 uint8_t weaponKind = 0;
785 if (auto weaponRes = _registry.get<ecs::components::SimpleWeapon>()) {
786 auto &weapons = weaponRes->get();
787 auto it2 = netToEntity.find(net.id);
788 if (it2 != netToEntity.end() && weapons.has(it2->second)) {
789 weaponKind = static_cast<uint8_t>(weapons[it2->second].kind);
790 }
791 }
792
794 net::EntitySpawnPayload payload = {
795 net.id,
796 static_cast<uint8_t>(type.type),
797 tf.position.x,
798 tf.position.y,
799 sizeX,
800 sizeY,
801 weaponKind
802 };
803 packet << payload;
804 _networkSyncSystem->sendPacketToSession(sessionId, packet, net::NetworkMode::TCP);
805 }
806 }
807}
Represents an entity in the ECS (Entity-Component-System) architecture.
Definition Entity.hpp:63
constexpr std::uint32_t index(void) const
auto subscribe(this Self &self) -> std::expected< std::reference_wrapper< ConstLike< Self, SparseArray< T > > >, rtp::Error >
void kill(Entity entity)
Definition Registry.cpp:73
auto get(this const Self &self) -> std::expected< std::reference_wrapper< ConstLike< Self, SparseArray< T > > >, rtp::Error >
auto zipView(this Self &self)
Network packet with header and serializable body.
Definition Packet.hpp:471
Header header
Packet header.
Definition Packet.hpp:473
void handlePing(uint32_t sessionId, const net::Packet &packet)
std::unique_ptr< RoomSystem > _roomSystem
Room system for handling room management.
std::unique_ptr< MovementSystem > _movementSystem
Movement system for updating entity positions.
void handlePlayerDisconnect(uint32_t sessionId)
Handle a player disconnection.
void handleJoinRoom(uint32_t sessionId, const net::Packet &packet)
Handle a generic incoming packet from a player.
std::unique_ptr< PlayerMouvementSystem > _playerMouvementSystem
Player movement system for handling player-specific movement logic.
std::unique_ptr< NetworkSyncSystem > _networkSyncSystem
Server network system for handling network-related ECS operations.
std::unique_ptr< EnemyAISystem > _enemyAISystem
Enemy AI system for movement patterns.
std::unique_ptr< BoomerangSystem > _boomerangSystem
Boomerang system for boomerang projectiles.
uint32_t _serverTick
Current server tick for synchronization.
std::mutex _mutex
Mutex for thread-safe operations.
void handleRoomChatSended(uint32_t sessionId, const net::Packet &packet)
Handle a generic incoming packet from a player.
void handleListRooms(uint32_t sessionId)
Handle a request to list available rooms.
void gameLoop(void)
Main game loop.
std::unique_ptr< EnemyShootSystem > _enemyShootSystem
Enemy shooting system.
void handleLeaveRoom(uint32_t sessionId, const net::Packet &packet)
Handle a generic incoming packet from a player.
void handleCreateRoom(uint32_t sessionId, const net::Packet &packet)
Handle a generic incoming packet from a player.
void sendRoomEntitySpawnsToSession(uint32_t roomId, uint32_t sessionId)
bool handleChatCommand(PlayerPtr player, const std::string &message)
void processNetworkEvents(void)
Process incoming network events with OpCode handling.
~GameManager()
Destructor for GameManager.
std::unique_ptr< LevelSystem > _levelSystem
Level system for timed spawns.
std::unique_ptr< CollisionSystem > _collisionSystem
Collision system for pickups/obstacles.
float _gameSpeed
Global game speed multiplier.
std::unique_ptr< HomingSystem > _homingSystem
Homing system for tracker bullets.
ServerNetwork & _networkManager
Reference to the ServerNetwork instance.
std::unique_ptr< PlayerSystem > _playerSystem
Player system for handling player-related operations.
GameManager(ServerNetwork &networkManager)
Constructor for GameManager.
void sendSystemMessageToRoom(uint32_t roomId, const std::string &message)
void handlePacket(uint32_t sessionId, const net::Packet &packet)
Handle an incoming packet from a player.
bool _gamePaused
Global game pause flag.
void handlePlayerLoginAuth(uint32_t sessionId, const net::Packet &packet)
Handle player login with provided username if successful then join the lobby.
void handleUpdateSelectedWeapon(uint32_t sessionId, const net::Packet &packet)
Handle an update to the selected weapon sent by client.
ecs::Registry _registry
ECS Registry for managing entities and components.
void handleSetReady(uint32_t sessionId, const net::Packet &packet)
Handle a generic incoming packet from a player.
void handlePlayerRegisterAuth(uint32_t sessionId, const net::Packet &packet)
Handle player registration with provided username.
void sendChatToSession(uint32_t sessionId, const std::string &message)
std::unique_ptr< PlayerShootSystem > _playerShootSystem
Player shooting system for handling bullets.
std::unique_ptr< BulletCleanupSystem > _bulletCleanupSystem
Bullet cleanup system.
std::unique_ptr< EntitySystem > _entitySystem
Entity system for handling entity-related operations.
void handlePlayerConnect(uint32_t sessionId)
Handle a new player connection.
void sendEntitySpawnToSessions(const ecs::Entity &entity, const std::vector< uint32_t > &sessions)
std::unique_ptr< AuthSystem > _authSystem
Authentication system for handling player logins.
Represents a game room in the server.
Definition Room.hpp:35
uint32_t getId(void) const
Get the unique identifier of the room.
Definition Room.cpp:219
@ InGame
Game in progress.
Definition Room.hpp:43
Implementation ASIO du serveur réseau (TCP + UDP)
void sendPacket(uint32_t sessionId, const net::Packet &packet, net::NetworkMode mode)
Send a packet to a specific session.
std::optional< net::NetworkEvent > pollEvent(void) override
Poll for a network event.
void broadcastPacket(const net::Packet &packet, net::NetworkMode mode)
Broadcast a packet to all connected sessions.
File : Network.hpp License: MIT Author : Elias Josué HAJJAR LLAUQUEN elias-josue.hajjar-llauquen@epit...
WeaponKind
Types of player weapons.
constexpr Entity NullEntity
Definition Entity.hpp:109
void error(LogFmt< std::type_identity_t< Args >... > fmt, Args &&...args) noexcept
Log an error message.
void warning(LogFmt< std::type_identity_t< Args >... > fmt, Args &&...args) noexcept
Log a warning message.
void info(LogFmt< std::type_identity_t< Args >... > fmt, Args &&...args) noexcept
Log an informational message.
void debug(LogFmt< std::type_identity_t< Args >... > fmt, Args &&...args) noexcept
Log a debug message.
@ Private
Private room.
@ DebugModeUpdate
Debug mode toggle.
@ LoginRequest
Client login request.
@ Disconnect
Disconnect notification.
@ RoomChatReceived
Chat message received in room.
@ LeaveRoom
Request to leave a room.
@ Pong
Ping response.
@ StartGame
Notification to start the game.
@ CreateRoom
Request to create a room.
@ HealthUpdate
Player health update.
@ EntitySpawn
Entity spawn notification.
@ ScoreUpdate
Player score update.
@ Kicked
Player kicked notification.
@ EntityDeath
Entity death notification.
File : GameManager.hpp License: MIT Author : Elias Josué HAJJAR LLAUQUEN elias-josue....
void startGame(Room &room)
std::shared_ptr< Player > PlayerPtr
Shared pointer type for Player.
Definition Player.hpp:178
Ammo tracking for weapons.
Definition Ammo.hpp:18
Marks a projectile as a boomerang and stores state for return logic.
Definition Boomerang.hpp:16
Component representing damage value.
Definition Damage.hpp:16
Component for double fire powerup.
Component representing an entity's health.
Definition Health.hpp:15
Marks an entity as homing and provides tuning parameters.
Definition Homing.hpp:17
Component representing a movement pattern.
Component representing movement speed with temporary boosts.
Component representing a network identifier for an entity.
Definition NetworkId.hpp:22
Component representing a powerup pickup.
Definition Powerup.hpp:27
Component representing a network identifier for an entity.
Definition RoomId.hpp:22
Component representing a shield that absorbs damage.
Definition Shield.hpp:16
Component representing a weapon configuration.
Component representing position, rotation, and scale of an entity.
Definition Transform.hpp:23
Component representing a 2D velocity.
Definition Velocity.hpp:17
Component to handle network input for server entities.
Data for creating a new room Client OpCode.
Definition Packet.hpp:264
uint32_t seed
Seed for random generation.
Definition Packet.hpp:270
uint32_t duration
Duration of the game session.
Definition Packet.hpp:271
float difficulty
Difficulty level.
Definition Packet.hpp:267
uint32_t maxPlayers
Maximum number of players.
Definition Packet.hpp:266
uint8_t roomType
Room type (public/private)
Definition Packet.hpp:272
char roomName[64]
Desired room name.
Definition Packet.hpp:265
float speed
Speed multiplier.
Definition Packet.hpp:268
uint32_t levelId
Level identifier.
Definition Packet.hpp:269
Debug mode toggle data Server OpCode.
Definition Packet.hpp:436
Entity death notification data.
Definition Packet.hpp:362
uint32_t netId
Network entity identifier.
Definition Packet.hpp:363
Entity spawn notification data.
Definition Packet.hpp:348
OpCode opCode
Operation code.
Definition Packet.hpp:135
Player health update data.
Definition Packet.hpp:415
Data for joining an existing room Client OpCode.
Definition Packet.hpp:281
uint8_t isSpectator
1 if joining as spectator
Definition Packet.hpp:283
uint32_t roomId
Room identifier to join.
Definition Packet.hpp:282
Ping request/response payload Client/Server /Pong OpCodes.
Definition Packet.hpp:426
Data for sending chat messages in a room Client OpCode.
Definition Packet.hpp:316
char message[256]
Chat message content.
Definition Packet.hpp:317
Data for receiving chat messages in a room Server OpCode.
Definition Packet.hpp:326
uint32_t sessionId
Sender's session identifier.
Definition Packet.hpp:327
Player score update notification data.
Definition Packet.hpp:397
Data for setting player readiness status Client OpCode.
Definition Packet.hpp:306
uint8_t isReady
Player readiness status.
Definition Packet.hpp:307