R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
RoomManager.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** Created by hugo on 06/12/2025
4** File description:
5** RoomManager.cpp
6*/
7
10
11namespace server {
12
14 : _matchmaking(std::make_shared<MatchmakingService>(2, 4, nullptr)), _eventBus(nullptr) {
15 _matchmaking->setMatchCreatedCallback([this](std::shared_ptr<Room> room) { _onMatchCreated(room); });
16 LOG_INFO("RoomManager created with matchmaking service");
17 }
18
19 RoomManager::RoomManager(std::shared_ptr<MatchmakingService> matchmaking,
20 std::shared_ptr<EventBus> eventBus)
21 : _matchmaking(matchmaking), _eventBus(eventBus) {
22 if (_matchmaking) {
23 _matchmaking->setMatchCreatedCallback(
24 [this](std::shared_ptr<Room> room) { _onMatchCreated(room); });
25 }
26 LOG_INFO("RoomManager created with provided matchmaking service");
27 }
28
29 void RoomManager::addPlayerToMatchmaking(uint32_t playerId) {
30 if (!_matchmaking) {
31 LOG_ERROR("Cannot add player to matchmaking - service not initialized");
32 return;
33 }
34
35 _matchmaking->addPlayer(playerId);
36 LOG_INFO("Player ", playerId, " added to matchmaking (queue size: ", _matchmaking->getQueueSize(),
37 ")");
38 }
39
41 if (!_matchmaking) {
42 return;
43 }
44
45 _matchmaking->removePlayer(playerId);
46 LOG_INFO("Player ", playerId, " removed from matchmaking");
47 }
48
49 std::shared_ptr<Room> RoomManager::createRoom(const std::string &id, const std::string &name,
50 size_t maxPlayers, bool isPrivate,
51 float gameSpeedMultiplier) {
52 std::lock_guard<std::recursive_mutex> lock(_mutex);
53
54 if (_rooms.find(id) != _rooms.end()) {
55 LOG_WARNING("Room ", id, " already exists");
56 return _rooms[id];
57 }
58
59 try {
60 auto room =
61 std::make_shared<Room>(id, name, maxPlayers, isPrivate, gameSpeedMultiplier, _eventBus);
62 _rooms[id] = room;
63
64 LOG_INFO("✓ Room created: '", room->getName(), "' (", id, ")");
65 return room;
66 } catch (const std::exception &e) {
67 LOG_ERROR("Failed to create room '", name, "' (", id, "): ", e.what());
68 return nullptr;
69 }
70 }
71
72 std::shared_ptr<Room> RoomManager::getRoom(const std::string &id) {
73 std::lock_guard<std::recursive_mutex> lock(_mutex);
74
75 auto it = _rooms.find(id);
76 if (it != _rooms.end()) {
77 return it->second;
78 }
79
80 return nullptr;
81 }
82
83 bool RoomManager::removeRoom(const std::string &id) {
84 std::lock_guard<std::recursive_mutex> lock(_mutex);
85
86 auto it = _rooms.find(id);
87 if (it != _rooms.end()) {
88 LOG_INFO("✓ Room removed: ", id);
89 _rooms.erase(it);
90 return true;
91 }
92
93 return false;
94 }
95
96 std::vector<std::shared_ptr<Room>> RoomManager::getAllRooms() {
97 std::lock_guard<std::recursive_mutex> lock(_mutex);
98
99 std::vector<std::shared_ptr<Room>> rooms;
100 rooms.reserve(_rooms.size());
101
102 for (const auto &[id, room] : _rooms) {
103 rooms.push_back(room);
104 }
105
106 return rooms;
107 }
108
109 std::vector<std::shared_ptr<Room>> RoomManager::getPublicRooms() {
110 std::lock_guard<std::recursive_mutex> lock(_mutex);
111
112 std::vector<std::shared_ptr<Room>> publicRooms;
113
114 for (const auto &[id, room] : _rooms) {
115 auto info = room->getInfo();
116 if (!info.isPrivate && info.state != RoomState::FINISHED) {
117 publicRooms.push_back(room);
118 }
119 }
120
121 return publicRooms;
122 }
123
125 std::lock_guard<std::recursive_mutex> lock(_mutex);
126 return _rooms.size();
127 }
128
129 bool RoomManager::update(float deltaTime) {
130 if (_matchmaking) {
131 _matchmaking->tick();
132 }
133
134 std::lock_guard<std::recursive_mutex> lock(_mutex);
135 for (auto &[id, room] : _rooms) {
136 room->update(deltaTime);
137 }
138
139 std::vector<std::string> roomsToRemove;
140 for (const auto &[id, room] : _rooms) {
141 if (room->getState() == RoomState::FINISHED && room->getPlayerCount() == 0) {
142 roomsToRemove.push_back(id);
143 }
144 }
145
146 for (const auto &id : roomsToRemove) {
147 _rooms.erase(id);
148 LOG_INFO("Cleaned up finished room: ", id);
149 }
150
151 if (!roomsToRemove.empty()) {
152 LOG_INFO("Cleaned up ", roomsToRemove.size(), " finished room(s)");
153 return true;
154 }
155
156 return false;
157 }
158
159 std::shared_ptr<Room> RoomManager::getRoomByPlayer(uint32_t playerId) {
160 std::lock_guard lock(_mutex);
161
162 for (const auto &[id, room] : _rooms) {
163 if (room->hasPlayer(playerId) || room->hasSpectator(playerId)) {
164 return room;
165 }
166 }
167
168 return nullptr;
169 }
170
172 std::lock_guard<std::recursive_mutex> lock(_mutex);
173
174 std::vector<std::string> roomsToRemove;
175
176 for (const auto &[id, room] : _rooms) {
177 if (room->getState() == RoomState::FINISHED && room->getPlayerCount() == 0) {
178 roomsToRemove.push_back(id);
179 }
180 }
181
182 for (const auto &id : roomsToRemove) {
183 _rooms.erase(id);
184 LOG_INFO("Cleaned up finished room: ", id);
185 }
186
187 if (!roomsToRemove.empty()) {
188 LOG_INFO("Cleaned up ", roomsToRemove.size(), " finished room(s)");
189 }
190 }
191
192 void RoomManager::_onMatchCreated(std::shared_ptr<Room> room) {
193 // Store callback and room outside the lock to avoid deadlock
194 // (callback may call getPublicRooms() which acquires the same mutex)
195 std::function<void(std::shared_ptr<Room>)> callback;
196
197 {
198 std::lock_guard<std::recursive_mutex> lock(_mutex);
199
200 std::string roomId = room->getId();
201
202 if (_rooms.find(roomId) != _rooms.end()) {
203 LOG_WARNING("Match room ", roomId, " already exists");
204 return;
205 }
206
207 _rooms[roomId] = room;
208 LOG_INFO("✓ Match room registered: ", roomId, " (", room->getPlayerCount(), " players)");
209 room->setState(RoomState::STARTING);
210
211 callback = _roomCreatedCallback;
212 }
213
214 // Invoke callback outside the lock to prevent deadlock
215 if (callback) {
216 callback(room);
217 }
218 }
219
220} // namespace server
#define LOG_INFO(...)
Definition Logger.hpp:181
#define LOG_ERROR(...)
Definition Logger.hpp:183
#define LOG_WARNING(...)
Definition Logger.hpp:182
Automatic matchmaking service.
std::shared_ptr< Room > createRoom(const std::string &id, const std::string &name="", size_t maxPlayers=4, bool isPrivate=false, float gameSpeedMultiplier=1.0f) override
Create a new room.
bool update(float deltaTime) override
Update all rooms (called by server loop)
std::shared_ptr< Room > getRoom(const std::string &id) override
Retrieve a room by ID.
RoomCreatedCallback _roomCreatedCallback
std::vector< std::shared_ptr< Room > > getAllRooms() override
Get all active rooms.
void removePlayerFromMatchmaking(uint32_t playerId)
Remove player from matchmaking queue.
void cleanupFinishedRooms()
Clean up finished rooms Removes rooms that are in FINISHED state and have no players.
std::shared_ptr< MatchmakingService > _matchmaking
bool removeRoom(const std::string &id) override
Remove a room by ID.
std::recursive_mutex _mutex
size_t getRoomCount() const override
Get number of active rooms.
std::shared_ptr< EventBus > _eventBus
std::shared_ptr< Room > getRoomByPlayer(uint32_t playerId)
Get room by player ID (find which room a player is in)
std::vector< std::shared_ptr< Room > > getPublicRooms() override
Get all public rooms (not private)
void addPlayerToMatchmaking(uint32_t playerId)
Add player to matchmaking queue.
void _onMatchCreated(std::shared_ptr< Room > room)
Handle match created by matchmaking service.
std::unordered_map< std::string, std::shared_ptr< Room > > _rooms