1 #include "RoomsContainer.h"
2 #include "ProfanityFilter.h"
3 #include "RakAssert.h"
4 #include "GetTime.h"
5 #include "BitStream.h"
6 #include "TableSerializer.h"
7
8 static const RakNetTime MINIMUM_QUICK_JOIN_TIMEOUT=5000;
9 static const RakNetTime MAXIMUM_QUICK_JOIN_TIMEOUT=60000 * 5;
10 static const int MAX_CUSTOM_QUERY_FIELDS=50;
11 static const RakNetTime PROCESS_QUICK_JOINS_INTERVAL=1000;
12 #define QUICK_JOIN_ROOM_NAME "Quick Join "
13
14
15 using namespace RakNet;
16
17 DataStructures::Table::FilterQuery RoomQuery::fq[32];
18 DataStructures::Table::Cell RoomQuery::cells[32];
19
RoomsSortByName(Room * const & key,Room * const & data)20 int AllGamesRoomsContainer::RoomsSortByName( Room* const &key, Room* const &data )
21 {
22 return strcmp(key->GetStringProperty(DefaultRoomColumns::TC_ROOM_NAME),data->GetStringProperty(DefaultRoomColumns::TC_ROOM_NAME));
23 }
24
25 // ---------------------------- QuickJoinMember ----------------------------
26
QuickJoinUser()27 QuickJoinUser::QuickJoinUser()
28 {
29 networkedQuickJoinUser.query.queries=0;
30 totalTimeWaiting=0;
31 }
~QuickJoinUser()32 QuickJoinUser::~QuickJoinUser()
33 {
34 }
35
SortByTotalTimeWaiting(QuickJoinUser * const & key,QuickJoinUser * const & data)36 int QuickJoinUser::SortByTotalTimeWaiting( QuickJoinUser* const &key, QuickJoinUser* const &data )
37 {
38 if (key->totalTimeWaiting > data->totalTimeWaiting)
39 return -1;
40 if (key->totalTimeWaiting < data->totalTimeWaiting)
41 return 1;
42 if (key->networkedQuickJoinUser.minimumPlayers > data->networkedQuickJoinUser.minimumPlayers)
43 return -1;
44 if (key->networkedQuickJoinUser.minimumPlayers < data->networkedQuickJoinUser.minimumPlayers)
45 return 1;
46 if (key->networkedQuickJoinUser.timeout < data->networkedQuickJoinUser.timeout)
47 return -1;
48 if (key->networkedQuickJoinUser.timeout > data->networkedQuickJoinUser.timeout)
49 return 1;
50 if (key < data)
51 return -1;
52 return -1;
53 }
SortByMinimumSlots(QuickJoinUser * const & key,QuickJoinUser * const & data)54 int QuickJoinUser::SortByMinimumSlots( QuickJoinUser* const &key, QuickJoinUser* const &data )
55 {
56 if (key->networkedQuickJoinUser.minimumPlayers > data->networkedQuickJoinUser.minimumPlayers)
57 return -1;
58 if (key->networkedQuickJoinUser.minimumPlayers < data->networkedQuickJoinUser.minimumPlayers)
59 return 1;
60 if (key->totalTimeWaiting > data->totalTimeWaiting)
61 return -1;
62 if (key->totalTimeWaiting < data->totalTimeWaiting)
63 return 1;
64 if (key->networkedQuickJoinUser.timeout < data->networkedQuickJoinUser.timeout)
65 return -1;
66 if (key->networkedQuickJoinUser.timeout > data->networkedQuickJoinUser.timeout)
67 return 1;
68 if (key < data)
69 return -1;
70 return -1;
71 }
Serialize(bool writeToBitstream,RakNet::BitStream * bitStream)72 void NetworkedQuickJoinUser::Serialize(bool writeToBitstream, RakNet::BitStream *bitStream)
73 {
74 query.Serialize(writeToBitstream, bitStream);
75 bitStream->Serialize(writeToBitstream,timeout);
76 bitStream->Serialize(writeToBitstream,query);
77 }
78 // ---------------------------- RoomMember ----------------------------
79
RoomMember()80 RoomMember::RoomMember() {isReady=false; newMemberNotificationProcessed=false; joinTime=0; roomMemberMode=RMM_PUBLIC; roomsParticipant=0;}
~RoomMember()81 RoomMember::~RoomMember() {}
82
83 // ---------------------------- Slots ----------------------------
84
Slots()85 Slots::Slots() {publicSlots=reservedSlots=spectatorSlots=0;}
~Slots()86 Slots::~Slots() {}
Validate(void) const87 RoomsErrorCode Slots::Validate(void) const
88 {
89 if (publicSlots+reservedSlots < 1)
90 return REC_SLOTS_VALIDATION_NO_PLAYABLE_SLOTS;
91 if (publicSlots<0)
92 return REC_SLOTS_VALIDATION_NEGATIVE_PUBLIC_SLOTS;
93 if (reservedSlots<0)
94 return REC_SLOTS_VALIDATION_NEGATIVE_RESERVED_SLOTS;
95 if (spectatorSlots<0)
96 return REC_SLOTS_VALIDATION_NEGATIVE_SPECTATOR_SLOTS;
97 return REC_SUCCESS;
98 }
Serialize(bool writeToBitstream,RakNet::BitStream * bitStream)99 void Slots::Serialize(bool writeToBitstream, RakNet::BitStream *bitStream)
100 {
101 bitStream->Serialize(writeToBitstream,publicSlots);
102 bitStream->Serialize(writeToBitstream,reservedSlots);
103 bitStream->Serialize(writeToBitstream,spectatorSlots);
104 }
105 // ---------------------------- InvitedUser ----------------------------
Serialize(bool writeToBitstream,RakNet::BitStream * bitStream)106 void InvitedUser::Serialize(bool writeToBitstream, RakNet::BitStream *bitStream)
107 {
108 if (room)
109 roomId=room->GetID();
110 bitStream->Serialize(writeToBitstream,roomId);
111 bitStream->Serialize(writeToBitstream,invitorName);
112 bitStream->Serialize(writeToBitstream,invitorSystemAddress);
113 bitStream->Serialize(writeToBitstream,target);
114 bitStream->Serialize(writeToBitstream,subject);
115 bitStream->Serialize(writeToBitstream,body);
116 bitStream->Serialize(writeToBitstream,invitedAsSpectator);
117 }
118 // ---------------------------- BannedUser ----------------------------
Serialize(bool writeToBitstream,RakNet::BitStream * bitStream)119 void BannedUser::Serialize(bool writeToBitstream, RakNet::BitStream *bitStream)
120 {
121 bitStream->Serialize(writeToBitstream, target);
122 bitStream->Serialize(writeToBitstream, reason);
123 }
124 // ---------------------------- RoomMemberDescriptor ----------------------------
FromRoomMember(RoomMember * roomMember)125 void RoomMemberDescriptor::FromRoomMember(RoomMember *roomMember)
126 {
127 name=roomMember->roomsParticipant->GetName();
128 roomMemberMode=roomMember->roomMemberMode;
129 isReady=roomMember->isReady;
130 systemAddress=roomMember->roomsParticipant->GetSystemAddress();
131 guid=roomMember->roomsParticipant->GetGUID();
132 }
Serialize(bool writeToBitstream,RakNet::BitStream * bitStream)133 void RoomMemberDescriptor::Serialize(bool writeToBitstream, RakNet::BitStream *bitStream)
134 {
135 bitStream->Serialize(writeToBitstream, name);
136 bitStream->Serialize(writeToBitstream, roomMemberMode);
137 bitStream->Serialize(writeToBitstream, isReady);
138 bitStream->Serialize(writeToBitstream, systemAddress);
139 bitStream->Serialize(writeToBitstream, guid);
140 }
141 // ---------------------------- RemoveUserResult ----------------------------
142
RemoveUserResult()143 RemoveUserResult::RemoveUserResult()
144 {
145 removedFromQuickJoin=false;
146 removedFromRoom=false;
147 room=0;
148 gotNewModerator=false;
149 roomDestroyed=false;
150 }
151
~RemoveUserResult()152 RemoveUserResult::~RemoveUserResult()
153 {
154
155 }
156
Serialize(bool writeToBitstream,RakNet::BitStream * bitStream)157 void RemoveUserResult::Serialize(bool writeToBitstream, RakNet::BitStream *bitStream)
158 {
159 bitStream->Serialize(writeToBitstream,removedFromQuickJoin);
160 bitStream->Serialize(writeToBitstream,removedFromRoom);
161 if (room)
162 roomId=room->GetID();
163 bitStream->Serialize(writeToBitstream,roomId);
164 bitStream->Serialize(writeToBitstream,removedUserName);
165 bitStream->Serialize(writeToBitstream,removedUserAddress);
166 bitStream->Serialize(writeToBitstream,gotNewModerator);
167 bitStream->Serialize(writeToBitstream,roomDestroyed);
168 unsigned int clearedInvitationsSize=clearedInvitations.Size();
169 bitStream->Serialize(writeToBitstream,clearedInvitationsSize);
170 if (writeToBitstream==false)
171 {
172 clearedInvitations.Clear(false, __FILE__, __LINE__);
173 InvitedUser invitedUser;
174 for (unsigned i=0; i < clearedInvitationsSize; i++)
175 {
176 invitedUser.Serialize(writeToBitstream, bitStream);
177 clearedInvitations.Insert(invitedUser, __FILE__, __LINE__ );
178 }
179 }
180 }
181
182 // ---------------------------- JoinedRoomResult ----------------------------
183
Serialize(bool writeToBitstream,RakNet::BitStream * bitStream)184 void JoinedRoomResult::Serialize(bool writeToBitstream, RakNet::BitStream *bitStream)
185 {
186 if (acceptedInvitor)
187 {
188 acceptedInvitorName=acceptedInvitor->GetName();
189 acceptedInvitorAddress=acceptedInvitor->GetSystemAddress();
190 }
191 if (joiningMember)
192 {
193 joiningMemberName=joiningMember->GetName();
194 joiningMemberAddress=joiningMember->GetSystemAddress();
195 }
196 bitStream->Serialize(writeToBitstream, acceptedInvitorName);
197 bitStream->Serialize(writeToBitstream, joiningMemberName);
198 bitStream->Serialize(writeToBitstream, acceptedInvitorAddress);
199 bitStream->Serialize(writeToBitstream, joiningMemberAddress);
200 roomDescriptor.FromRoom(roomOutput, agrc);
201 roomDescriptor.Serialize(writeToBitstream, bitStream);
202
203 // if (writeToBitstream)
204 // RakAssert(roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_SLOTS)==roomOutput->roomMemberList.Size()-1);
205 }
206 // ---------------------------- RoomDescriptor ----------------------------
FromRoom(Room * room,AllGamesRoomsContainer * agrc)207 void RoomDescriptor::FromRoom(Room *room, AllGamesRoomsContainer *agrc)
208 {
209 if (room==0)
210 return;
211
212 Clear();
213
214 roomLockState=room->roomLockState;
215 lobbyRoomId=room->lobbyRoomId;
216 autoLockReadyStatus=room->autoLockReadyStatus;
217 hiddenFromSearches=room->hiddenFromSearches;
218 inviteToRoomPermission=room->inviteToRoomPermission;
219 inviteToSpectatorSlotPermission=room->inviteToSpectatorSlotPermission;
220 RoomMemberDescriptor rmd;
221 unsigned int i;
222 for (i=0; i < room->roomMemberList.Size(); i++)
223 {
224 rmd.FromRoomMember(room->roomMemberList[i]);
225 roomMemberList.Insert(rmd, __FILE__, __LINE__ );
226 }
227 for (i=0; i < room->banList.Size(); i++)
228 {
229 banList.Insert(room->banList[i], __FILE__, __LINE__ );
230 }
231
232 RakAssert(agrc);
233 if (agrc)
234 {
235 Room *r;
236 agrc->GetRoomProperties(room->GetID(), &r, &roomProperties);
237 }
238 }
Serialize(bool writeToBitstream,RakNet::BitStream * bitStream)239 void RoomDescriptor::Serialize(bool writeToBitstream, RakNet::BitStream *bitStream)
240 {
241 bitStream->Serialize(writeToBitstream, roomLockState);
242 bitStream->Serialize(writeToBitstream, lobbyRoomId);
243 bitStream->Serialize(writeToBitstream, autoLockReadyStatus);
244 bitStream->Serialize(writeToBitstream, hiddenFromSearches);
245 bitStream->Serialize(writeToBitstream, inviteToRoomPermission);
246 bitStream->Serialize(writeToBitstream, inviteToSpectatorSlotPermission);
247 unsigned int i;
248 unsigned int roomMemberListSize, banListSize;
249 roomMemberListSize=roomMemberList.Size();
250 bitStream->Serialize(writeToBitstream, roomMemberListSize);
251 for (i=0; i < roomMemberListSize; i++)
252 {
253 RoomMemberDescriptor rmd;
254 if (writeToBitstream==false)
255 {
256 rmd.Serialize(writeToBitstream, bitStream);
257 roomMemberList.Insert(rmd, __FILE__, __LINE__ );
258 }
259 else
260 roomMemberList[i].Serialize(writeToBitstream, bitStream);
261 }
262 banListSize=banList.Size();
263 bitStream->Serialize(writeToBitstream, banListSize);
264 for (i=0; i < banListSize; i++)
265 {
266 BannedUser bu;
267 if (writeToBitstream==false)
268 bu.Serialize(writeToBitstream, bitStream);
269 else
270 banList[i].Serialize(writeToBitstream, bitStream);
271 }
272 if (writeToBitstream)
273 TableSerializer::SerializeTable(&roomProperties, bitStream);
274 else
275 TableSerializer::DeserializeTable(bitStream, &roomProperties);
276 }
277 // ---------------------------- RoomQuery ----------------------------
278
Validate(void)279 RoomsErrorCode RoomQuery::Validate(void)
280 {
281 if (numQueries > DefaultRoomColumns::TC_TABLE_COLUMNS_COUNT+MAX_CUSTOM_QUERY_FIELDS)
282 return REC_ROOM_QUERY_TOO_MANY_QUERIES;
283 if (numQueries>0 && queries==0)
284 return REC_ROOM_QUERY_INVALID_QUERIES_POINTER;
285 return REC_SUCCESS;
286 }
Serialize(bool writeToBitstream,RakNet::BitStream * bitStream)287 void RoomQuery::Serialize(bool writeToBitstream, RakNet::BitStream *bitStream)
288 {
289 bool hasQuery = numQueries!=0;
290 bitStream->Serialize(writeToBitstream,hasQuery);
291 if (hasQuery)
292 {
293 bitStream->Serialize(writeToBitstream,numQueries);
294 unsigned int i;
295 for (i=0; i < numQueries; i++)
296 {
297 if (writeToBitstream)
298 TableSerializer::SerializeFilterQuery(bitStream, &queries[i]);
299 else
300 TableSerializer::DeserializeFilterQuery(bitStream, &queries[i]);
301 }
302 }
303 }
304 // ---------------------------- RoomCreationParameters ----------------------------
Serialize(bool writeToBitstream,RakNet::BitStream * bitStream)305 void NetworkedRoomCreationParameters::Serialize(bool writeToBitstream, RakNet::BitStream *bitStream)
306 {
307 slots.Serialize(writeToBitstream, bitStream);
308 bitStream->Serialize(writeToBitstream,hiddenFromSearches);
309 bitStream->Serialize(writeToBitstream,destroyOnModeratorLeave);
310 bitStream->Serialize(writeToBitstream,autoLockReadyStatus);
311 bitStream->Serialize(writeToBitstream,inviteToRoomPermission);
312 bitStream->Serialize(writeToBitstream,inviteToSpectatorSlotPermission);
313 bitStream->Serialize(writeToBitstream,clearInvitesOnNewModerator);
314 bitStream->Serialize(writeToBitstream,roomName);
315 }
316
SendInvitePermissionToEnum(SendInvitePermission e)317 const char *NetworkedRoomCreationParameters::SendInvitePermissionToEnum(SendInvitePermission e)
318 {
319 switch (e)
320 {
321 case INVITE_MODE_ANYONE_CAN_INVITE:
322 return "INVITE_MODE_ANYONE_CAN_INVITE";
323 case INVITE_MODE_MODERATOR_CAN_INVITE:
324 return "INVITE_MODE_MODERATOR_CAN_INVITE";
325 case INVITE_MODE_PUBLIC_SLOTS_CAN_INVITE:
326 return "INVITE_MODE_PUBLIC_SLOTS_CAN_INVITE";
327 case INVITE_MODE_RESERVED_SLOTS_CAN_INVITE:
328 return "INVITE_MODE_RESERVED_SLOTS_CAN_INVITE";
329 case INVITE_MODE_SPECTATOR_SLOTS_CAN_INVITE:
330 return "INVITE_MODE_SPECTATOR_SLOTS_CAN_INVITE";
331 case INVITE_MODE_MODERATOR_OR_PUBLIC_SLOTS_CAN_INVITE:
332 return "INVITE_MODE_MODERATOR_OR_PUBLIC_SLOTS_CAN_INVITE";
333 case INVITE_MODE_MODERATOR_OR_PUBLIC_OR_RESERVED_SLOTS_CAN_INVITE:
334 return "INVITE_MODE_MODERATOR_OR_PUBLIC_OR_RESERVED_SLOTS_CAN_INVITE";
335 }
336 return "Error in NetworkedRoomCreationParameters::SendInvitePermissionToEnum";
337 }
RoomCreationParameters()338 RoomCreationParameters::RoomCreationParameters()
339 {
340 networkedRoomCreationParameters.hiddenFromSearches=false;
341 networkedRoomCreationParameters.destroyOnModeratorLeave=false;
342 firstUser=0;
343 createdRoom=false;
344 roomOutput=0;
345 networkedRoomCreationParameters.inviteToRoomPermission=NetworkedRoomCreationParameters::INVITE_MODE_ANYONE_CAN_INVITE;
346 networkedRoomCreationParameters.inviteToSpectatorSlotPermission=NetworkedRoomCreationParameters::INVITE_MODE_ANYONE_CAN_INVITE;
347 networkedRoomCreationParameters.clearInvitesOnNewModerator=false;
348 }
~RoomCreationParameters()349 RoomCreationParameters::~RoomCreationParameters()
350 {
351
352 }
Validate(const DataStructures::List<RakNet::RakString> & otherRoomNames,ProfanityFilter * profanityFilter) const353 RoomsErrorCode RoomCreationParameters::Validate(const DataStructures::List<RakNet::RakString> &otherRoomNames,
354 ProfanityFilter *profanityFilter) const
355 {
356 static size_t QUICK_JOIN_ROOM_NAME_LENGTH = strlen(QUICK_JOIN_ROOM_NAME);
357 if (networkedRoomCreationParameters.roomName.IsEmpty())
358 return REC_ROOM_CREATION_PARAMETERS_EMPTY_ROOM_NAME;
359 if (profanityFilter && profanityFilter->HasProfanity(networkedRoomCreationParameters.roomName.C_String()))
360 return REC_ROOM_CREATION_PARAMETERS_ROOM_NAME_HAS_PROFANITY;
361 if (otherRoomNames.GetIndexOf(networkedRoomCreationParameters.roomName)!=(unsigned)-1)
362 return REC_ROOM_CREATION_PARAMETERS_ROOM_NAME_IN_USE;
363 if (networkedRoomCreationParameters.slots.publicSlots+networkedRoomCreationParameters.slots.reservedSlots<1)
364 return REC_ROOM_CREATION_PARAMETERS_NO_PLAYABLE_SLOTS;
365 if (networkedRoomCreationParameters.roomName.SubStr(0,(unsigned int) QUICK_JOIN_ROOM_NAME_LENGTH)==QUICK_JOIN_ROOM_NAME)
366 return REC_ROOM_CREATION_PARAMETERS_RESERVED_QUICK_JOIN_ROOM_NAME;
367 return REC_SUCCESS;
368 }
369
370 // ---------------------------- RoomQuery ----------------------------
371
RoomQuery()372 RoomQuery::RoomQuery() {queries=0; numQueries=0; queriesAllocated=false; SetQueriesToStatic();}
~RoomQuery()373 RoomQuery::~RoomQuery() {}
AddQuery_NUMERIC(const char * columnName,double numericValue,DataStructures::Table::FilterQueryType op)374 void RoomQuery::AddQuery_NUMERIC(const char *columnName, double numericValue, DataStructures::Table::FilterQueryType op)
375 {
376 SetupNextQuery(columnName,op);
377 cells[numQueries].Set(numericValue);
378 numQueries++;
379 }
AddQuery_STRING(const char * columnName,const char * charValue,DataStructures::Table::FilterQueryType op)380 void RoomQuery::AddQuery_STRING(const char *columnName, const char *charValue, DataStructures::Table::FilterQueryType op)
381 {
382 if (charValue==0 || charValue[0]==0)
383 return;
384
385 SetupNextQuery(columnName,op);
386 cells[numQueries].Set(charValue);
387 numQueries++;
388 }
AddQuery_BINARY(const char * columnName,const char * input,int inputLength,DataStructures::Table::FilterQueryType op)389 void RoomQuery::AddQuery_BINARY(const char *columnName, const char *input, int inputLength, DataStructures::Table::FilterQueryType op)
390 {
391 if (input==0 || input[0]==0 || inputLength==0)
392 return;
393 SetupNextQuery(columnName,op);
394 cells[numQueries].Set(input, inputLength);
395 numQueries++;
396 }
AddQuery_POINTER(const char * columnName,void * ptr,DataStructures::Table::FilterQueryType op)397 void RoomQuery::AddQuery_POINTER(const char *columnName, void *ptr, DataStructures::Table::FilterQueryType op)
398 {
399 SetupNextQuery(columnName,op);
400 cells[numQueries].SetPtr(ptr);
401 numQueries++;
402 }
SetupNextQuery(const char * columnName,DataStructures::Table::FilterQueryType op)403 void RoomQuery::SetupNextQuery(const char *columnName,DataStructures::Table::FilterQueryType op)
404 {
405 queries=(DataStructures::Table::FilterQuery *)fq;
406 fq[numQueries].cellValue=&cells[numQueries];
407 strcpy(fq[numQueries].columnName, columnName);
408 fq[numQueries].operation=op;
409 }
SetQueriesToStatic(void)410 void RoomQuery::SetQueriesToStatic(void)
411 {
412 queries = (DataStructures::Table::FilterQuery *)fq;
413 for (int i=0; i < 32; i++)
414 {
415 fq[i].cellValue=&cells[i];
416 }
417 }
418 // ---------------------------- AllGamesRoomsContainer ----------------------------
419
AllGamesRoomsContainer()420 AllGamesRoomsContainer::AllGamesRoomsContainer()
421 {
422 DataStructures::Map<GameIdentifier, PerGameRoomsContainer*>::IMPLEMENT_DEFAULT_COMPARISON();
423 nextRoomId=0;
424 }
~AllGamesRoomsContainer()425 AllGamesRoomsContainer::~AllGamesRoomsContainer()
426 {
427
428 }
CreateRoom(RoomCreationParameters * roomCreationParameters,ProfanityFilter * profanityFilter)429 RoomsErrorCode AllGamesRoomsContainer::CreateRoom(RoomCreationParameters *roomCreationParameters,
430 ProfanityFilter *profanityFilter)
431 {
432 if (roomCreationParameters->firstUser->GetRoom())
433 return REC_CREATE_ROOM_CURRENTLY_IN_A_ROOM;
434 else if (roomCreationParameters->firstUser->GetInQuickJoin())
435 return REC_CREATE_ROOM_CURRENTLY_IN_QUICK_JOIN;
436
437 if (perGamesRoomsContainers.Has(roomCreationParameters->gameIdentifier)==false)
438 return REC_CREATE_ROOM_UNKNOWN_TITLE;
439 PerGameRoomsContainer *perGameRoomsContainer = perGamesRoomsContainers.Get(roomCreationParameters->gameIdentifier);
440 RoomsErrorCode roomsErrorCode = perGameRoomsContainer->CreateRoom(roomCreationParameters,profanityFilter,++nextRoomId, true);
441 if (roomsErrorCode!=REC_SUCCESS)
442 nextRoomId--;
443 return roomsErrorCode;
444 }
EnterRoom(RoomCreationParameters * roomCreationParameters,RoomMemberMode roomMemberMode,ProfanityFilter * profanityFilter,RoomQuery * query,JoinedRoomResult * joinRoomResult)445 RoomsErrorCode AllGamesRoomsContainer::EnterRoom(RoomCreationParameters *roomCreationParameters,
446 RoomMemberMode roomMemberMode,
447 ProfanityFilter *profanityFilter,
448 RoomQuery *query,
449 JoinedRoomResult *joinRoomResult)
450 {
451 roomCreationParameters->roomOutput=0;
452 joinRoomResult->roomOutput=0;
453 joinRoomResult->agrc=this;
454 if (roomCreationParameters->firstUser->GetRoom())
455 return REC_ENTER_ROOM_CURRENTLY_IN_A_ROOM;
456 else if (roomCreationParameters->firstUser->GetInQuickJoin())
457 return REC_ENTER_ROOM_CURRENTLY_IN_QUICK_JOIN;
458 roomCreationParameters->createdRoom=false;
459 if (perGamesRoomsContainers.Has(roomCreationParameters->gameIdentifier)==false)
460 return REC_ENTER_ROOM_UNKNOWN_TITLE;
461 PerGameRoomsContainer *perGameRoomsContainer = perGamesRoomsContainers.Get(roomCreationParameters->gameIdentifier);
462 RoomsErrorCode roomsErrorCode = perGameRoomsContainer->JoinByFilter(roomMemberMode, roomCreationParameters->firstUser, (RakNet::RoomID) -1, query, joinRoomResult);
463
464 // Redundant, rooms plugin does this anyway
465 // if (roomsErrorCode==REC_SUCCESS)
466 // joinRoomResult->roomDescriptor.FromRoom(joinRoomResult->roomOutput, this);
467
468 if (roomsErrorCode != REC_JOIN_BY_FILTER_NO_ROOMS || roomsErrorCode==REC_SUCCESS)
469 return roomsErrorCode;
470 roomsErrorCode = perGameRoomsContainer->CreateRoom(roomCreationParameters,profanityFilter,++nextRoomId, true);
471 if (roomsErrorCode!=REC_SUCCESS)
472 {
473 nextRoomId--;
474 }
475 else
476 {
477 roomCreationParameters->createdRoom=true;
478 }
479 return roomsErrorCode;
480 }
JoinByFilter(GameIdentifier gameIdentifier,RoomMemberMode roomMemberMode,RoomsParticipant * roomsParticipant,RoomID lastRoomJoined,RoomQuery * query,JoinedRoomResult * joinRoomResult)481 RoomsErrorCode AllGamesRoomsContainer::JoinByFilter(GameIdentifier gameIdentifier, RoomMemberMode roomMemberMode, RoomsParticipant* roomsParticipant, RoomID lastRoomJoined, RoomQuery *query, JoinedRoomResult *joinRoomResult)
482 {
483 (void) lastRoomJoined;
484
485 if (roomsParticipant->GetRoom())
486 return REC_JOIN_BY_FILTER_CURRENTLY_IN_A_ROOM;
487 else if (roomsParticipant->GetInQuickJoin())
488 return REC_JOIN_BY_FILTER_CURRENTLY_IN_QUICK_JOIN;
489
490 if (perGamesRoomsContainers.Has(gameIdentifier)==false)
491 {
492 joinRoomResult->roomOutput=0;
493 return REC_JOIN_BY_FILTER_UNKNOWN_TITLE;
494 }
495 PerGameRoomsContainer *perGameRoomsContainer = perGamesRoomsContainers.Get(gameIdentifier);
496 joinRoomResult->agrc=this;
497 RoomsErrorCode rec = perGameRoomsContainer->JoinByFilter(roomMemberMode, roomsParticipant, (RakNet::RoomID) -1, query, joinRoomResult);
498 joinRoomResult->roomDescriptor.FromRoom(joinRoomResult->roomOutput, this);
499 return rec;
500 }
LeaveRoom(RoomsParticipant * roomsParticipant,RemoveUserResult * removeUserResult)501 RoomsErrorCode AllGamesRoomsContainer::LeaveRoom(RoomsParticipant* roomsParticipant, RemoveUserResult *removeUserResult)
502 {
503 if (roomsParticipant->GetRoom()==false)
504 return REC_LEAVE_ROOM_NOT_IN_ROOM;
505 else if (roomsParticipant->GetInQuickJoin())
506 return REC_LEAVE_ROOM_CURRENTLY_IN_QUICK_JOIN;
507
508 RoomsErrorCode roomsErrorCode = roomsParticipant->GetRoom()->RemoveUser(roomsParticipant, removeUserResult);
509 return roomsErrorCode;
510 }
511
AddUserToQuickJoin(GameIdentifier gameIdentifier,QuickJoinUser * quickJoinMember)512 RoomsErrorCode AllGamesRoomsContainer::AddUserToQuickJoin(GameIdentifier gameIdentifier, QuickJoinUser *quickJoinMember)
513 {
514 if (quickJoinMember->roomsParticipant->GetRoom())
515 return REC_ADD_TO_QUICK_JOIN_CURRENTLY_IN_A_ROOM;
516 else if (quickJoinMember->roomsParticipant->GetInQuickJoin())
517 return REC_ADD_TO_QUICK_JOIN_ALREADY_THERE;
518
519 if (perGamesRoomsContainers.Has(gameIdentifier)==false)
520 return REC_ADD_TO_QUICK_JOIN_UNKNOWN_TITLE;
521 if (quickJoinMember->networkedQuickJoinUser.timeout < MINIMUM_QUICK_JOIN_TIMEOUT)
522 return REC_ADD_TO_QUICK_JOIN_INVALID_TIMEOUT_TOO_LOW;
523 if (quickJoinMember->networkedQuickJoinUser.timeout > MAXIMUM_QUICK_JOIN_TIMEOUT)
524 return REC_ADD_TO_QUICK_JOIN_INVALID_TIMEOUT_TOO_HIGH;
525 if (quickJoinMember->networkedQuickJoinUser.minimumPlayers<2)
526 return REC_ADD_TO_QUICK_JOIN_MINIMUM_SLOTS_TOO_LOW;
527 if (quickJoinMember->networkedQuickJoinUser.minimumPlayers>5000) // Pretty arbitrary, but who would have this many members in a room?
528 return REC_ADD_TO_QUICK_JOIN_MINIMUM_SLOTS_TOO_HIGH;
529 return perGamesRoomsContainers.Get(gameIdentifier)->AddUserToQuickJoin(quickJoinMember);
530 }
RemoveUserFromQuickJoin(RoomsParticipant * roomsParticipant,QuickJoinUser ** qju)531 RoomsErrorCode AllGamesRoomsContainer::RemoveUserFromQuickJoin(RoomsParticipant* roomsParticipant, QuickJoinUser **qju)
532 {
533 RoomsErrorCode roomsErrorCode;
534 unsigned int i;
535 for (i=0; i < perGamesRoomsContainers.Size(); i++)
536 {
537 roomsErrorCode = perGamesRoomsContainers[i]->RemoveUserFromQuickJoin(roomsParticipant, qju);
538 if (roomsErrorCode!=REC_REMOVE_FROM_QUICK_JOIN_NOT_THERE)
539 return roomsErrorCode;
540 }
541 return REC_REMOVE_FROM_QUICK_JOIN_NOT_THERE;
542 }
IsInQuickJoin(RoomsParticipant * roomsParticipant)543 bool AllGamesRoomsContainer::IsInQuickJoin(RoomsParticipant* roomsParticipant)
544 {
545 unsigned int i;
546 for (i=0; i < perGamesRoomsContainers.Size(); i++)
547 if (perGamesRoomsContainers[i]->IsInQuickJoin(roomsParticipant))
548 return true;
549 return false;
550 }
SearchByFilter(GameIdentifier gameIdentifier,RoomsParticipant * roomsParticipant,RoomQuery * roomQuery,DataStructures::OrderedList<Room *,Room *,RoomsSortByName> & roomsOutput,bool onlyJoinable)551 RoomsErrorCode AllGamesRoomsContainer::SearchByFilter( GameIdentifier gameIdentifier, RoomsParticipant* roomsParticipant, RoomQuery *roomQuery, DataStructures::OrderedList<Room*, Room*, RoomsSortByName> &roomsOutput, bool onlyJoinable )
552 {
553 roomsOutput.Clear(false, __FILE__, __LINE__);
554 if (perGamesRoomsContainers.Has(gameIdentifier)==false)
555 return REC_SEARCH_BY_FILTER_UNKNOWN_TITLE;
556 PerGameRoomsContainer *perGameRoomsContainer = perGamesRoomsContainers.Get(gameIdentifier);
557 return perGameRoomsContainer->SearchByFilter(roomsParticipant, roomQuery, roomsOutput, onlyJoinable);
558 }
DestroyRoomIfDead(Room * room)559 void AllGamesRoomsContainer::DestroyRoomIfDead(Room *room)
560 {
561 if (room==0 || room->IsRoomDead()==false)
562 return;
563 unsigned int i;
564 for (i=0; i < perGamesRoomsContainers.Size(); i++)
565 perGamesRoomsContainers[i]->DestroyRoomIfDead(room);
566 }
ChangeHandle(RakNet::RakString oldHandle,RakNet::RakString newHandle)567 void AllGamesRoomsContainer::ChangeHandle(RakNet::RakString oldHandle, RakNet::RakString newHandle)
568 {
569 unsigned int i;
570 for (i=0; i < perGamesRoomsContainers.Size(); i++)
571 perGamesRoomsContainers[i]->ChangeHandle(oldHandle, newHandle);
572 }
GetPropertyIndex(RoomID lobbyRoomId,const char * propertyName) const573 unsigned int AllGamesRoomsContainer::GetPropertyIndex(RoomID lobbyRoomId, const char *propertyName) const
574 {
575 unsigned int i;
576 Room *room;
577 for (i=0; i < perGamesRoomsContainers.Size(); i++)
578 {
579 room = perGamesRoomsContainers[i]->GetRoomByLobbyRoomID(lobbyRoomId);
580 if (room)
581 return perGamesRoomsContainers[i]->roomsTable.ColumnIndex(propertyName);
582 }
583 return (unsigned int) -1;
584 }
GetInvitesToParticipant(RoomsParticipant * roomsParticipant,DataStructures::List<InvitedUser * > & invites)585 RoomsErrorCode AllGamesRoomsContainer::GetInvitesToParticipant(RoomsParticipant* roomsParticipant, DataStructures::List<InvitedUser*> &invites)
586 {
587 unsigned int i;
588 invites.Clear(true, __FILE__, __LINE__ );
589 for (i=0; i < perGamesRoomsContainers.Size(); i++)
590 perGamesRoomsContainers[i]->GetInvitesToParticipant(roomsParticipant, invites);
591 return REC_SUCCESS;
592 }
593 // userLocation is optional, but will speed up the function if it's pre-known
RemoveUser(RoomsParticipant * roomsParticipant,RemoveUserResult * removeUserResult)594 RoomsErrorCode AllGamesRoomsContainer::RemoveUser(RoomsParticipant* roomsParticipant, RemoveUserResult *removeUserResult)
595 {
596 if (RemoveUserFromQuickJoin(roomsParticipant, &removeUserResult->qju)!=REC_SUCCESS)
597 {
598 removeUserResult->qju=0;
599 removeUserResult->removedFromQuickJoin=false;
600 if (roomsParticipant->GetRoom()==0)
601 return REC_REMOVE_USER_NOT_IN_ROOM;
602
603 RoomsErrorCode roomsErrorCode = roomsParticipant->GetRoom()->RemoveUser(roomsParticipant, removeUserResult);
604 // if (removeUserResult->roomDestroyed)
605 // roomsParticipant->GetPerGameRoomsContainer()->roomsTable.RemoveRow(roomsParticipant->GetRoom()->GetID());
606 return roomsErrorCode;
607 }
608 removeUserResult->removedFromQuickJoin=true;
609 return REC_SUCCESS;
610 }
SendInvite(RoomsParticipant * roomsParticipant,RoomsParticipant * inviteeId,bool inviteToSpectatorSlot,RakNet::RakString subject,RakNet::RakString body)611 RoomsErrorCode AllGamesRoomsContainer::SendInvite(RoomsParticipant* roomsParticipant, RoomsParticipant* inviteeId, bool inviteToSpectatorSlot, RakNet::RakString subject, RakNet::RakString body)
612 {
613 if (roomsParticipant->GetRoom()==0)
614 return REC_SEND_INVITE_UNKNOWN_ROOM_ID;
615
616 return roomsParticipant->GetRoom()->SendInvite(roomsParticipant, inviteeId, inviteToSpectatorSlot, subject, body);
617 }
AcceptInvite(RoomID roomId,Room ** room,RoomsParticipant * roomsParticipant,RakNet::RakString inviteSender)618 RoomsErrorCode AllGamesRoomsContainer::AcceptInvite(RoomID roomId, Room **room, RoomsParticipant* roomsParticipant, RakNet::RakString inviteSender)
619 {
620 *room = GetRoomByLobbyRoomID(roomId);
621 if (*room==0)
622 return REC_ACCEPT_INVITE_UNKNOWN_ROOM_ID;
623 if (roomsParticipant->GetRoom())
624 return REC_ACCEPT_INVITE_CURRENTLY_IN_A_ROOM;
625 if (roomsParticipant->GetInQuickJoin())
626 return REC_ACCEPT_INVITE_CURRENTLY_IN_QUICK_JOIN;
627 return (*room)->AcceptInvite(roomsParticipant, inviteSender);
628 }
StartSpectating(RoomsParticipant * roomsParticipant)629 RoomsErrorCode AllGamesRoomsContainer::StartSpectating(RoomsParticipant* roomsParticipant)
630 {
631 if (roomsParticipant->GetRoom()==0)
632 return REC_START_SPECTATING_UNKNOWN_ROOM_ID;
633
634 return roomsParticipant->GetRoom()->StartSpectating(roomsParticipant);
635 }
StopSpectating(RoomsParticipant * roomsParticipant)636 RoomsErrorCode AllGamesRoomsContainer::StopSpectating(RoomsParticipant* roomsParticipant)
637 {
638 if (roomsParticipant->GetRoom()==0)
639 return REC_STOP_SPECTATING_UNKNOWN_ROOM_ID;
640
641 return roomsParticipant->GetRoom()->StopSpectating(roomsParticipant);
642 }
GrantModerator(RoomsParticipant * roomsParticipant,RoomsParticipant * newModerator,DataStructures::List<InvitedUser> & clearedInvites)643 RoomsErrorCode AllGamesRoomsContainer::GrantModerator(RoomsParticipant* roomsParticipant, RoomsParticipant *newModerator, DataStructures::List<InvitedUser> &clearedInvites)
644 {
645 if (roomsParticipant->GetRoom()==0)
646 return REC_GRANT_MODERATOR_UNKNOWN_ROOM_ID;
647
648 return roomsParticipant->GetRoom()->GrantModerator(roomsParticipant, newModerator, clearedInvites);
649 }
ChangeSlotCounts(RoomsParticipant * roomsParticipant,Slots slots)650 RoomsErrorCode AllGamesRoomsContainer::ChangeSlotCounts(RoomsParticipant* roomsParticipant, Slots slots)
651 {
652 if (roomsParticipant->GetRoom()==0)
653 return REC_CHANGE_SLOT_COUNTS_UNKNOWN_ROOM_ID;
654
655 return roomsParticipant->GetRoom()->ChangeSlotCounts(roomsParticipant, slots);
656 }
SetCustomRoomProperties(RoomsParticipant * roomsParticipant,DataStructures::Table * table)657 RoomsErrorCode AllGamesRoomsContainer::SetCustomRoomProperties(RoomsParticipant* roomsParticipant, DataStructures::Table *table)
658 {
659 if (roomsParticipant->GetRoom()==0)
660 return REC_SET_CUSTOM_ROOM_PROPERTIES_UNKNOWN_ROOM_ID;
661
662 RoomsErrorCode roomsErrorCode = roomsParticipant->GetRoom()->SetCustomRoomProperties(roomsParticipant, table);
663 if (roomsErrorCode!=REC_SUCCESS)
664 return roomsErrorCode;
665
666 unsigned int perGamesRoomContainersIndex;
667 for (perGamesRoomContainersIndex=0; perGamesRoomContainersIndex < perGamesRoomsContainers.Size(); perGamesRoomContainersIndex++)
668 {
669 if (perGamesRoomsContainers[perGamesRoomContainersIndex]->GetRoomByLobbyRoomID(roomsParticipant->GetRoom()->GetID()))
670 break;
671 }
672 RakAssert(perGamesRoomContainersIndex != perGamesRoomsContainers.Size());
673
674 PerGameRoomsContainer *perGameRoomsContainer = perGamesRoomsContainers[perGamesRoomContainersIndex];
675 unsigned int newTableIndex, oldTableIndex;
676 DataStructures::Table *oldTable = &perGameRoomsContainer->roomsTable;
677 DataStructures::Table::Row *row;
678 for (newTableIndex=0; newTableIndex < table->GetColumnCount(); newTableIndex++)
679 {
680 oldTableIndex = oldTable->ColumnIndex(table->ColumnName(newTableIndex));
681 if (oldTableIndex==(unsigned int) -1)
682 {
683 if (oldTable->GetColumnCount() < (unsigned int) MAX_CUSTOM_QUERY_FIELDS)
684 {
685 oldTable->AddColumn(table->ColumnName(newTableIndex), table->GetColumnType(newTableIndex));
686 }
687 else
688 continue;
689
690 }
691 oldTableIndex=oldTable->ColumnIndex(table->ColumnName(newTableIndex));
692 row = roomsParticipant->GetRoom()->tableRow;
693 *(row->cells[oldTableIndex])=*(table->GetRowByIndex(0,0)->cells[newTableIndex]);
694 }
695 return REC_SUCCESS;
696 }
GetRoomProperties(RoomID roomId,Room ** room,DataStructures::Table * table)697 void AllGamesRoomsContainer::GetRoomProperties(RoomID roomId, Room **room, DataStructures::Table *table)
698 {
699 table->Clear();
700 unsigned int perGamesRoomContainersIndex;
701 for (perGamesRoomContainersIndex=0; perGamesRoomContainersIndex < perGamesRoomsContainers.Size(); perGamesRoomContainersIndex++)
702 {
703 *room=perGamesRoomsContainers[perGamesRoomContainersIndex]->GetRoomByLobbyRoomID(roomId);
704 if (*room)
705 break;
706 }
707 RakAssert(perGamesRoomContainersIndex != perGamesRoomsContainers.Size());
708 PerGameRoomsContainer *perGameRoomsContainer = perGamesRoomsContainers[perGamesRoomContainersIndex];
709 DataStructures::Table *oldTable = &perGameRoomsContainer->roomsTable;
710 unsigned int i;
711 for (i=0; i < oldTable->GetColumnCount(); i++)
712 table->AddColumn(oldTable->ColumnName(i), oldTable->GetColumnType(i));
713 table->AddRow(roomId, oldTable->GetRowByID(roomId)->cells, true);
714 }
ChangeRoomName(RoomsParticipant * roomsParticipant,RakNet::RakString newRoomName,ProfanityFilter * profanityFilter)715 RoomsErrorCode AllGamesRoomsContainer::ChangeRoomName(RoomsParticipant* roomsParticipant, RakNet::RakString newRoomName, ProfanityFilter *profanityFilter)
716 {
717 if (roomsParticipant->GetRoom()==0)
718 return REC_CHANGE_ROOM_NAME_UNKNOWN_ROOM_ID;
719
720 unsigned int i;
721 DataStructures::List<RakNet::RakString> roomNames;
722 for (i=0; i < perGamesRoomsContainers.Size(); i++)
723 {
724 perGamesRoomsContainers[i]->GetRoomNames(roomNames);
725 if (roomNames.GetIndexOf(newRoomName)!=(unsigned int) -1)
726 return REC_CHANGE_ROOM_NAME_NAME_ALREADY_IN_USE;
727 }
728
729 return roomsParticipant->GetRoom()->ChangeRoomName(roomsParticipant, newRoomName, profanityFilter);
730 }
SetHiddenFromSearches(RoomsParticipant * roomsParticipant,bool _hiddenFromSearches)731 RoomsErrorCode AllGamesRoomsContainer::SetHiddenFromSearches(RoomsParticipant* roomsParticipant, bool _hiddenFromSearches)
732 {
733 if (roomsParticipant->GetRoom()==0)
734 return REC_SET_HIDDEN_FROM_SEARCHES_UNKNOWN_ROOM_ID;
735
736 return roomsParticipant->GetRoom()->SetHiddenFromSearches(roomsParticipant, _hiddenFromSearches);
737 }
SetDestroyOnModeratorLeave(RoomsParticipant * roomsParticipant,bool destroyOnModeratorLeave)738 RoomsErrorCode AllGamesRoomsContainer::SetDestroyOnModeratorLeave(RoomsParticipant* roomsParticipant, bool destroyOnModeratorLeave)
739 {
740 if (roomsParticipant->GetRoom()==0)
741 return REC_SET_DESTROY_ON_MODERATOR_LEAVE_UNKNOWN_ROOM_ID;
742
743 return roomsParticipant->GetRoom()->SetDestroyOnModeratorLeave(roomsParticipant, destroyOnModeratorLeave);
744 }
SetReadyStatus(RoomsParticipant * roomsParticipant,bool isReady)745 RoomsErrorCode AllGamesRoomsContainer::SetReadyStatus(RoomsParticipant* roomsParticipant, bool isReady)
746 {
747 if (roomsParticipant->GetRoom()==0)
748 return REC_SET_READY_STATUS_UNKNOWN_ROOM_ID;
749
750 return roomsParticipant->GetRoom()->SetReadyStatus(roomsParticipant, isReady);
751 }
GetReadyStatus(RoomID roomId,Room ** room,DataStructures::List<RoomsParticipant * > & readyUsers,DataStructures::List<RoomsParticipant * > & unreadyUsers)752 RoomsErrorCode AllGamesRoomsContainer::GetReadyStatus( RoomID roomId, Room **room, DataStructures::List<RoomsParticipant*> &readyUsers, DataStructures::List<RoomsParticipant*> &unreadyUsers)
753 {
754 *room = GetRoomByLobbyRoomID(roomId);
755
756 if (room==0)
757 return REC_GET_READY_STATUS_UNKNOWN_ROOM_ID;
758
759 return (*room)->GetReadyStatus(readyUsers, unreadyUsers);
760 }
SetRoomLockState(RoomsParticipant * roomsParticipant,RoomLockState _roomLockState)761 RoomsErrorCode AllGamesRoomsContainer::SetRoomLockState(RoomsParticipant* roomsParticipant, RoomLockState _roomLockState)
762 {
763 if (roomsParticipant->GetRoom()==0)
764 return REC_SET_ROOM_LOCK_STATE_UNKNOWN_ROOM_ID;
765
766 return roomsParticipant->GetRoom()->SetRoomLockState(roomsParticipant, _roomLockState);
767 }
GetRoomLockState(RoomID roomId,Room ** room,RoomLockState * roomLockState)768 RoomsErrorCode AllGamesRoomsContainer::GetRoomLockState(RoomID roomId, Room **room, RoomLockState *roomLockState)
769 {
770 *room = GetRoomByLobbyRoomID(roomId);
771
772 if (*room==0)
773 return REC_GET_ROOM_LOCK_STATE_UNKNOWN_ROOM_ID;
774
775 return (*room)->GetRoomLockState( roomLockState);
776 }
AreAllMembersReady(RoomID roomId,Room ** room,bool * allReady)777 RoomsErrorCode AllGamesRoomsContainer::AreAllMembersReady(RoomID roomId, Room **room, bool *allReady)
778 {
779 *room = GetRoomByLobbyRoomID(roomId);
780
781 if (*room==0)
782 return REC_ARE_ALL_MEMBERS_READY_UNKNOWN_ROOM_ID;
783
784 return (RoomsErrorCode) (*room)->AreAllMembersReady((unsigned int) -1, allReady);
785 }
KickMember(RoomsParticipant * roomsParticipant,RoomsParticipant * kickedParticipant,RakNet::RakString reason)786 RoomsErrorCode AllGamesRoomsContainer::KickMember(RoomsParticipant* roomsParticipant, RoomsParticipant *kickedParticipant, RakNet::RakString reason)
787 {
788 if (roomsParticipant->GetRoom()==0)
789 return REC_KICK_MEMBER_UNKNOWN_ROOM_ID;
790
791 return roomsParticipant->GetRoom()->KickMember(roomsParticipant, kickedParticipant, reason);
792 }
UnbanMember(RoomsParticipant * roomsParticipant,RakNet::RakString name)793 RoomsErrorCode AllGamesRoomsContainer::UnbanMember(RoomsParticipant* roomsParticipant, RakNet::RakString name)
794 {
795 if (roomsParticipant->GetRoom()==0)
796 return REC_UNBAN_MEMBER_UNKNOWN_ROOM_ID;
797
798 return roomsParticipant->GetRoom()->UnbanMember(roomsParticipant, name);
799 }
GetBanReason(RoomID lobbyRoomId,Room ** room,RakNet::RakString name,RakNet::RakString * reason)800 RoomsErrorCode AllGamesRoomsContainer::GetBanReason( RoomID lobbyRoomId, Room **room, RakNet::RakString name, RakNet::RakString *reason)
801 {
802 *room = GetRoomByLobbyRoomID(lobbyRoomId);
803 if (*room==0)
804 return REC_GET_BAN_REASON_UNKNOWN_ROOM_ID;
805 return (*room)->GetBanReason(name, reason);
806 }
807 /*
808 RoomsErrorCode AllGamesRoomsContainer::GetKickReason(RoomsParticipant* roomsParticipant, RakNet::RakString *kickReason)
809 {
810 *room = GetRoomByLobbyRoomID(lobbyRoomId);
811 if (*room==0)
812 return REC_GET_KICK_REASON_UNKNOWN_ROOM_ID;
813 return roomsParticipant->GetRoom()->GetKickReason(roomsParticipant, kickReason);
814 }
815 */
GetRoomByLobbyRoomID(RoomID lobbyRoomID)816 Room * AllGamesRoomsContainer::GetRoomByLobbyRoomID(RoomID lobbyRoomID)
817 {
818 unsigned int i;
819 Room *room;
820 for (i=0; i < perGamesRoomsContainers.Size(); i++)
821 {
822 room = perGamesRoomsContainers[i]->GetRoomByLobbyRoomID(lobbyRoomID);
823 if (room)
824 return room;
825 }
826 return 0;
827 }
GetRoomByName(RakNet::RakString roomName)828 Room * AllGamesRoomsContainer::GetRoomByName(RakNet::RakString roomName)
829 {
830 unsigned int i;
831 Room *room;
832 for (i=0; i < perGamesRoomsContainers.Size(); i++)
833 {
834 room = perGamesRoomsContainers[i]->GetRoomByName(roomName);
835 if (room)
836 return room;
837 }
838 return 0;
839 }
ProcessQuickJoins(DataStructures::List<QuickJoinUser * > & timeoutExpired,DataStructures::List<JoinedRoomResult> & joinedRoomMembers,DataStructures::List<QuickJoinUser * > & dereferencedPointers,RakNetTime elapsedTime)840 RoomsErrorCode AllGamesRoomsContainer::ProcessQuickJoins(
841 DataStructures::List<QuickJoinUser*> &timeoutExpired,
842 DataStructures::List<JoinedRoomResult> &joinedRoomMembers,
843 DataStructures::List<QuickJoinUser*> &dereferencedPointers,
844 RakNetTime elapsedTime)
845 {
846 unsigned int numRoomsCreated;
847 unsigned int i;
848 dereferencedPointers.Clear(false, __FILE__, __LINE__);
849 joinedRoomMembers.Clear(false, __FILE__, __LINE__);
850 for (i=0; i < perGamesRoomsContainers.Size(); i++)
851 {
852 numRoomsCreated=perGamesRoomsContainers[i]->ProcessQuickJoins(timeoutExpired, joinedRoomMembers, dereferencedPointers, elapsedTime, nextRoomId);
853 nextRoomId += numRoomsCreated;
854 }
855 unsigned int j;
856 for (j=0; j < joinedRoomMembers.Size(); j++)
857 joinedRoomMembers[j].agrc=this;
858 return REC_SUCCESS;
859 }
AddTitle(GameIdentifier gameIdentifier)860 RoomsErrorCode AllGamesRoomsContainer::AddTitle(GameIdentifier gameIdentifier)
861 {
862 if (perGamesRoomsContainers.Has(gameIdentifier)==true)
863 return REC_ADD_TITLE_ALREADY_IN_USE;
864 perGamesRoomsContainers.SetNew(gameIdentifier, new PerGameRoomsContainer);
865 return REC_SUCCESS;
866 }
867
868 // ---------------------------- PerGameRoomsContainer ----------------------------
869
PerGameRoomsContainer()870 PerGameRoomsContainer::PerGameRoomsContainer()
871 {
872 DefaultRoomColumns::AddDefaultColumnsToTable(&roomsTable);
873 nextQuickJoinProcess.SetPeriod(PROCESS_QUICK_JOINS_INTERVAL);
874 }
~PerGameRoomsContainer()875 PerGameRoomsContainer::~PerGameRoomsContainer()
876 {
877 }
CreateRoom(RoomCreationParameters * roomCreationParameters,ProfanityFilter * profanityFilter,RoomID lobbyRoomId,bool validate)878 RoomsErrorCode PerGameRoomsContainer::CreateRoom(RoomCreationParameters *roomCreationParameters,
879 ProfanityFilter *profanityFilter,
880 RoomID lobbyRoomId,
881 bool validate)
882 {
883 if (validate)
884 {
885 DataStructures::List<RakNet::RakString> otherRoomNames;
886 GetRoomNames(otherRoomNames);
887 RoomsErrorCode roomsErrorCode = roomCreationParameters->Validate(otherRoomNames, profanityFilter);
888 if (roomsErrorCode!=REC_SUCCESS)
889 return roomsErrorCode;
890 roomCreationParameters->createdRoom=true;
891 }
892 DataStructures::List<DataStructures::Table::Cell> initialCellValues;
893 DataStructures::Table::Row *row = roomsTable.AddRow(lobbyRoomId,initialCellValues);
894 roomCreationParameters->roomOutput = new Room(lobbyRoomId, roomCreationParameters, row, roomCreationParameters->firstUser);
895 roomCreationParameters->firstUser->SetPerGameRoomsContainer(this);
896 RakAssert(roomCreationParameters->firstUser->GetRoom()==roomCreationParameters->roomOutput);
897 return REC_SUCCESS;
898 }
JoinByFilter(RoomMemberMode roomMemberMode,RoomsParticipant * roomsParticipant,RoomID lastRoomJoined,RoomQuery * query,JoinedRoomResult * joinRoomResult)899 RoomsErrorCode PerGameRoomsContainer::JoinByFilter(RoomMemberMode roomMemberMode, RoomsParticipant* roomsParticipant, RoomID lastRoomJoined, RoomQuery *query, JoinedRoomResult *joinRoomResult)
900 {
901 joinRoomResult->roomOutput=0;
902 if (roomMemberMode==RMM_MODERATOR)
903 return REC_JOIN_BY_FILTER_CANNOT_JOIN_AS_MODERATOR;
904 RoomsErrorCode roomsErrorCode;
905 if (query!=0)
906 {
907 roomsErrorCode = query->Validate();
908 if (roomsErrorCode!=REC_SUCCESS)
909 return roomsErrorCode;
910 }
911
912 DataStructures::OrderedList<Room*, Room*, PerGameRoomsContainer::RoomsSortByTimeThenTotalSlots> roomsOutput;
913 RoomPrioritySort( roomsParticipant, query, roomsOutput );
914 if (roomsOutput.Size()==0)
915 return REC_JOIN_BY_FILTER_NO_ROOMS;
916 if (roomsOutput[0]->GetID()==lastRoomJoined && roomsOutput.Size()>1)
917 joinRoomResult->roomOutput = roomsOutput[1];
918 else
919 joinRoomResult->roomOutput = roomsOutput[0];
920 roomsParticipant->SetPerGameRoomsContainer(this);
921 return (joinRoomResult->roomOutput)->JoinByFilter(roomsParticipant, roomMemberMode, joinRoomResult);
922 }
AddUserToQuickJoin(QuickJoinUser * quickJoinMember)923 RoomsErrorCode PerGameRoomsContainer::AddUserToQuickJoin(QuickJoinUser *quickJoinMember)
924 {
925 if (GetQuickJoinIndex(quickJoinMember->roomsParticipant)!=(unsigned int) -1)
926 return REC_ADD_TO_QUICK_JOIN_ALREADY_THERE;
927 quickJoinMember->roomsParticipant->SetPerGameRoomsContainer(this);
928 quickJoinMember->roomsParticipant->SetInQuickJoin(true);
929 quickJoinList.Insert(quickJoinMember, __FILE__, __LINE__ );
930 return REC_SUCCESS;
931 }
RemoveUserFromQuickJoin(RoomsParticipant * roomsParticipant,QuickJoinUser ** qju)932 RoomsErrorCode PerGameRoomsContainer::RemoveUserFromQuickJoin(RoomsParticipant* roomsParticipant, QuickJoinUser **qju)
933 {
934 unsigned int quickJoinIndex = GetQuickJoinIndex(roomsParticipant);
935 *qju=0;
936 if (quickJoinIndex==(unsigned int) -1)
937 return REC_REMOVE_FROM_QUICK_JOIN_NOT_THERE;
938 quickJoinList[quickJoinIndex]->roomsParticipant->SetInQuickJoin(false);
939 *qju=quickJoinList[quickJoinIndex];
940 quickJoinList.RemoveAtIndex(quickJoinIndex);
941 roomsParticipant->SetPerGameRoomsContainer(0);
942 return REC_SUCCESS;
943 }
IsInQuickJoin(RoomsParticipant * roomsParticipant)944 bool PerGameRoomsContainer::IsInQuickJoin(RoomsParticipant* roomsParticipant)
945 {
946 return roomsParticipant->GetInQuickJoin()!=0;
947 }
948
RoomsSortByTimeThenTotalSlots(Room * const & key,Room * const & data)949 int PerGameRoomsContainer::RoomsSortByTimeThenTotalSlots( Room* const &key, Room* const &data )
950 {
951 double keyCreationTime = key->GetNumericProperty(DefaultRoomColumns::TC_CREATION_TIME);
952 double dataCreationTime = data->GetNumericProperty(DefaultRoomColumns::TC_CREATION_TIME);
953 int diff = (int) abs(keyCreationTime-dataCreationTime);
954 if (diff < 30 * 1000)
955 {
956 double keyTotalSlots = key->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS);
957 double dataTotalSlots = data->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS);
958 if (keyTotalSlots > dataTotalSlots)
959 return -1;
960 if (keyTotalSlots < dataTotalSlots)
961 return 1;
962 if (key < data)
963 return -1;
964 return 1;
965 }
966 if (keyCreationTime < dataCreationTime)
967 return -1;
968 if (keyCreationTime > dataCreationTime)
969 return 1;
970 return strcmp(key->GetStringProperty(DefaultRoomColumns::TC_ROOM_NAME),data->GetStringProperty(DefaultRoomColumns::TC_ROOM_NAME));
971 }
ProcessQuickJoins(DataStructures::List<QuickJoinUser * > & timeoutExpired,DataStructures::List<JoinedRoomResult> & joinedRoomMembers,DataStructures::List<QuickJoinUser * > & dereferencedPointers,RakNetTime elapsedTime,RoomID startingRoomId)972 unsigned PerGameRoomsContainer::ProcessQuickJoins( DataStructures::List<QuickJoinUser*> &timeoutExpired,
973 DataStructures::List<JoinedRoomResult> &joinedRoomMembers,
974 DataStructures::List<QuickJoinUser*> &dereferencedPointers,
975 RakNetTime elapsedTime,
976 RoomID startingRoomId)
977 {
978 unsigned roomIndex, quickJoinIndex;
979 for (quickJoinIndex=0; quickJoinIndex < quickJoinList.Size(); quickJoinIndex++)
980 quickJoinList[quickJoinIndex]->totalTimeWaiting+=elapsedTime;
981
982 // This is slow, so don't do it very often
983 if (nextQuickJoinProcess.UpdateInterval(elapsedTime)==false)
984 return 0;
985
986 unsigned numRoomsCreated=0;
987 RoomsErrorCode roomsErrorCode;
988 Room *room;
989 double totalRoomSlots, remainingRoomSlots;
990 DataStructures::OrderedList<Room*, Room*, RoomsSortByTimeThenTotalSlots> potentialRooms;
991 DataStructures::OrderedList<QuickJoinUser *, QuickJoinUser *, QuickJoinUser::SortByTotalTimeWaiting> quickJoinMemberTimeSort;
992 DataStructures::List<Room*> allRooms;
993 GetAllRooms(allRooms);
994
995 while (1)
996 {
997 // 1. Clear all quickJoinWorkingList from all rooms
998 for (roomIndex=0; roomIndex < allRooms.Size(); roomIndex++)
999 allRooms[roomIndex]->quickJoinWorkingList.Clear(true, __FILE__, __LINE__ );
1000
1001 // 2. Use RoomPrioritySort to get all rooms they can potentially join
1002 // 3. For each of these rooms, record that this member can potentially join by storing a copy of the pointer into quickJoinWorkingList, if minimumPlayers => total room slots
1003 for (quickJoinIndex=0; quickJoinIndex < quickJoinList.Size(); quickJoinIndex++)
1004 {
1005 RoomPrioritySort( quickJoinList[quickJoinIndex]->roomsParticipant, &quickJoinList[quickJoinIndex]->networkedQuickJoinUser.query, potentialRooms );
1006
1007 for (roomIndex=0; roomIndex < potentialRooms.Size(); roomIndex++)
1008 {
1009 totalRoomSlots = potentialRooms[roomIndex]->GetNumericProperty(DefaultRoomColumns::TC_TOTAL_PUBLIC_PLUS_RESERVED_SLOTS);
1010 if (totalRoomSlots >= quickJoinList[quickJoinIndex]->networkedQuickJoinUser.minimumPlayers-1 &&
1011 potentialRooms[roomIndex]->ParticipantCanJoinRoom(quickJoinList[quickJoinIndex]->roomsParticipant, false, true)==PCJRR_SUCCESS )
1012 potentialRooms[roomIndex]->quickJoinWorkingList.Insert( quickJoinList[quickJoinIndex], __FILE__, __LINE__ );
1013 }
1014 }
1015
1016
1017 // For all rooms:
1018 // 4. For each room where there are enough potential quick join members to fill the room, join all those members at once. Remove these members from the quick join list. Go to 1.
1019 for (roomIndex=0; roomIndex < allRooms.Size(); roomIndex++)
1020 {
1021 room = allRooms[roomIndex];
1022 remainingRoomSlots = room->GetNumericProperty(DefaultRoomColumns::TC_REMAINING_PUBLIC_PLUS_RESERVED_SLOTS);
1023 if (remainingRoomSlots>0 && room->quickJoinWorkingList.Size() >= (unsigned int) remainingRoomSlots)
1024 {
1025 quickJoinMemberTimeSort.Clear(false, __FILE__, __LINE__ );
1026
1027 // Sort those waiting in quick join from longest waiting to least waiting. Those longest waiting are processed first
1028 for (quickJoinIndex=0; quickJoinIndex < (int) room->quickJoinWorkingList.Size(); quickJoinIndex++)
1029 quickJoinMemberTimeSort.Insert( room->quickJoinWorkingList[quickJoinIndex], room->quickJoinWorkingList[quickJoinIndex], true, __FILE__, __LINE__ );
1030
1031 for (quickJoinIndex=0; quickJoinIndex < (unsigned) remainingRoomSlots; quickJoinIndex++)
1032 {
1033 JoinedRoomResult jrr;
1034 jrr.roomOutput=room;
1035 roomsErrorCode=room->JoinByQuickJoin(quickJoinMemberTimeSort[quickJoinIndex]->roomsParticipant, RMM_ANY_PLAYABLE, &jrr);
1036 RakAssert(roomsErrorCode==REC_SUCCESS);
1037
1038 dereferencedPointers.Insert(quickJoinMemberTimeSort[quickJoinIndex], __FILE__, __LINE__ );
1039 joinedRoomMembers.Insert(jrr, __FILE__, __LINE__ );
1040
1041 QuickJoinUser *qju;
1042 roomsErrorCode=RemoveUserFromQuickJoin(quickJoinMemberTimeSort[quickJoinIndex]->roomsParticipant, &qju);
1043 RakAssert(roomsErrorCode==REC_SUCCESS);
1044 }
1045
1046 continue;
1047 }
1048 }
1049
1050 break;
1051 }
1052
1053 DataStructures::OrderedList<QuickJoinUser *, QuickJoinUser *, QuickJoinUser::SortByMinimumSlots> quickJoinMemberSlotSort;
1054 // 5. Sort quick join members by minimumPlayers, excluding members where minimumPlayers > total number of quick join members
1055 for (quickJoinIndex=0; quickJoinIndex < quickJoinList.Size(); quickJoinIndex++)
1056 {
1057 if (quickJoinList[quickJoinIndex]->networkedQuickJoinUser.minimumPlayers <= (int) quickJoinList.Size())
1058 quickJoinMemberSlotSort.Insert(quickJoinList[quickJoinIndex],quickJoinList[quickJoinIndex],true, __FILE__, __LINE__ );
1059 }
1060
1061 DataStructures::Table potentialNewRoom;
1062 unsigned queryIndex, quickJoinIndex2;
1063 DataStructures::Table resultTable;
1064 QuickJoinUser *quickJoinMember;
1065 RoomCreationParameters roomCreationParameters;
1066 DataStructures::List<QuickJoinUser*> potentialNewRoommates;
1067
1068 // 6. If the current member created a roomOutput, find out how many subsequent members would join based on the custom filter
1069 quickJoinIndex=0;
1070 while (quickJoinIndex < quickJoinList.Size())
1071 {
1072 quickJoinMember = quickJoinList[quickJoinIndex];
1073 potentialNewRoom.Clear();
1074 DefaultRoomColumns::AddDefaultColumnsToTable(&potentialNewRoom);
1075 DataStructures::Table::Row *row = potentialNewRoom.AddRow(0);
1076 roomCreationParameters.networkedRoomCreationParameters.slots.publicSlots=quickJoinMember->networkedQuickJoinUser.minimumPlayers-1;
1077 Room::UpdateRowSlots( row, &roomCreationParameters.networkedRoomCreationParameters.slots, &roomCreationParameters.networkedRoomCreationParameters.slots);
1078
1079 for (queryIndex=0; queryIndex < quickJoinMember->networkedQuickJoinUser.query.numQueries; queryIndex++)
1080 {
1081 // For all filters that are equal and custom, create a table with rows with these values
1082 if ( ( quickJoinMember->networkedQuickJoinUser.query.queries[queryIndex].operation==DataStructures::Table::QF_EQUAL ) &&
1083 DefaultRoomColumns::HasColumnName(quickJoinMember->networkedQuickJoinUser.query.queries[queryIndex].columnName)==false &&
1084 potentialNewRoom.ColumnIndex(quickJoinMember->networkedQuickJoinUser.query.queries[queryIndex].columnName)==-1 &&
1085 quickJoinMember->networkedQuickJoinUser.query.queries[queryIndex].cellValue->isEmpty==false
1086 )
1087 {
1088 potentialNewRoom.AddColumn(quickJoinMember->networkedQuickJoinUser.query.queries[queryIndex].columnName, quickJoinMember->networkedQuickJoinUser.query.queries[queryIndex].cellValue->EstimateColumnType());
1089 *(row->cells[potentialNewRoom.GetColumnCount()-1]) = *(quickJoinMember->networkedQuickJoinUser.query.queries[queryIndex].cellValue);
1090 }
1091 }
1092
1093 potentialNewRoommates.Clear(true, __FILE__, __LINE__ );
1094 for (quickJoinIndex2=quickJoinIndex+1; quickJoinIndex2 < quickJoinList.Size(); quickJoinIndex2++)
1095 {
1096 resultTable.Clear();
1097 unsigned columnIndices[1];
1098 columnIndices[0]=DefaultRoomColumns::TC_LOBBY_ROOM_PTR;
1099 JoinedRoomResult joinedRoomResult;
1100
1101 DataStructures::Table::FilterQuery subQueries[MAX_CUSTOM_QUERY_FIELDS];
1102 unsigned int subQueryCount;
1103 unsigned int subQueryIndex;
1104 for (subQueryIndex=0, subQueryCount=0; subQueryIndex < quickJoinList[quickJoinIndex2]->networkedQuickJoinUser.query.numQueries; subQueryIndex++)
1105 {
1106 if (potentialNewRoom.ColumnIndex(quickJoinList[quickJoinIndex2]->networkedQuickJoinUser.query.queries[subQueryIndex].columnName)!=-1)
1107 {
1108 subQueries[subQueryCount++]=quickJoinList[quickJoinIndex2]->networkedQuickJoinUser.query.queries[subQueryIndex];
1109 }
1110 }
1111
1112 potentialNewRoom.QueryTable(columnIndices,1,subQueries,subQueryCount,0,0,&resultTable);
1113 if (resultTable.GetRowCount()>0)
1114 {
1115 potentialNewRoommates.Insert(quickJoinList[quickJoinIndex2], __FILE__, __LINE__ );
1116 if (potentialNewRoommates.Size()>=(unsigned int) quickJoinMember->networkedQuickJoinUser.minimumPlayers-1)
1117 {
1118 // 7. If this satisfies minimumPlayers, have that user create a roomOutput and those subsequent members join.
1119 roomCreationParameters.networkedRoomCreationParameters.hiddenFromSearches=false;
1120 roomCreationParameters.networkedRoomCreationParameters.destroyOnModeratorLeave=false;
1121 roomCreationParameters.networkedRoomCreationParameters.roomName.Set(QUICK_JOIN_ROOM_NAME "%i", startingRoomId+numRoomsCreated);
1122 roomCreationParameters.firstUser=quickJoinMember->roomsParticipant;
1123
1124 roomsErrorCode = CreateRoom(&roomCreationParameters, 0,startingRoomId+numRoomsCreated, false);
1125 joinedRoomResult.roomOutput=roomCreationParameters.roomOutput;
1126 numRoomsCreated++;
1127 RakAssert(roomsErrorCode==REC_SUCCESS);
1128
1129 QuickJoinUser *qju;
1130 for (quickJoinIndex2=0; quickJoinIndex2 < potentialNewRoommates.Size(); quickJoinIndex2++)
1131 {
1132 roomsErrorCode = roomCreationParameters.roomOutput->JoinByQuickJoin(potentialNewRoommates[quickJoinIndex2]->roomsParticipant, RMM_PUBLIC, &joinedRoomResult);
1133 RakAssert(roomsErrorCode==REC_SUCCESS);
1134 RemoveUserFromQuickJoin(potentialNewRoommates[quickJoinIndex2]->roomsParticipant, &qju);
1135 dereferencedPointers.Insert(qju, __FILE__, __LINE__ );
1136 joinedRoomResult.joiningMember=potentialNewRoommates[quickJoinIndex2]->roomsParticipant;
1137 joinedRoomMembers.Insert(joinedRoomResult, __FILE__, __LINE__ );
1138 }
1139
1140 joinedRoomResult.joiningMember=quickJoinMember->roomsParticipant;
1141 joinedRoomMembers.Insert(joinedRoomResult, __FILE__, __LINE__ );
1142 RemoveUserFromQuickJoin(quickJoinMember->roomsParticipant, &qju);
1143 dereferencedPointers.Insert(qju, __FILE__, __LINE__ );
1144 continue;
1145 }
1146 }
1147 }
1148
1149 quickJoinIndex++;
1150 }
1151
1152
1153 // 5. Remove from list if timeout has expired.
1154 quickJoinIndex=0;
1155 while (quickJoinIndex < quickJoinList.Size())
1156 {
1157 if (quickJoinList[quickJoinIndex]->totalTimeWaiting >= quickJoinList[quickJoinIndex]->networkedQuickJoinUser.timeout)
1158 {
1159 quickJoinList[quickJoinIndex]->roomsParticipant->SetInQuickJoin(false);
1160 timeoutExpired.Insert(quickJoinList[quickJoinIndex], __FILE__, __LINE__ );
1161 dereferencedPointers.Insert(quickJoinList[quickJoinIndex], __FILE__, __LINE__ );
1162 quickJoinList.RemoveAtIndexFast(quickJoinIndex);
1163 }
1164 else
1165 quickJoinIndex++;
1166 }
1167
1168 return numRoomsCreated;
1169 }
GetInvitesToParticipant(RoomsParticipant * roomsParticipant,DataStructures::List<InvitedUser * > & invites)1170 RoomsErrorCode PerGameRoomsContainer::GetInvitesToParticipant(RoomsParticipant* roomsParticipant, DataStructures::List<InvitedUser*> &invites)
1171 {
1172 DataStructures::List<Room*> rooms;
1173 GetAllRooms(rooms);
1174 unsigned i;
1175 for (i=0; i < rooms.Size(); i++)
1176 rooms[i]->GetInvitesToParticipant(roomsParticipant, invites);
1177 return REC_SUCCESS;
1178 }
DestroyRoomIfDead(Room * room)1179 void PerGameRoomsContainer::DestroyRoomIfDead(Room *room)
1180 {
1181 roomsTable.RemoveRow(room->GetID());
1182 delete room;
1183 }
ChangeHandle(RakNet::RakString oldHandle,RakNet::RakString newHandle)1184 void PerGameRoomsContainer::ChangeHandle(RakNet::RakString oldHandle, RakNet::RakString newHandle)
1185 {
1186 DataStructures::List<Room*> rooms;
1187 GetAllRooms(rooms);
1188 unsigned i;
1189 for (i=0; i < rooms.Size(); i++)
1190 rooms[i]->ChangeHandle(oldHandle, newHandle);
1191 }
1192
SearchByFilter(RoomsParticipant * roomsParticipant,RoomQuery * roomQuery,DataStructures::OrderedList<Room *,Room *,AllGamesRoomsContainer::RoomsSortByName> & roomsOutput,bool onlyJoinable)1193 RoomsErrorCode PerGameRoomsContainer::SearchByFilter( RoomsParticipant* roomsParticipant, RoomQuery *roomQuery, DataStructures::OrderedList<Room*, Room*, AllGamesRoomsContainer::RoomsSortByName> &roomsOutput, bool onlyJoinable )
1194 {
1195 DataStructures::Table resultTable;
1196 unsigned columnIndices[1];
1197 columnIndices[0]=DefaultRoomColumns::TC_LOBBY_ROOM_PTR;
1198
1199 // Process user queries
1200 roomsTable.QueryTable(columnIndices,1,roomQuery->queries,roomQuery->numQueries,0,0,&resultTable);
1201
1202 roomsOutput.Clear(false, __FILE__, __LINE__);
1203 DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> *cur = resultTable.GetRows().GetListHead();
1204 int i;
1205 Room *room;
1206 while (cur)
1207 {
1208 for (i=0; i < cur->size; i++)
1209 {
1210 // Put all the pointers in the roomSort list, filtering out those you cannot join (full, or no public and you are not invited)
1211 room = (Room*) cur->data[i]->cells[0]->ptr;
1212 if ( (onlyJoinable==false || room->ParticipantCanJoinRoom(roomsParticipant, false, true)==PCJRR_SUCCESS) &&
1213 room->IsHiddenToParticipant(roomsParticipant)==false)
1214 roomsOutput.Insert(room,room,true, __FILE__, __LINE__ );
1215 }
1216 cur=cur->next;
1217 }
1218 return REC_SUCCESS;
1219 }
RoomPrioritySort(RoomsParticipant * roomsParticipant,RoomQuery * roomQuery,DataStructures::OrderedList<Room *,Room *,RoomsSortByTimeThenTotalSlots> & roomsOutput)1220 void PerGameRoomsContainer::RoomPrioritySort( RoomsParticipant* roomsParticipant, RoomQuery *roomQuery, DataStructures::OrderedList<Room*, Room*, RoomsSortByTimeThenTotalSlots> &roomsOutput )
1221 {
1222 int i;
1223 // If you don't care about room filters, just join any room
1224 if (roomQuery==0 || roomQuery->numQueries==0 || roomQuery->queries==0)
1225 {
1226 DataStructures::List<Room*> rooms;
1227 GetAllRooms(rooms);
1228 for (i=0; (unsigned) i < rooms.Size(); i++)
1229 {
1230 Room *room = rooms[i];
1231 if (room->ParticipantCanJoinRoom(roomsParticipant, false, true)==PCJRR_SUCCESS &&
1232 room->IsHiddenToParticipant(roomsParticipant)==false)
1233 roomsOutput.Insert(rooms[i], rooms[i], true, __FILE__, __LINE__ );
1234 }
1235 return;
1236 }
1237
1238 // Must pass room query
1239 // Of those that pass room query, sort by time (lower is first). If within one minute of each other, sort by number of users in playable slots (higher if first)
1240 // Be sure to return columns TC_LOBBY_ROOM_PTR, TC_USED_PUBLIC_PLUS_RESERVED_SLOTS, TC_LOBBY_ROOM_PTR
1241
1242 DataStructures::Table resultTable;
1243 unsigned columnIndices[1];
1244 columnIndices[0]=DefaultRoomColumns::TC_LOBBY_ROOM_PTR;
1245
1246 // Process user queries
1247 roomsTable.QueryTable(columnIndices,1,roomQuery->queries,roomQuery->numQueries,0,0,&resultTable);
1248
1249 roomsOutput.Clear(false, __FILE__, __LINE__);
1250 DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> *cur = resultTable.GetRows().GetListHead();
1251 Room *room;
1252 while (cur)
1253 {
1254 for (i=0; i < cur->size; i++)
1255 {
1256 // Put all the pointers in the roomSort list, filtering out those you cannot join (full, or no public and you are not invited)
1257 room = (Room*) cur->data[i]->cells[0]->ptr;
1258 if (room->ParticipantCanJoinRoom(roomsParticipant, false, true)==PCJRR_SUCCESS &&
1259 room->IsHiddenToParticipant(roomsParticipant)==false)
1260 roomsOutput.Insert(room,room,true, __FILE__, __LINE__ );
1261 }
1262 cur=cur->next;
1263 }
1264 }
GetRoomByLobbyRoomID(RoomID lobbyRoomID)1265 Room* PerGameRoomsContainer::GetRoomByLobbyRoomID(RoomID lobbyRoomID)
1266 {
1267 DataStructures::Table::Row *row = roomsTable.GetRowByID(lobbyRoomID);
1268 if (row==0)
1269 return 0;
1270
1271 return (Room*) roomsTable.GetRowByID(lobbyRoomID)->cells[DefaultRoomColumns::TC_LOBBY_ROOM_PTR]->ptr;
1272 }
GetRoomByName(RakNet::RakString roomName)1273 Room * PerGameRoomsContainer::GetRoomByName(RakNet::RakString roomName)
1274 {
1275 DataStructures::List<Room*> rooms;
1276 GetAllRooms(rooms);
1277 unsigned int i;
1278 for (i=0; i < rooms.Size(); i++)
1279 {
1280 if (strcmp(rooms[i]->GetStringProperty(DefaultRoomColumns::TC_ROOM_NAME), roomName.C_String())==0)
1281 {
1282 return rooms[i];
1283 }
1284 }
1285 return 0;
1286 }
GetAllRooms(DataStructures::List<Room * > & rooms)1287 void PerGameRoomsContainer::GetAllRooms(DataStructures::List<Room*> &rooms)
1288 {
1289 DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> *cur = roomsTable.GetRows().GetListHead();
1290 int i;
1291 rooms.Clear(false, __FILE__, __LINE__);
1292 while (cur)
1293 {
1294 for (i=0; i < cur->size; i++)
1295 rooms.Insert((Room*)cur->data[i]->cells[DefaultRoomColumns::TC_LOBBY_ROOM_PTR]->ptr, __FILE__, __LINE__ );
1296 cur=cur->next;
1297 }
1298 }
GetRoomNames(DataStructures::List<RakNet::RakString> & roomNames)1299 void PerGameRoomsContainer::GetRoomNames(DataStructures::List<RakNet::RakString> &roomNames)
1300 {
1301 DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> *cur = roomsTable.GetRows().GetListHead();
1302 int i;
1303 roomNames.Clear(false, __FILE__, __LINE__);
1304 while (cur)
1305 {
1306 for (i=0; i < cur->size; i++)
1307 roomNames.Insert(RakNet::RakString(cur->data[i]->cells[DefaultRoomColumns::TC_ROOM_NAME]->c), __FILE__, __LINE__ );
1308 cur=cur->next;
1309 }
1310 }
1311
GetQuickJoinIndex(RoomsParticipant * roomsParticipant)1312 unsigned int PerGameRoomsContainer::GetQuickJoinIndex(RoomsParticipant* roomsParticipant)
1313 {
1314 unsigned int i;
1315 for (i=0; i < quickJoinList.Size(); i++)
1316 if (quickJoinList[i]->roomsParticipant==roomsParticipant)
1317 return i;
1318 return (unsigned int) -1;
1319 }
1320
1321 // ---------------------------- ROOMS ----------------------------
1322
Room(RoomID _roomId,RoomCreationParameters * roomCreationParameters,DataStructures::Table::Row * _row,RoomsParticipant * roomsParticipant)1323 Room::Room( RoomID _roomId, RoomCreationParameters *roomCreationParameters, DataStructures::Table::Row *_row, RoomsParticipant* roomsParticipant )
1324 {
1325 roomDestroyed=false;
1326
1327 lobbyRoomId=_roomId;
1328 tableRow=_row;
1329
1330 autoLockReadyStatus=roomCreationParameters->networkedRoomCreationParameters.autoLockReadyStatus;
1331 hiddenFromSearches=roomCreationParameters->networkedRoomCreationParameters.hiddenFromSearches;
1332 // destroyOnModeratorLeave=roomCreationParameters->networkedRoomCreationParameters.destroyOnModeratorLeave;
1333 clearInvitesOnNewModerator=roomCreationParameters->networkedRoomCreationParameters.clearInvitesOnNewModerator;
1334 inviteToRoomPermission=roomCreationParameters->networkedRoomCreationParameters.inviteToRoomPermission;
1335 inviteToSpectatorSlotPermission=roomCreationParameters->networkedRoomCreationParameters.inviteToSpectatorSlotPermission;
1336 roomLockState=RLS_NOT_LOCKED;
1337
1338 Slots usedSlots;
1339 UpdateRowSlots( tableRow, &roomCreationParameters->networkedRoomCreationParameters.slots, &usedSlots);
1340
1341 RoomMember *roomMember = new RoomMember;
1342 roomMember->roomMemberMode=RMM_MODERATOR;
1343 roomMember->roomsParticipant=roomsParticipant;
1344 roomsParticipant->SetRoom(this);
1345 roomMemberList.Insert(roomMember, __FILE__, __LINE__ );
1346 tableRow->cells[DefaultRoomColumns::TC_ROOM_NAME]->Set(roomCreationParameters->networkedRoomCreationParameters.roomName.C_String());
1347 tableRow->cells[DefaultRoomColumns::TC_ROOM_ID]->Set(lobbyRoomId);
1348 tableRow->cells[DefaultRoomColumns::TC_CREATION_TIME]->Set((int) RakNet::GetTime());
1349 tableRow->cells[DefaultRoomColumns::TC_DESTROY_ON_MODERATOR_LEAVE]->Set((int) roomCreationParameters->networkedRoomCreationParameters.destroyOnModeratorLeave);
1350 tableRow->cells[DefaultRoomColumns::TC_LOBBY_ROOM_PTR]->SetPtr(this);
1351 }
~Room()1352 Room::~Room()
1353 {
1354 }
UpdateRowSlots(DataStructures::Table::Row * row,Slots * totalSlots,Slots * usedSlots)1355 void Room::UpdateRowSlots( DataStructures::Table::Row* row, Slots *totalSlots, Slots *usedSlots)
1356 {
1357 row->cells[DefaultRoomColumns::TC_TOTAL_SLOTS]->Set(totalSlots->publicSlots+totalSlots->reservedSlots+totalSlots->spectatorSlots);
1358 row->cells[DefaultRoomColumns::TC_TOTAL_PUBLIC_PLUS_RESERVED_SLOTS]->Set(totalSlots->publicSlots+totalSlots->reservedSlots);
1359 row->cells[DefaultRoomColumns::TC_TOTAL_PUBLIC_SLOTS]->Set(totalSlots->publicSlots);
1360 row->cells[DefaultRoomColumns::TC_TOTAL_RESERVED_SLOTS]->Set(totalSlots->reservedSlots);
1361 row->cells[DefaultRoomColumns::TC_TOTAL_SPECTATOR_SLOTS]->Set(totalSlots->spectatorSlots);
1362
1363 UpdateUsedSlots(row, totalSlots, usedSlots);
1364 }
UpdateUsedSlots(void)1365 void Room::UpdateUsedSlots( void )
1366 {
1367 Slots totalSlots = GetTotalSlots();
1368 Slots usedSlots = GetUsedSlots();
1369 UpdateUsedSlots(&totalSlots, &usedSlots);
1370 }
UpdateUsedSlots(DataStructures::Table::Row * tableRow,Slots * totalSlots,Slots * usedSlots)1371 void Room::UpdateUsedSlots( DataStructures::Table::Row* tableRow, Slots *totalSlots, Slots *usedSlots )
1372 {
1373 tableRow->cells[DefaultRoomColumns::TC_USED_SLOTS]->Set(usedSlots->publicSlots+usedSlots->reservedSlots+usedSlots->spectatorSlots);
1374 tableRow->cells[DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS]->Set(usedSlots->publicSlots+usedSlots->reservedSlots);
1375 tableRow->cells[DefaultRoomColumns::TC_REMAINING_SLOTS]->Set(totalSlots->publicSlots+totalSlots->reservedSlots+totalSlots->spectatorSlots-usedSlots->publicSlots-usedSlots->reservedSlots-usedSlots->spectatorSlots);
1376 tableRow->cells[DefaultRoomColumns::TC_REMAINING_PUBLIC_PLUS_RESERVED_SLOTS]->Set(totalSlots->publicSlots+totalSlots->reservedSlots-usedSlots->publicSlots-usedSlots->reservedSlots);
1377 tableRow->cells[DefaultRoomColumns::TC_USED_PUBLIC_SLOTS]->Set(usedSlots->publicSlots);
1378 tableRow->cells[DefaultRoomColumns::TC_USED_RESERVED_SLOTS]->Set(usedSlots->reservedSlots);
1379 tableRow->cells[DefaultRoomColumns::TC_USED_SPECTATOR_SLOTS]->Set(usedSlots->spectatorSlots);
1380 tableRow->cells[DefaultRoomColumns::TC_REMAINING_PUBLIC_SLOTS]->Set(totalSlots->publicSlots-usedSlots->publicSlots);
1381 tableRow->cells[DefaultRoomColumns::TC_REMAINING_RESERVED_SLOTS]->Set(totalSlots->reservedSlots-usedSlots->reservedSlots);
1382 tableRow->cells[DefaultRoomColumns::TC_REMAINING_SPECTATOR_SLOTS]->Set(totalSlots->spectatorSlots-usedSlots->spectatorSlots);
1383 }
UpdateUsedSlots(Slots * totalSlots,Slots * usedSlots)1384 void Room::UpdateUsedSlots( Slots *totalSlots, Slots *usedSlots )
1385 {
1386 UpdateUsedSlots(tableRow, totalSlots, usedSlots);
1387 }
GetTotalSlots(void) const1388 Slots Room::GetTotalSlots(void) const
1389 {
1390 Slots totalSlots;
1391 totalSlots.publicSlots=(int)GetNumericProperty(DefaultRoomColumns::TC_TOTAL_PUBLIC_SLOTS);
1392 totalSlots.reservedSlots=(int)GetNumericProperty(DefaultRoomColumns::TC_TOTAL_RESERVED_SLOTS);
1393 totalSlots.spectatorSlots=(int)GetNumericProperty(DefaultRoomColumns::TC_TOTAL_SPECTATOR_SLOTS);
1394 return totalSlots;
1395 }
SetTotalSlots(Slots * totalSlots)1396 void Room::SetTotalSlots(Slots *totalSlots)
1397 {
1398 SetNumericProperty(DefaultRoomColumns::TC_TOTAL_PUBLIC_SLOTS, totalSlots->publicSlots);
1399 SetNumericProperty(DefaultRoomColumns::TC_TOTAL_RESERVED_SLOTS, totalSlots->reservedSlots);
1400 SetNumericProperty(DefaultRoomColumns::TC_TOTAL_SPECTATOR_SLOTS, totalSlots->spectatorSlots);
1401 }
GetUsedSlots(void) const1402 Slots Room::GetUsedSlots(void) const
1403 {
1404 Slots usedSlots;
1405 unsigned i;
1406 for (i=0; i < roomMemberList.Size(); i++)
1407 {
1408 if (roomMemberList[i]->roomMemberMode==RMM_PUBLIC)
1409 usedSlots.publicSlots++;
1410 else if (roomMemberList[i]->roomMemberMode==RMM_RESERVED)
1411 usedSlots.reservedSlots++;
1412 else if (
1413 roomMemberList[i]->roomMemberMode==RMM_SPECTATOR_PUBLIC ||
1414 roomMemberList[i]->roomMemberMode==RMM_SPECTATOR_RESERVED)
1415 usedSlots.spectatorSlots++;
1416 // Moderator not counted
1417 }
1418 return usedSlots;
1419 }
SendInvite(RoomsParticipant * roomsParticipant,RoomsParticipant * inviteeId,bool inviteToSpectatorSlot,RakNet::RakString subject,RakNet::RakString body)1420 RoomsErrorCode Room::SendInvite(RoomsParticipant* roomsParticipant, RoomsParticipant* inviteeId, bool inviteToSpectatorSlot, RakNet::RakString subject, RakNet::RakString body)
1421 {
1422 RakAssert(roomDestroyed==false);
1423
1424 // Is roomsParticipant in the room?
1425 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1426 if (roomsParticipantIndex==-1) return REC_SEND_INVITE_INVITOR_NOT_IN_ROOM;
1427
1428 if (roomsParticipant==inviteeId)
1429 return REC_SEND_INVITE_CANNOT_PERFORM_ON_SELF;
1430
1431 // Is inviteeId not in the room?
1432 if (IsInRoom(inviteeId)) return REC_SEND_INVITE_INVITEE_ALREADY_IN_THIS_ROOM;
1433
1434 // Does inviteeId already have an invite from roomsParticipant (either slot type)?
1435 if (HasInvite(inviteeId->GetName())) return REC_SEND_INVITE_INVITEE_ALREADY_INVITED;
1436
1437 // Can inviteeId join?
1438 ParticipantCanJoinRoomResult pcjrr = ParticipantCanJoinRoom(inviteeId, inviteToSpectatorSlot, false);
1439 if (pcjrr==PCJRR_BANNED) return REC_SEND_INVITE_INVITEE_BANNED;
1440 if (pcjrr==PCJRR_NO_PUBLIC_SLOTS && inviteToSpectatorSlot==false) return REC_SEND_INVITE_NO_SLOTS;
1441 if (pcjrr==PCJRR_NO_PUBLIC_OR_RESERVED_SLOTS) return REC_SEND_INVITE_NO_SLOTS;
1442 if (pcjrr==PCJRR_LOCKED) return REC_SEND_INVITE_ROOM_LOCKED;
1443 RakAssert(pcjrr==PCJRR_SUCCESS);
1444
1445 // Can roomsParticipant send an invite, given inviteToRoomPermission or inviteToSpectatorSlotPermission? (leader can always invite no matter what)
1446 RoomMemberMode memberMode = roomMemberList[roomsParticipantIndex]->roomMemberMode;
1447 RakAssert(memberMode!=RMM_ANY_PLAYABLE);
1448 bool canInvite;
1449 if (memberMode==RMM_MODERATOR)
1450 {
1451 canInvite=true;
1452 }
1453 else
1454 {
1455 NetworkedRoomCreationParameters::SendInvitePermission relevantPermission;
1456 if (inviteToSpectatorSlotPermission)
1457 relevantPermission=inviteToSpectatorSlotPermission;
1458 else
1459 relevantPermission=inviteToRoomPermission;
1460 if (relevantPermission==NetworkedRoomCreationParameters::INVITE_MODE_MODERATOR_CAN_INVITE)
1461 return REC_SEND_INVITE_INVITOR_ONLY_MODERATOR_CAN_INVITE;
1462 if (relevantPermission==NetworkedRoomCreationParameters::INVITE_MODE_ANYONE_CAN_INVITE)
1463 canInvite=true;
1464 else if (
1465 (relevantPermission==NetworkedRoomCreationParameters::INVITE_MODE_PUBLIC_SLOTS_CAN_INVITE ||
1466 relevantPermission==NetworkedRoomCreationParameters::INVITE_MODE_MODERATOR_OR_PUBLIC_SLOTS_CAN_INVITE ||
1467 relevantPermission==NetworkedRoomCreationParameters::INVITE_MODE_MODERATOR_OR_PUBLIC_OR_RESERVED_SLOTS_CAN_INVITE)
1468 && memberMode==RMM_PUBLIC)
1469 canInvite=true;
1470 else if (
1471 (relevantPermission==NetworkedRoomCreationParameters::INVITE_MODE_RESERVED_SLOTS_CAN_INVITE ||
1472 relevantPermission==NetworkedRoomCreationParameters::INVITE_MODE_MODERATOR_OR_PUBLIC_OR_RESERVED_SLOTS_CAN_INVITE)
1473 && memberMode==RMM_RESERVED)
1474 canInvite=true;
1475 else if (relevantPermission==NetworkedRoomCreationParameters::INVITE_MODE_SPECTATOR_SLOTS_CAN_INVITE && (memberMode==RMM_SPECTATOR_PUBLIC || memberMode==RMM_SPECTATOR_RESERVED))
1476 canInvite=true;
1477 else if (relevantPermission==NetworkedRoomCreationParameters::INVITE_MODE_MODERATOR_OR_PUBLIC_SLOTS_CAN_INVITE && (memberMode==RMM_SPECTATOR_PUBLIC || memberMode==RMM_SPECTATOR_RESERVED))
1478 canInvite=true;
1479 else
1480 return REC_SEND_INVITE_INVITOR_LACK_INVITE_PERMISSIONS;
1481 }
1482
1483 InvitedUser invitedUser;
1484 invitedUser.body=body;
1485 invitedUser.invitedAsSpectator=inviteToSpectatorSlot;
1486 invitedUser.target=inviteeId->GetName();
1487 invitedUser.invitorName=roomsParticipant->GetName();
1488 invitedUser.room=this;
1489 invitedUser.subject=subject;
1490 inviteList.Insert(invitedUser, __FILE__, __LINE__ );
1491 return REC_SUCCESS;
1492 }
AcceptInvite(RoomsParticipant * roomsParticipant,RakNet::RakString inviteSender)1493 RoomsErrorCode Room::AcceptInvite(RoomsParticipant* roomsParticipant, RakNet::RakString inviteSender)
1494 {
1495 RakAssert(roomDestroyed==false);
1496
1497 // Is roomsParticipant not in the roomOutput?
1498 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1499 if (roomsParticipantIndex!=-1) return REC_ACCEPT_INVITE_CURRENTLY_IN_A_ROOM;
1500
1501 // Does roomsParticipant have an invite from inviteSender?
1502 unsigned int inviteIndex = GetInviteIndex(roomsParticipant->GetName(), inviteSender);
1503 if (inviteIndex==-1) return REC_ACCEPT_INVITE_NO_SUCH_INVITE;
1504
1505 // Is the roomOutput locked for the target slot type (any slot and RLS_ALL_LOCKED, or player and RLS_PLAYERS_LOCKED)?
1506 ParticipantCanJoinRoomResult pcjrr = ParticipantCanJoinRoom(roomsParticipant, inviteList[inviteIndex].invitedAsSpectator, true);
1507 if (pcjrr==PCJRR_BANNED) return REC_ACCEPT_INVITE_BANNED;
1508 if (pcjrr==PCJRR_NO_PUBLIC_SLOTS || pcjrr==PCJRR_NO_PUBLIC_OR_RESERVED_SLOTS) return REC_ACCEPT_INVITE_NO_SLOTS;
1509 if (pcjrr==PCJRR_LOCKED) return REC_ACCEPT_INVITE_ROOM_LOCKED;
1510 RakAssert(pcjrr==PCJRR_SUCCESS);
1511
1512 // Remove the used invite
1513 inviteList.RemoveAtIndex(inviteIndex);
1514
1515 // Add the new roomOutput member
1516 RoomMember* roomMember = new RoomMember;
1517 roomMember->isReady=false;
1518 roomMember->joinTime=RakNet::GetTime();
1519 roomMember->roomMemberMode=RMM_RESERVED;
1520 roomMember->roomsParticipant=roomsParticipant;
1521 roomsParticipant->SetRoom(this);
1522 roomMemberList.Insert(roomMember, __FILE__, __LINE__ );
1523 UpdateUsedSlots();
1524 return REC_SUCCESS;
1525 }
StartSpectating(RoomsParticipant * roomsParticipant)1526 RoomsErrorCode Room::StartSpectating(RoomsParticipant* roomsParticipant)
1527 {
1528 RakAssert(roomDestroyed==false);
1529
1530 // Is roomsParticipant in the roomOutput?
1531 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1532 if (roomsParticipantIndex==-1) return REC_START_SPECTATING_NOT_IN_ROOM;
1533
1534 // Is roomsParticipant the moderator? Moderator must grant moderator to another user first
1535 // Would this destroy the roomOutput (no players left)? (last player is always leader)
1536 if (roomMemberList[roomsParticipantIndex]->roomMemberMode==RMM_MODERATOR)
1537 return REC_START_SPECTATING_REASSIGN_MODERATOR_BEFORE_SPECTATE;
1538
1539 // Already spectating?
1540 if (roomMemberList[roomsParticipantIndex]->roomMemberMode==RMM_SPECTATOR_PUBLIC ||
1541 roomMemberList[roomsParticipantIndex]->roomMemberMode==RMM_SPECTATOR_RESERVED)
1542 return REC_START_SPECTATING_ALREADY_SPECTATING;
1543
1544 // Are there open spectator slots?
1545 if (GetNumericProperty(DefaultRoomColumns::TC_REMAINING_SPECTATOR_SLOTS)<=0.0)
1546 return REC_START_SPECTATING_NO_SPECTATOR_SLOTS_AVAILABLE;
1547
1548 // Is the roomOutput locked to spectators (RLS_ALL_LOCKED)?
1549 if (roomLockState==RLS_ALL_LOCKED)
1550 return REC_START_SPECTATING_ROOM_LOCKED;
1551
1552 if (roomMemberList[roomsParticipantIndex]->roomMemberMode==RMM_RESERVED ||
1553 roomMemberList[roomsParticipantIndex]->roomMemberMode==RMM_MODERATOR)
1554 roomMemberList[roomsParticipantIndex]->roomMemberMode=RMM_SPECTATOR_RESERVED;
1555 else
1556 roomMemberList[roomsParticipantIndex]->roomMemberMode=RMM_SPECTATOR_PUBLIC;
1557
1558 UpdateUsedSlots();
1559 return REC_SUCCESS;
1560 }
StopSpectating(RoomsParticipant * roomsParticipant)1561 RoomsErrorCode Room::StopSpectating(RoomsParticipant* roomsParticipant)
1562 {
1563 RakAssert(roomDestroyed==false);
1564
1565 // Is roomsParticipant a spectator?
1566 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1567 if (roomsParticipantIndex==-1) return REC_STOP_SPECTATING_NOT_IN_ROOM;
1568 if (roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_SPECTATOR_PUBLIC &&
1569 roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_SPECTATOR_RESERVED)
1570 return REC_STOP_SPECTATING_NOT_CURRENTLY_SPECTATING;
1571
1572 // Is the roomOutput locked to players (RLS_ALL_LOCKED or RLS_PLAYERS_LOCKED)?
1573 ParticipantCanJoinRoomResult pcjrr = ParticipantCanJoinAsPlayer(roomsParticipant, false, true);
1574 RakAssert(pcjrr!=PCJRR_BANNED);
1575 if (pcjrr==PCJRR_NO_PUBLIC_OR_RESERVED_SLOTS) return REC_STOP_SPECTATING_NO_SLOTS;
1576 if (pcjrr==PCJRR_LOCKED) return REC_STOP_SPECTATING_ROOM_LOCKED;
1577 RakAssert(pcjrr==PCJRR_SUCCESS);
1578
1579 if (roomMemberList[roomsParticipantIndex]->roomMemberMode==RMM_SPECTATOR_RESERVED && HasOpenReservedSlots())
1580 roomMemberList[roomsParticipantIndex]->roomMemberMode=RMM_RESERVED;
1581 else
1582 roomMemberList[roomsParticipantIndex]->roomMemberMode=RMM_PUBLIC;
1583
1584 UpdateUsedSlots();
1585 return REC_SUCCESS;
1586 }
GrantModerator(RoomsParticipant * roomsParticipant,RoomsParticipant * newModerator,DataStructures::List<InvitedUser> & clearedInvites)1587 RoomsErrorCode Room::GrantModerator(RoomsParticipant* roomsParticipant, RoomsParticipant *newModerator, DataStructures::List<InvitedUser> &clearedInvites)
1588 {
1589 RakAssert(roomDestroyed==false);
1590
1591 // Is roomsParticipant in the roomOutput?
1592 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1593 if (roomsParticipantIndex==-1) return REC_GRANT_MODERATOR_NOT_IN_ROOM;
1594
1595 // Is roomsParticipant the moderator?
1596 if (roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_MODERATOR)
1597 return REC_GRANT_MODERATOR_MUST_BE_MODERATOR_TO_GRANT_MODERATOR;
1598
1599 // Is newModerator in the roomOutput as a player?
1600 unsigned int newModeratorIndex = GetRoomIndex(newModerator);
1601 if (newModeratorIndex==-1) return REC_GRANT_MODERATOR_NEW_MODERATOR_NOT_IN_ROOM;
1602
1603 if (roomMemberList[newModeratorIndex]->roomMemberMode==RMM_SPECTATOR_PUBLIC ||
1604 roomMemberList[newModeratorIndex]->roomMemberMode==RMM_SPECTATOR_RESERVED)
1605 return REC_GRANT_MODERATOR_NEW_MODERATOR_NOT_IN_PLAYABLE_SLOT;
1606
1607 if (roomsParticipant==newModerator)
1608 return REC_GRANT_MODERATOR_CANNOT_PERFORM_ON_SELF;
1609
1610 if (clearInvitesOnNewModerator)
1611 {
1612 // Clear invites
1613 clearedInvites=inviteList;
1614 inviteList.Clear(true, __FILE__, __LINE__ );
1615
1616 // Change RMM_SPECTATOR_RESERVED to RMM_SPECTATOR_PUBLIC
1617 unsigned int i;
1618 for (i=0; i < roomMemberList.Size(); i++)
1619 {
1620 if (roomMemberList[i]->roomMemberMode==RMM_SPECTATOR_RESERVED)
1621 roomMemberList[i]->roomMemberMode=RMM_SPECTATOR_PUBLIC;
1622 }
1623 }
1624
1625 roomMemberList[roomsParticipantIndex]->roomMemberMode=roomMemberList[newModeratorIndex]->roomMemberMode;
1626 roomMemberList[newModeratorIndex]->roomMemberMode=RMM_MODERATOR;
1627
1628 UpdateUsedSlots();
1629 return REC_SUCCESS;
1630 }
ChangeSlotCounts(RoomsParticipant * roomsParticipant,Slots slots)1631 RoomsErrorCode Room::ChangeSlotCounts(RoomsParticipant* roomsParticipant, Slots slots)
1632 {
1633 RakAssert(roomDestroyed==false);
1634
1635 // Is roomsParticipant in the roomOutput?
1636 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1637 if (roomsParticipantIndex==-1) return REC_CHANGE_SLOT_COUNTS_NOT_IN_ROOM;
1638
1639 // Is roomsParticipant the moderator?
1640 if (roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_MODERATOR)
1641 return REC_CHANGE_SLOT_COUNTS_MUST_BE_MODERATOR;
1642
1643 // Validate slots - cannot be negative
1644 RoomsErrorCode roomsErrorCode = slots.Validate();
1645 if (roomsErrorCode!=REC_SUCCESS)
1646 return roomsErrorCode;
1647
1648 SetTotalSlots(&slots);
1649 UpdateUsedSlots();
1650
1651 return REC_SUCCESS;
1652 }
SetCustomRoomProperties(RoomsParticipant * roomsParticipant,DataStructures::Table * table)1653 RoomsErrorCode Room::SetCustomRoomProperties(RoomsParticipant* roomsParticipant, DataStructures::Table *table)
1654 {
1655 RakAssert(roomDestroyed==false);
1656
1657 // Is roomsParticipant in the roomOutput?
1658 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1659 if (roomsParticipantIndex==-1) return REC_SET_CUSTOM_ROOM_PROPERTIES_NOT_IN_ROOM;
1660
1661 // Is roomsParticipant the moderator?
1662 if (roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_MODERATOR)
1663 return REC_SET_CUSTOM_ROOM_PROPERTIES_MUST_BE_MODERATOR;
1664
1665 // Validate table - can only have custom properties, not predefined properties
1666 if (DefaultRoomColumns::HasDefaultColumns(table))
1667 return REC_SET_CUSTOM_ROOM_PROPERTIES_CONTAINS_DEFAULT_COLUMNS;
1668
1669 return REC_SUCCESS;
1670 }
ChangeRoomName(RoomsParticipant * roomsParticipant,RakNet::RakString newRoomName,ProfanityFilter * profanityFilter)1671 RoomsErrorCode Room::ChangeRoomName(RoomsParticipant* roomsParticipant, RakNet::RakString newRoomName, ProfanityFilter *profanityFilter)
1672 {
1673 RakAssert(roomDestroyed==false);
1674
1675 // Is roomsParticipant in the roomOutput?
1676 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1677 if (roomsParticipantIndex==-1) return REC_CHANGE_ROOM_NAME_NOT_IN_ROOM;
1678
1679 // Is roomsParticipant the moderator?
1680 if (roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_MODERATOR)
1681 return REC_CHANGE_ROOM_NAME_MUST_BE_MODERATOR;
1682
1683 // Is newRoomName empty?
1684 if (newRoomName.IsEmpty())
1685 return REC_CHANGE_ROOM_NAME_EMPTY_ROOM_NAME;
1686
1687 // Does newRoomName have profanity?
1688 if (profanityFilter->HasProfanity(newRoomName.C_String()))
1689 return REC_CHANGE_ROOM_NAME_HAS_PROFANITY;
1690
1691 SetStringProperty(DefaultRoomColumns::TC_ROOM_NAME, newRoomName.C_String());
1692 return REC_SUCCESS;
1693 }
SetHiddenFromSearches(RoomsParticipant * roomsParticipant,bool _hiddenFromSearches)1694 RoomsErrorCode Room::SetHiddenFromSearches(RoomsParticipant* roomsParticipant, bool _hiddenFromSearches)
1695 {
1696 RakAssert(roomDestroyed==false);
1697
1698 // Is roomsParticipant in the roomOutput?
1699 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1700 if (roomsParticipantIndex==-1) return REC_SET_HIDDEN_FROM_SEARCHES_NOT_IN_ROOM;
1701
1702 // Is roomsParticipant the moderator?
1703 if (roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_MODERATOR)
1704 return REC_SET_HIDDEN_FROM_SEARCHES_MUST_BE_MODERATOR;
1705
1706 hiddenFromSearches=_hiddenFromSearches;
1707 return REC_SUCCESS;
1708 }
SetDestroyOnModeratorLeave(RoomsParticipant * roomsParticipant,bool destroyOnModeratorLeave)1709 RoomsErrorCode Room::SetDestroyOnModeratorLeave(RoomsParticipant* roomsParticipant, bool destroyOnModeratorLeave)
1710 {
1711 RakAssert(roomDestroyed==false);
1712
1713 // Is roomsParticipant in the roomOutput?
1714 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1715 if (roomsParticipantIndex==-1) return REC_SET_DESTROY_ON_MODERATOR_LEAVE_NOT_IN_ROOM;
1716
1717 // Is roomsParticipant the moderator?
1718 if (roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_MODERATOR)
1719 return REC_SET_DESTROY_ON_MODERATOR_LEAVE_MUST_BE_MODERATOR;
1720
1721 tableRow->cells[DefaultRoomColumns::TC_DESTROY_ON_MODERATOR_LEAVE]->Set((int) destroyOnModeratorLeave);
1722 return REC_SUCCESS;
1723 }
SetReadyStatus(RoomsParticipant * roomsParticipant,bool isReady)1724 RoomsErrorCode Room::SetReadyStatus(RoomsParticipant* roomsParticipant, bool isReady)
1725 {
1726 RakAssert(roomDestroyed==false);
1727
1728 // Is roomsParticipant in the roomOutput?
1729 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1730 if (roomsParticipantIndex==-1) return REC_SET_READY_STATUS_NOT_IN_ROOM;
1731
1732 // Is roomsParticipant a player?
1733 if (roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_MODERATOR &&
1734 roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_PUBLIC &&
1735 roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_RESERVED)
1736 return REC_SET_READY_STATUS_NOT_IN_PLAYABLE_SLOT;
1737
1738 // Is autoLockReadyStatus true, the roomOutput locked or the roomOutput full of players, and all the other players are ready?
1739 bool allReady;
1740 AreAllMembersReady(roomsParticipantIndex,&allReady);
1741 if (autoLockReadyStatus==true &&
1742 isReady==false &&
1743 (AreAllPlayableSlotsFilled() || IsRoomLockedToPlayers()) &&
1744 allReady)
1745 return REC_SET_READY_STATUS_AUTO_LOCK_ALL_PLAYERS_READY;
1746
1747 roomMemberList[roomsParticipantIndex]->isReady=isReady;
1748 return REC_SUCCESS;
1749 }
GetReadyStatus(DataStructures::List<RoomsParticipant * > & readyUsers,DataStructures::List<RoomsParticipant * > & unreadyUsers)1750 RoomsErrorCode Room::GetReadyStatus(DataStructures::List<RoomsParticipant*> &readyUsers, DataStructures::List<RoomsParticipant*> &unreadyUsers)
1751 {
1752 RakAssert(roomDestroyed==false);
1753
1754 readyUsers.Clear(true, __FILE__, __LINE__ );
1755 unreadyUsers.Clear(true, __FILE__, __LINE__ );
1756 unsigned int i;
1757 for (i=0; i < roomMemberList.Size(); i++)
1758 {
1759 if (roomMemberList[i]->isReady)
1760 readyUsers.Insert(roomMemberList[i]->roomsParticipant, __FILE__, __LINE__ );
1761 else
1762 unreadyUsers.Insert(roomMemberList[i]->roomsParticipant, __FILE__, __LINE__ );
1763 }
1764 return REC_SUCCESS;
1765 }
SetRoomLockState(RoomsParticipant * roomsParticipant,RoomLockState _roomLockState)1766 RoomsErrorCode Room::SetRoomLockState(RoomsParticipant* roomsParticipant, RoomLockState _roomLockState)
1767 {
1768 RakAssert(roomDestroyed==false);
1769
1770 // Is roomsParticipant in the roomOutput?
1771 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1772 if (roomsParticipantIndex==-1) return REC_SET_ROOM_LOCK_STATE_NOT_IN_ROOM;
1773
1774 // Is roomsParticipant the moderator?
1775 if (roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_MODERATOR)
1776 return REC_SET_ROOM_LOCK_STATE_MUST_BE_MODERATOR;
1777
1778 // Is roomLockState a valid enumeration value?
1779 if ((int)roomLockState<0 || (int)roomLockState>(int)RLS_ALL_LOCKED)
1780 return REC_SET_ROOM_LOCK_STATE_BAD_ENUMERATION_VALUE;
1781
1782 roomLockState=_roomLockState;
1783 return REC_SUCCESS;
1784 }
GetRoomLockState(RoomLockState * _roomLockState)1785 RoomsErrorCode Room::GetRoomLockState(RoomLockState *_roomLockState)
1786 {
1787 RakAssert(roomDestroyed==false);
1788
1789 *_roomLockState=roomLockState;
1790 return REC_SUCCESS;
1791 }
AreAllMembersReady(unsigned int exceptThisIndex,bool * allReady)1792 RoomsErrorCode Room::AreAllMembersReady(unsigned int exceptThisIndex, bool *allReady)
1793 {
1794 RakAssert(roomDestroyed==false);
1795
1796 // Is the ready status for all members true?
1797 unsigned int i;
1798 for (i=0; i < roomMemberList.Size(); i++)
1799 {
1800 if (roomMemberList[i]->isReady==false && i!=exceptThisIndex)
1801 {
1802 *allReady=false;
1803 return REC_SUCCESS;
1804 }
1805 }
1806
1807 *allReady=true;
1808 return REC_SUCCESS;
1809 }
KickMember(RoomsParticipant * roomsParticipant,RoomsParticipant * kickedParticipant,RakNet::RakString reason)1810 RoomsErrorCode Room::KickMember(RoomsParticipant* roomsParticipant, RoomsParticipant *kickedParticipant, RakNet::RakString reason )
1811 {
1812 RakAssert(roomDestroyed==false);
1813
1814 // Is roomsParticipant in the roomOutput?
1815 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1816 if (roomsParticipantIndex==-1) return REC_KICK_MEMBER_NOT_IN_ROOM;
1817
1818 // Is roomsParticipant the moderator?
1819 if (roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_MODERATOR)
1820 return REC_KICK_MEMBER_MUST_BE_MODERATOR;
1821
1822 // Is kickedParticipant in the roomOutput, or in a spectator slot?
1823 unsigned int kickedParticipantIndex = GetRoomIndex(kickedParticipant);
1824 if (kickedParticipantIndex==-1) return REC_KICK_MEMBER_TARGET_NOT_IN_YOUR_ROOM;
1825
1826 if (roomsParticipant==kickedParticipant)
1827 return REC_KICK_MEMBER_CANNOT_PERFORM_ON_SELF;
1828
1829 kickedParticipant->SetRoom(0);
1830 roomMemberList.RemoveAtIndex(kickedParticipantIndex);
1831
1832 if (GetBannedIndex(kickedParticipant->GetName())==-1)
1833 {
1834 BannedUser bannedUser;
1835 bannedUser.reason=reason;
1836 bannedUser.target=kickedParticipant->GetName();
1837 banList.Insert(bannedUser, __FILE__, __LINE__ );
1838 }
1839
1840 return REC_SUCCESS;
1841 }
UnbanMember(RoomsParticipant * roomsParticipant,RakNet::RakString name)1842 RoomsErrorCode Room::UnbanMember(RoomsParticipant* roomsParticipant, RakNet::RakString name)
1843 {
1844 RakAssert(roomDestroyed==false);
1845
1846 // Is roomsParticipant in the roomOutput?
1847 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1848 if (roomsParticipantIndex==-1) return REC_UNBAN_MEMBER_NOT_IN_ROOM;
1849
1850 // Is roomsParticipant the moderator?
1851 if (roomMemberList[roomsParticipantIndex]->roomMemberMode!=RMM_MODERATOR)
1852 return REC_UNBAN_MEMBER_MUST_BE_MODERATOR;
1853
1854 unsigned int banIndex = GetBannedIndex(name);
1855 if (banIndex==-1)
1856 return REC_UNBAN_MEMBER_NOT_BANNED;
1857
1858 banList.RemoveAtIndexFast(banIndex);
1859
1860 return REC_SUCCESS;
1861 }
GetBanReason(RakNet::RakString name,RakNet::RakString * reason)1862 RoomsErrorCode Room::GetBanReason(RakNet::RakString name, RakNet::RakString *reason)
1863 {
1864 RakAssert(roomDestroyed==false);
1865 unsigned int banIndex = GetBannedIndex(name);
1866 if (banIndex==-1)
1867 return REC_GET_BAN_REASON_NOT_BANNED;
1868
1869 *reason = banList[banIndex].reason;
1870
1871 return REC_SUCCESS;
1872 }
LeaveRoom(RoomsParticipant * roomsParticipant,RemoveUserResult * removeUserResult)1873 RoomsErrorCode Room::LeaveRoom(RoomsParticipant* roomsParticipant, RemoveUserResult *removeUserResult)
1874 {
1875 RakAssert(roomDestroyed==false);
1876
1877 return RemoveUser(roomsParticipant,removeUserResult);
1878 }
1879 /*
1880 RoomsErrorCode Room::GetKickReason(RoomsParticipant* roomsParticipant, RakNet::RakString *kickReason)
1881 {
1882 RakAssert(roomDestroyed==false);
1883
1884 // Is roomsParticipant in a kick slot?
1885 unsigned int roomsParticipantIndex = GetKickSlotIndex(roomsParticipant);
1886 if (roomsParticipantIndex==-1) return REC_GET_KICK_REASON_NOT_KICKED;
1887
1888 *kickReason=kickedList[roomsParticipantIndex].reason;
1889 return REC_SUCCESS;
1890 }
1891 */
JoinByFilter(RoomsParticipant * roomsParticipant,RoomMemberMode roomMemberMode,JoinedRoomResult * joinRoomResult)1892 RoomsErrorCode Room::JoinByFilter(RoomsParticipant* roomsParticipant, RoomMemberMode roomMemberMode, JoinedRoomResult *joinRoomResult)
1893 {
1894 RakAssert(roomDestroyed==false);
1895
1896 if (roomMemberMode==RMM_MODERATOR) return REC_JOIN_BY_FILTER_CANNOT_JOIN_AS_MODERATOR;
1897 // Is the roomOutput locked for the target slot type (any slot and RLS_ALL_LOCKED, or player and RLS_PLAYERS_LOCKED)?
1898 joinRoomResult->roomOutput=0;
1899 bool joinAsSpectator = roomMemberMode==RMM_SPECTATOR_PUBLIC || roomMemberMode==RMM_SPECTATOR_RESERVED || roomMemberMode==RMM_ANY_SPECTATOR;
1900 ParticipantCanJoinRoomResult pcjrr = ParticipantCanJoinRoom(roomsParticipant, joinAsSpectator, true);
1901 if (pcjrr==PCJRR_BANNED) return REC_JOIN_BY_FILTER_BANNED;
1902 if (pcjrr==PCJRR_NO_PUBLIC_SLOTS || pcjrr==PCJRR_NO_PUBLIC_OR_RESERVED_SLOTS) return REC_JOIN_BY_FILTER_NO_SLOTS;
1903 if (pcjrr==PCJRR_LOCKED) return REC_JOIN_BY_FILTER_ROOM_LOCKED;
1904 RakAssert(pcjrr==PCJRR_SUCCESS);
1905
1906 joinRoomResult->roomOutput=this;
1907 unsigned int firstInviteIndex = GetFirstInviteIndex(roomsParticipant->GetName());
1908 if (roomMemberMode==RMM_ANY_SPECTATOR)
1909 {
1910 if (firstInviteIndex==-1)
1911 roomMemberMode=RMM_SPECTATOR_PUBLIC;
1912 else
1913 roomMemberMode=RMM_SPECTATOR_RESERVED;
1914 }
1915 else if (roomMemberMode==RMM_ANY_PLAYABLE)
1916 {
1917 if (firstInviteIndex==-1)
1918 roomMemberMode=RMM_PUBLIC;
1919 else
1920 roomMemberMode=RMM_RESERVED;
1921 }
1922 RoomMember *rm = new RoomMember;
1923 rm->roomsParticipant=roomsParticipant;
1924 rm->roomMemberMode=roomMemberMode;
1925 roomMemberList.Insert(rm, __FILE__, __LINE__ );
1926 roomsParticipant->SetRoom(this);
1927
1928 if (firstInviteIndex!=-1)
1929 {
1930 joinRoomResult->acceptedInvitor=roomMemberList[firstInviteIndex]->roomsParticipant;
1931 inviteList.RemoveAtIndex(firstInviteIndex);
1932 }
1933 else
1934 joinRoomResult->acceptedInvitor=0;
1935
1936 // Moderator does not count towards a slot
1937 UpdateUsedSlots();
1938 RakAssert(GetNumericProperty(DefaultRoomColumns::TC_USED_SLOTS)==roomMemberList.Size()-1);
1939
1940 joinRoomResult->joiningMember=roomsParticipant;
1941 return REC_SUCCESS;
1942 }
JoinByQuickJoin(RoomsParticipant * roomsParticipant,RoomMemberMode roomMemberMode,JoinedRoomResult * joinRoomResult)1943 RoomsErrorCode Room::JoinByQuickJoin(RoomsParticipant* roomsParticipant, RoomMemberMode roomMemberMode, JoinedRoomResult *joinRoomResult)
1944 {
1945 RakAssert(roomDestroyed==false);
1946
1947 // Use same function, just add to the error code if one is returned
1948 RoomsErrorCode roomsErrorCode = JoinByFilter(roomsParticipant, roomMemberMode, joinRoomResult);
1949 if (roomsErrorCode!=REC_SUCCESS)
1950 {
1951 int val = (int) roomsErrorCode;
1952 val += (int)REC_JOIN_BY_QUICK_JOIN_CANNOT_JOIN_AS_MODERATOR-(int)REC_JOIN_BY_FILTER_CANNOT_JOIN_AS_MODERATOR;
1953 roomsErrorCode=(RoomsErrorCode)val;
1954 }
1955 else
1956 {
1957 // Moderator does not count towards a slot
1958 UpdateUsedSlots();
1959 RakAssert(GetNumericProperty(DefaultRoomColumns::TC_USED_SLOTS)==roomMemberList.Size()-1);
1960 }
1961 return roomsErrorCode;
1962 }
ParticipantCanJoinRoom(RoomsParticipant * roomsParticipant,bool asSpectator,bool checkHasInvite)1963 ParticipantCanJoinRoomResult Room::ParticipantCanJoinRoom( RoomsParticipant* roomsParticipant, bool asSpectator, bool checkHasInvite )
1964 {
1965 RakAssert(roomDestroyed==false);
1966
1967 // Is roomsParticipant already in the room?
1968 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
1969 if (roomsParticipantIndex!=-1)
1970 return PCJRR_SLOT_ALREADY_USED;
1971
1972 return ParticipantCanJoinAsPlayer(roomsParticipant, asSpectator, checkHasInvite);
1973 }
ParticipantCanJoinAsPlayer(RoomsParticipant * roomsParticipant,bool asSpectator,bool checkHasInvite)1974 ParticipantCanJoinRoomResult Room::ParticipantCanJoinAsPlayer( RoomsParticipant* roomsParticipant, bool asSpectator, bool checkHasInvite )
1975 {
1976 // Is the room locked?
1977 if (roomLockState==RLS_PLAYERS_LOCKED && asSpectator==false)
1978 return PCJRR_LOCKED;
1979
1980 // Is the room locked?
1981 if (roomLockState==RLS_ALL_LOCKED)
1982 return PCJRR_LOCKED;
1983
1984 // Is the player banned?
1985 if (GetBannedIndex(roomsParticipant->GetName())!=-1)
1986 return PCJRR_BANNED;
1987
1988 // Any slots?
1989 bool hasInvite = HasInvite(roomsParticipant->GetName());
1990 bool publicAvailable = HasOpenPublicSlots();
1991
1992 if (asSpectator==false)
1993 {
1994 if (hasInvite==false && checkHasInvite)
1995 {
1996 if (publicAvailable==false)
1997 return PCJRR_NO_PUBLIC_SLOTS;
1998 }
1999
2000 // Invited will join public if no reserved slots are open
2001 bool reservedAvailable = HasOpenReservedSlots();
2002 if (publicAvailable==false && reservedAvailable==false)
2003 return PCJRR_NO_PUBLIC_OR_RESERVED_SLOTS;
2004 }
2005 else
2006 {
2007 if (HasOpenSpectatorSlots()==false)
2008 return PCJRR_NO_SPECTATOR_SLOTS;
2009 }
2010
2011 return PCJRR_SUCCESS;
2012 }
IsRoomDead(void) const2013 bool Room::IsRoomDead(void) const
2014 {
2015 return roomMemberList.Size()==0 || roomDestroyed==true;
2016 }
GetInvitesToParticipant(RoomsParticipant * roomsParticipant,DataStructures::List<InvitedUser * > & invites)2017 RoomsErrorCode Room::GetInvitesToParticipant(RoomsParticipant* roomsParticipant, DataStructures::List<InvitedUser*> &invites)
2018 {
2019 RakAssert(roomDestroyed==false);
2020
2021 unsigned int i;
2022 for (i=0; i < inviteList.Size(); i++)
2023 {
2024 if (inviteList[i].target==roomsParticipant->GetName())
2025 invites.Insert(&inviteList[i], __FILE__, __LINE__ );
2026 }
2027 return REC_SUCCESS;
2028 }
GetModerator(void) const2029 RoomsParticipant* Room::GetModerator(void) const
2030 {
2031 unsigned int i;
2032 for (i=0; i < roomMemberList.Size(); i++)
2033 if (roomMemberList[i]->roomMemberMode==RMM_MODERATOR)
2034 return roomMemberList[i]->roomsParticipant;
2035 RakAssert("Room::GetModerator: Room should always have a moderator" && 0);
2036 return 0;
2037 }
GetID(void) const2038 RoomID Room::GetID(void) const
2039 {
2040 return lobbyRoomId;
2041 }
GetNumericProperty(int index) const2042 double Room::GetNumericProperty(int index) const
2043 {
2044 return tableRow->cells[index]->i;
2045 }
GetStringProperty(int index) const2046 const char *Room::GetStringProperty(int index) const
2047 {
2048 return tableRow->cells[index]->c;
2049 }
SetNumericProperty(int index,double value)2050 void Room::SetNumericProperty(int index, double value)
2051 {
2052 tableRow->cells[index]->Set(value);
2053 }
SetStringProperty(int index,const char * value)2054 void Room::SetStringProperty(int index, const char *value)
2055 {
2056 tableRow->cells[index]->Set(value);
2057 }
RemoveUser(RoomsParticipant * roomsParticipant,RemoveUserResult * removeUserResult)2058 RoomsErrorCode Room::RemoveUser(RoomsParticipant* roomsParticipant,RemoveUserResult *removeUserResult)
2059 {
2060 RakAssert(roomDestroyed==false);
2061
2062 removeUserResult->gotNewModerator=false;
2063 removeUserResult->removedFromRoom=false;
2064 removeUserResult->room=this;
2065 unsigned int roomsParticipantIndex = GetRoomIndex(roomsParticipant);
2066 if (roomsParticipantIndex==-1) return REC_REMOVE_USER_NOT_IN_ROOM;
2067 removeUserResult->removedFromRoom=true;
2068 removeUserResult->removedUserAddress=roomsParticipant->GetSystemAddress();
2069 removeUserResult->removedUserName=roomsParticipant->GetName();
2070
2071 if (roomMemberList[roomsParticipantIndex]->roomMemberMode==RMM_MODERATOR)
2072 {
2073 int destroyOnModeratorLeave;
2074 tableRow->cells[DefaultRoomColumns::TC_DESTROY_ON_MODERATOR_LEAVE]->Get(&destroyOnModeratorLeave);
2075 if (destroyOnModeratorLeave || roomMemberList.Size()==1)
2076 {
2077 removeUserResult->clearedInvitations=inviteList;
2078 inviteList.Clear(false, __FILE__, __LINE__);
2079
2080 removeUserResult->roomDestroyed=true;
2081 unsigned int i;
2082 for (i=0; i < roomMemberList.Size(); i++)
2083 roomMemberList[i]->roomsParticipant->SetRoom(0);
2084 roomDestroyed=true;
2085 removeUserResult->roomDestroyed=true;
2086 // Up to caller to call PerGamesRoomContainer::DestroyRoom();
2087 return REC_SUCCESS;
2088 }
2089
2090 // Transfer moderator to the next player, if any. Reserved slot players take priority to be moderator.
2091 unsigned int nextModIndex;
2092 for (nextModIndex = 0; nextModIndex < roomMemberList.Size(); nextModIndex++)
2093 {
2094 if (roomMemberList[nextModIndex]->roomMemberMode==RMM_RESERVED)
2095 {
2096 roomMemberList[nextModIndex]->roomMemberMode=RMM_MODERATOR;
2097 removeUserResult->gotNewModerator=true;
2098 break;
2099 }
2100 }
2101 if (removeUserResult->gotNewModerator==false)
2102 {
2103 for (nextModIndex = 0; nextModIndex < roomMemberList.Size(); nextModIndex++)
2104 {
2105 if (roomMemberList[nextModIndex]->roomMemberMode==RMM_PUBLIC)
2106 {
2107 roomMemberList[nextModIndex]->roomMemberMode=RMM_MODERATOR;
2108 removeUserResult->gotNewModerator=true;
2109 break;
2110 }
2111 }
2112 }
2113
2114 // If moderator and clearInvitesOnNewModerator, clear invitations and add to removeUserResult->clearedInvitations
2115 if (clearInvitesOnNewModerator)
2116 {
2117 removeUserResult->clearedInvitations=inviteList;
2118 inviteList.Clear(false, __FILE__, __LINE__);
2119
2120 unsigned int i;
2121 for (i=0; i < roomMemberList.Size(); i++)
2122 {
2123 if (roomMemberList[i]->roomMemberMode==RMM_SPECTATOR_RESERVED)
2124 roomMemberList[i]->roomMemberMode=RMM_SPECTATOR_PUBLIC;
2125 }
2126 }
2127 }
2128
2129 delete roomMemberList[roomsParticipantIndex];
2130 roomMemberList.RemoveAtIndex(roomsParticipantIndex);
2131 roomsParticipant->SetRoom(0);
2132 removeUserResult->roomDestroyed=IsRoomDead();
2133 roomDestroyed=removeUserResult->roomDestroyed;
2134 removeUserResult->removedFromRoom=true;
2135 if (removeUserResult->roomDestroyed==false)
2136 UpdateUsedSlots();
2137
2138 return REC_SUCCESS;
2139
2140 }
IsRoomLockedToSpectators(void) const2141 bool Room::IsRoomLockedToSpectators(void) const
2142 {
2143 return roomLockState==RLS_ALL_LOCKED;
2144 }
IsRoomLockedToPlayers(void) const2145 bool Room::IsRoomLockedToPlayers(void) const
2146 {
2147 return roomLockState==RLS_PLAYERS_LOCKED || roomLockState==RLS_ALL_LOCKED;
2148 }
IsInRoom(RoomsParticipant * roomsParticipant) const2149 bool Room::IsInRoom(RoomsParticipant* roomsParticipant) const
2150 {
2151 return GetRoomIndex(roomsParticipant)!=-1;
2152 }
HasInvite(RakNet::RakString roomsParticipant)2153 bool Room::HasInvite(RakNet::RakString roomsParticipant)
2154 {
2155 return GetFirstInviteIndex(roomsParticipant)!=-1;
2156 }
GetRoomIndex(RoomsParticipant * roomsParticipant) const2157 unsigned int Room::GetRoomIndex(RoomsParticipant* roomsParticipant) const
2158 {
2159 unsigned int i;
2160 for (i=0; i < roomMemberList.Size(); i++)
2161 if (roomMemberList[i]->roomsParticipant==roomsParticipant)
2162 return i;
2163 return (unsigned int) -1;
2164 }
2165 /*
2166 unsigned int Room::GetKickSlotIndex(RoomsParticipant* roomsParticipant) const
2167 {
2168 unsigned int i;
2169 for (i=0; i < kickedList.Size(); i++)
2170 if (kickedList[i].roomsParticipant==roomsParticipant)
2171 return i;
2172 return -1;
2173 }
2174 */
GetBannedIndex(RakNet::RakString username) const2175 unsigned int Room::GetBannedIndex(RakNet::RakString username) const
2176 {
2177 unsigned int i;
2178 for (i=0; i < banList.Size(); i++)
2179 if (banList[i].target==username)
2180 return i;
2181 return (unsigned int) -1;
2182 }
GetInviteIndex(RakNet::RakString invitee,RakNet::RakString invitor) const2183 unsigned int Room::GetInviteIndex(RakNet::RakString invitee, RakNet::RakString invitor) const
2184 {
2185 unsigned int i;
2186 for (i=0; i < inviteList.Size(); i++)
2187 if (inviteList[i].target==invitee && inviteList[i].invitorName==invitor)
2188 return i;
2189 return (unsigned int) -1;
2190 }
GetFirstInviteIndex(RakNet::RakString invitee) const2191 unsigned int Room::GetFirstInviteIndex(RakNet::RakString invitee) const
2192 {
2193 unsigned int i;
2194 for (i=0; i < inviteList.Size(); i++)
2195 if (inviteList[i].target==invitee)
2196 return i;
2197 return (unsigned int) -1;
2198 }
AreAllPlayableSlotsFilled(void) const2199 bool Room::AreAllPlayableSlotsFilled(void) const
2200 {
2201 return HasOpenPublicSlots()==false && HasOpenReservedSlots()==false;
2202 }
HasOpenPublicSlots(void) const2203 bool Room::HasOpenPublicSlots(void) const
2204 {
2205 return GetNumericProperty(DefaultRoomColumns::TC_REMAINING_PUBLIC_SLOTS)!=0.0;
2206 }
HasOpenReservedSlots(void) const2207 bool Room::HasOpenReservedSlots(void) const
2208 {
2209 return GetNumericProperty(DefaultRoomColumns::TC_REMAINING_RESERVED_SLOTS)!=0.0;
2210 }
HasOpenSpectatorSlots(void) const2211 bool Room::HasOpenSpectatorSlots(void) const
2212 {
2213 return GetNumericProperty(DefaultRoomColumns::TC_REMAINING_SPECTATOR_SLOTS)!=0.0;
2214 }
IsHiddenToParticipant(RoomsParticipant * roomsParticipant) const2215 bool Room::IsHiddenToParticipant(RoomsParticipant* roomsParticipant) const
2216 {
2217 if (hiddenFromSearches==false)
2218 return false;
2219 if (IsInRoom(roomsParticipant))
2220 return false;
2221 if (GetFirstInviteIndex(roomsParticipant->GetName())!=-1)
2222 return false;
2223 return true;
2224 }
ChangeHandle(RakNet::RakString oldHandle,RakNet::RakString newHandle)2225 void Room::ChangeHandle(RakNet::RakString oldHandle, RakNet::RakString newHandle)
2226 {
2227 if (oldHandle==newHandle)
2228 return;
2229 unsigned int index;
2230 index = GetBannedIndex(newHandle);
2231 RakAssert(index==-1);
2232 index = GetFirstInviteIndex(newHandle);
2233 RakAssert(index==-1);
2234 index = GetBannedIndex(oldHandle);
2235 if (index!=-1)
2236 banList[index].target=newHandle;
2237 for (index=0; index < inviteList.Size(); index++)
2238 {
2239 if (inviteList[index].target==oldHandle)
2240 inviteList[index].target=newHandle;
2241 if (inviteList[index].invitorName==oldHandle)
2242 inviteList[index].invitorName=newHandle;
2243 }
2244 }
2245 // ---------------------------- UNIT TEST ----------------------------
UnitTest(void)2246 void AllGamesRoomsContainer::UnitTest(void)
2247 {
2248 RoomsErrorCodeDescription::Validate();
2249
2250 AllGamesRoomsContainer agrc;
2251 RoomsErrorCode roomsErrorCode;
2252 GameIdentifier gameIdentifier1, gameIdentifier2;
2253 DataStructures::List<InvitedUser> clearedInvitations;
2254 gameIdentifier1="gameIdentifier1";
2255 gameIdentifier2="gameIdentifier2";
2256 RoomsParticipant roomsParticipant1, roomsParticipant2;
2257 roomsParticipant1.SetName("roomsParticipant1");
2258 roomsParticipant2.SetName("roomsParticipant2");
2259 RoomQuery roomQuery;
2260 roomQuery.numQueries=2;
2261 DataStructures::Table::FilterQuery filterQuery[2];
2262 roomQuery.queries=filterQuery;
2263 DataStructures::Table::Cell cells[2];
2264 filterQuery[0].cellValue=&cells[0];
2265 filterQuery[1].cellValue=&cells[1];
2266 strcpy(filterQuery[0].columnName, "LevelName");
2267 strcpy(filterQuery[1].columnName, "FlagCaptureCount");
2268 filterQuery[0].operation=DataStructures::Table::QF_EQUAL;
2269 filterQuery[1].operation=DataStructures::Table::QF_NOT_EQUAL;
2270 cells[0].Set("DogFoodLevel");
2271 cells[1].Set(10);
2272 DataStructures::OrderedList<Room*, Room*, RoomsSortByName> roomsOutput;
2273 bool onlyJoinable;
2274 RemoveUserResult removeUserResult;
2275 QuickJoinUser quickJoinUser;
2276 DataStructures::List<QuickJoinUser*> timeoutExpired;
2277 DataStructures::List<JoinedRoomResult> joinedRoomMembers;
2278 Room *room;
2279 RoomCreationParameters roomCreationParameters;
2280 quickJoinUser.networkedQuickJoinUser.minimumPlayers=2;
2281 quickJoinUser.networkedQuickJoinUser.query=roomQuery;
2282 quickJoinUser.roomsParticipant=&roomsParticipant1;
2283 quickJoinUser.networkedQuickJoinUser.timeout=5000;
2284 ProfanityFilter profanityFilter;
2285 profanityFilter.AddWord("BADWORD");
2286 DataStructures::Table customRoomProperties;
2287 customRoomProperties.AddColumn(filterQuery[0].columnName, DataStructures::Table::STRING);
2288 customRoomProperties.AddColumn(filterQuery[1].columnName, DataStructures::Table::NUMERIC);
2289 DataStructures::List<QuickJoinUser*> dereferencedPointers;
2290 DataStructures::List<DataStructures::Table::Cell*> cellList;
2291 DataStructures::List<InvitedUser*> invites;
2292 RakNet::RakString kickReason;
2293 cellList.Insert(&cells[0], __FILE__, __LINE__ );
2294 cellList.Insert(&cells[1], __FILE__, __LINE__ );
2295 customRoomProperties.AddRow(0, cellList);
2296
2297 // Search by filter
2298 onlyJoinable=true;
2299 roomsErrorCode = agrc.SearchByFilter( gameIdentifier1, &roomsParticipant1, &roomQuery, roomsOutput, onlyJoinable );
2300 RakAssert(roomsErrorCode==REC_SEARCH_BY_FILTER_UNKNOWN_TITLE);
2301
2302 // leave room
2303 roomsErrorCode = agrc.LeaveRoom(&roomsParticipant1, &removeUserResult);
2304 RakAssert(roomsErrorCode==REC_LEAVE_ROOM_NOT_IN_ROOM);
2305
2306 // Add title
2307 roomsErrorCode = agrc.AddTitle(gameIdentifier1);
2308 RakAssert(roomsErrorCode==REC_SUCCESS);
2309 roomsErrorCode = agrc.AddTitle(gameIdentifier1);
2310 RakAssert(roomsErrorCode==REC_ADD_TITLE_ALREADY_IN_USE);
2311
2312 // Search by filter
2313 roomsErrorCode = agrc.SearchByFilter( gameIdentifier1, &roomsParticipant1, &roomQuery, roomsOutput, onlyJoinable );
2314 RakAssert(roomsErrorCode==REC_SUCCESS);
2315
2316 // Search by filter (another game)
2317 roomsErrorCode = agrc.SearchByFilter( gameIdentifier2, &roomsParticipant1, &roomQuery, roomsOutput, onlyJoinable );
2318 RakAssert(roomsErrorCode==REC_SEARCH_BY_FILTER_UNKNOWN_TITLE);
2319
2320 // leave room
2321 roomsErrorCode = agrc.LeaveRoom( &roomsParticipant1, &removeUserResult);
2322 RakAssert(roomsErrorCode==REC_LEAVE_ROOM_NOT_IN_ROOM);
2323
2324 // Quick join
2325 roomsErrorCode = agrc.AddUserToQuickJoin(gameIdentifier1, &quickJoinUser);
2326 RakAssert(roomsErrorCode==REC_SUCCESS);
2327
2328 // Process quick join
2329 roomsErrorCode = agrc.ProcessQuickJoins( timeoutExpired, joinedRoomMembers, dereferencedPointers, 1000);
2330 RakAssert(roomsErrorCode==REC_SUCCESS);
2331
2332 // Let timeout expire
2333 // Process quick join
2334 roomsErrorCode = agrc.ProcessQuickJoins( timeoutExpired, joinedRoomMembers, dereferencedPointers, 5000);
2335 RakAssert(roomsErrorCode==REC_SUCCESS);
2336 RakAssert(timeoutExpired.Size()==1 && timeoutExpired[0]==&quickJoinUser);
2337
2338 // Quick join
2339 roomsErrorCode = agrc.AddUserToQuickJoin(gameIdentifier1, &quickJoinUser);
2340 RakAssert(roomsErrorCode==REC_SUCCESS);
2341
2342 // Quick join (should fail)
2343 roomsErrorCode = agrc.AddUserToQuickJoin(gameIdentifier1, &quickJoinUser);
2344 RakAssert(roomsErrorCode==REC_ADD_TO_QUICK_JOIN_ALREADY_THERE);
2345
2346 // Create room (should fail due to in quick join)
2347 roomCreationParameters.networkedRoomCreationParameters.inviteToRoomPermission=NetworkedRoomCreationParameters::INVITE_MODE_RESERVED_SLOTS_CAN_INVITE;
2348 roomCreationParameters.networkedRoomCreationParameters.inviteToSpectatorSlotPermission=NetworkedRoomCreationParameters::INVITE_MODE_RESERVED_SLOTS_CAN_INVITE;
2349 roomCreationParameters.networkedRoomCreationParameters.autoLockReadyStatus=true;
2350 roomCreationParameters.networkedRoomCreationParameters.clearInvitesOnNewModerator=true;
2351 roomCreationParameters.networkedRoomCreationParameters.roomName="BADWORD room";
2352 roomCreationParameters.firstUser=&roomsParticipant1;
2353 roomCreationParameters.gameIdentifier=gameIdentifier1;
2354 roomCreationParameters.networkedRoomCreationParameters.slots.publicSlots=1;
2355 roomCreationParameters.networkedRoomCreationParameters.slots.reservedSlots=1;
2356 roomCreationParameters.networkedRoomCreationParameters.slots.spectatorSlots=1;
2357 roomsErrorCode = agrc.CreateRoom(&roomCreationParameters, &profanityFilter);
2358 RakAssert(roomsErrorCode==REC_CREATE_ROOM_CURRENTLY_IN_QUICK_JOIN);
2359
2360 // Cancel quick join
2361 QuickJoinUser *qju;
2362 roomsErrorCode = agrc.RemoveUserFromQuickJoin(quickJoinUser.roomsParticipant, &qju);
2363 RakAssert(roomsErrorCode==REC_SUCCESS);
2364
2365 // Create room (should fail due to bad word)
2366 roomsErrorCode = agrc.CreateRoom(&roomCreationParameters, &profanityFilter);
2367 RakAssert(roomsErrorCode==REC_ROOM_CREATION_PARAMETERS_ROOM_NAME_HAS_PROFANITY);
2368
2369 // Create room
2370 roomCreationParameters.networkedRoomCreationParameters.roomName="My room";
2371 roomsErrorCode = agrc.CreateRoom(&roomCreationParameters, &profanityFilter);
2372 RakAssert(roomsErrorCode==REC_SUCCESS);
2373 RakAssert(roomCreationParameters.roomOutput);
2374
2375 // Create room (should fail due to already in room)
2376 roomsErrorCode = agrc.CreateRoom(&roomCreationParameters, &profanityFilter);
2377 RakAssert(roomsErrorCode==REC_CREATE_ROOM_CURRENTLY_IN_A_ROOM);
2378
2379 // Quick join (should fail due to already in room)
2380 roomsErrorCode = agrc.AddUserToQuickJoin(gameIdentifier1, &quickJoinUser);
2381 RakAssert(roomsErrorCode==REC_ADD_TO_QUICK_JOIN_CURRENTLY_IN_A_ROOM);
2382
2383 // Search by filter
2384 roomsErrorCode = agrc.SearchByFilter( gameIdentifier1, &roomsParticipant1, &roomQuery, roomsOutput, onlyJoinable );
2385 RakAssert(roomsErrorCode==REC_SUCCESS);
2386 RakAssert(roomsOutput.Size()==0);
2387
2388 // Set room properties (Should fail due to not being in the room)
2389 roomsErrorCode = agrc.SetCustomRoomProperties( &roomsParticipant2, &customRoomProperties );
2390 RakAssert(roomsErrorCode==REC_SET_CUSTOM_ROOM_PROPERTIES_UNKNOWN_ROOM_ID);
2391
2392 // Set room properties
2393 roomsErrorCode = agrc.SetCustomRoomProperties( &roomsParticipant1, &customRoomProperties );
2394 RakAssert(roomsErrorCode==REC_SUCCESS);
2395
2396 // Search by filter, including not joinable
2397 RakAssert(&filterQuery[1]==&roomQuery.queries[1]);
2398 roomQuery.queries[1].cellValue->Set(1234); // Query 1 is not equal, change to something else
2399 roomsErrorCode = agrc.SearchByFilter( gameIdentifier1, &roomsParticipant1, &roomQuery, roomsOutput, false );
2400 RakAssert(roomsErrorCode==REC_SUCCESS);
2401 RakAssert(roomsOutput.Size()==1);
2402
2403 // Invite member to room (yourself, should fail)
2404 roomsErrorCode = agrc.SendInvite( &roomsParticipant1, &roomsParticipant1, false, "SendInviteSubject", "SendInviteBody" );
2405 RakAssert(roomsErrorCode==REC_SEND_INVITE_CANNOT_PERFORM_ON_SELF);
2406
2407 // Invite member to room
2408 roomsErrorCode = agrc.SendInvite( &roomsParticipant1, &roomsParticipant2, false, "SendInviteSubject", "SendInviteBody" );
2409 RakAssert(roomsErrorCode==REC_SUCCESS);
2410
2411 // Get invites to member
2412 roomsErrorCode = agrc.GetInvitesToParticipant(&roomsParticipant2, invites);
2413 RakAssert(roomsErrorCode==REC_SUCCESS);
2414 RakAssert(invites.Size()==1);
2415 RakAssert(invites[0]->subject=="SendInviteSubject");
2416 RakAssert(invites[0]->invitorName==roomsParticipant1.GetName());
2417
2418 // Leave room
2419 roomsErrorCode = agrc.LeaveRoom( &roomsParticipant1, &removeUserResult);
2420 RakAssert(roomsParticipant1.GetRoom()==0);
2421 RakAssert(roomsErrorCode==REC_SUCCESS);
2422 RakAssert(removeUserResult.removedFromQuickJoin==false);
2423 RakAssert(removeUserResult.removedFromRoom==true);
2424 RakAssert(removeUserResult.room==roomCreationParameters.roomOutput);
2425 RakAssert(removeUserResult.clearedInvitations.Size()==1);
2426 RakAssert(removeUserResult.roomDestroyed==true);
2427
2428 // Clear room pointer
2429 agrc.DestroyRoomIfDead(removeUserResult.room);
2430
2431 // Create room
2432 // Clear invites on moderator changes or leaves
2433 roomCreationParameters.networkedRoomCreationParameters.destroyOnModeratorLeave=false;
2434 roomCreationParameters.networkedRoomCreationParameters.clearInvitesOnNewModerator=true;
2435 roomsErrorCode = agrc.CreateRoom(&roomCreationParameters, &profanityFilter);
2436 RakAssert(roomsErrorCode==REC_SUCCESS);
2437 RakAssert(roomCreationParameters.roomOutput);
2438 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==0);
2439
2440 // Invite member to room
2441 roomsErrorCode = agrc.SendInvite( &roomsParticipant1, &roomsParticipant2, false, "SendInviteSubject", "SendInviteBody" );
2442 RakAssert(roomsErrorCode==REC_SUCCESS);
2443 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==0);
2444
2445 // member accepts invite (backwards parameters)
2446 roomsErrorCode = agrc.AcceptInvite( roomsParticipant1.GetRoom()->GetID(), &room, &roomsParticipant1, roomsParticipant2.GetName() );
2447 RakAssert(roomsErrorCode==REC_ACCEPT_INVITE_CURRENTLY_IN_A_ROOM);
2448 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==0);
2449
2450 // member accepts invite (correct parameters)
2451 roomsErrorCode = agrc.AcceptInvite( roomsParticipant1.GetRoom()->GetID(), &room, &roomsParticipant2, roomsParticipant1.GetName() );
2452 RakAssert(roomsErrorCode==REC_SUCCESS);
2453 RakAssert(roomsParticipant2.GetRoom()!=0);
2454 RakAssert(roomsParticipant1.GetRoom()==roomsParticipant2.GetRoom());
2455 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==1);
2456
2457 // change moderator
2458 roomsErrorCode = agrc.GrantModerator( &roomsParticipant1, &roomsParticipant2, clearedInvitations );
2459 RakAssert(roomsErrorCode==REC_SUCCESS);
2460 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==1);
2461
2462 // new member invites existing member
2463 roomsErrorCode = agrc.SendInvite( &roomsParticipant2, &roomsParticipant1, false, "SendInviteSubject", "SendInviteBody" );
2464 RakAssert(roomsErrorCode==REC_SEND_INVITE_INVITEE_ALREADY_IN_THIS_ROOM);
2465 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==1);
2466
2467 // Moderator leaves
2468 roomsErrorCode = agrc.LeaveRoom( &roomsParticipant2, &removeUserResult );
2469 RakAssert(roomsErrorCode==REC_SUCCESS);
2470 RakAssert(removeUserResult.gotNewModerator==true);
2471 RakAssert(roomCreationParameters.roomOutput->GetModerator()==&roomsParticipant1);
2472 RakAssert(roomsParticipant2.GetRoom()==0);
2473 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==0);
2474
2475 // Invite the guy that just left
2476 roomsErrorCode = agrc.SendInvite( &roomsParticipant1, &roomsParticipant2, false, "SendInviteSubject", "SendInviteBody" );
2477 RakAssert(roomsErrorCode==REC_SUCCESS);
2478
2479 // member accepts invite
2480 roomsErrorCode = agrc.AcceptInvite( roomsParticipant1.GetRoom()->GetID(), &room, &roomsParticipant2, roomsParticipant1.GetName() );
2481 RakAssert(roomsErrorCode==REC_SUCCESS);
2482 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==1);
2483
2484 // change current moderator to to spectator (should fail)
2485 roomsErrorCode = agrc.StartSpectating( &roomsParticipant1 );
2486 RakAssert(roomsErrorCode==REC_START_SPECTATING_REASSIGN_MODERATOR_BEFORE_SPECTATE);
2487
2488 // change other member to spectator
2489 roomsErrorCode = agrc.StartSpectating( &roomsParticipant2 );
2490 RakAssert(roomsErrorCode==REC_SUCCESS);
2491 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==0);
2492
2493 // change member type to player
2494 roomsErrorCode = agrc.StopSpectating( &roomsParticipant2 );
2495 RakAssert(roomsErrorCode==REC_SUCCESS);
2496 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==1);
2497
2498 // Moderator logs off
2499 roomsErrorCode = agrc.RemoveUser( &roomsParticipant1, &removeUserResult );
2500 RakAssert(roomsErrorCode==REC_SUCCESS);
2501 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==0);
2502 RakAssert(roomCreationParameters.roomOutput->GetModerator()==&roomsParticipant2);
2503 RakAssert(roomsParticipant1.GetRoom()==0);
2504
2505 // Other player logs off
2506 roomsErrorCode = agrc.RemoveUser( roomCreationParameters.roomOutput->GetModerator(), &removeUserResult );
2507 RakAssert(roomsErrorCode==REC_SUCCESS);
2508 RakAssert(roomsParticipant2.GetRoom()==0);
2509 agrc.DestroyRoomIfDead(removeUserResult.room);
2510
2511 // both members quick join with a custom filter (equality).
2512 QuickJoinUser quickJoinUser1;
2513 quickJoinUser1.networkedQuickJoinUser.minimumPlayers=2;
2514 quickJoinUser1.networkedQuickJoinUser.query=roomQuery;
2515 quickJoinUser1.roomsParticipant=&roomsParticipant1;
2516 quickJoinUser1.networkedQuickJoinUser.timeout=10000;
2517 roomsErrorCode = agrc.AddUserToQuickJoin(gameIdentifier1, &quickJoinUser1);
2518 RakAssert(roomsErrorCode==REC_SUCCESS);
2519 RakAssert(roomsParticipant1.GetRoom()==0);
2520 RakAssert(roomsParticipant2.GetRoom()==0);
2521 RakAssert(roomsParticipant1.GetInQuickJoin()==true);
2522
2523 QuickJoinUser quickJoinUser2;
2524 quickJoinUser2.networkedQuickJoinUser.minimumPlayers=2;
2525 quickJoinUser2.networkedQuickJoinUser.query=roomQuery;
2526 quickJoinUser2.roomsParticipant=&roomsParticipant2;
2527 quickJoinUser2.networkedQuickJoinUser.timeout=10000;
2528 roomsErrorCode = agrc.AddUserToQuickJoin(gameIdentifier1, &quickJoinUser2);
2529 RakAssert(roomsErrorCode==REC_SUCCESS);
2530 RakAssert(roomsParticipant1.GetRoom()==0);
2531 RakAssert(roomsParticipant2.GetRoom()==0);
2532 RakAssert(roomsParticipant2.GetInQuickJoin()==true);
2533
2534 // Update quick join. Should create a room
2535 roomsErrorCode = agrc.ProcessQuickJoins( timeoutExpired, joinedRoomMembers, dereferencedPointers, 1000);
2536 RakAssert(roomsErrorCode==REC_SUCCESS);
2537 RakAssert(roomsParticipant1.GetRoom()!=0);
2538 RakAssert(roomsParticipant1.GetRoom()==roomsParticipant2.GetRoom());
2539 RakAssert(joinedRoomMembers.Size()==2);
2540
2541 // Both members log off
2542 roomsErrorCode = agrc.RemoveUser( &roomsParticipant1, &removeUserResult );
2543 RakAssert(roomsErrorCode==REC_SUCCESS);
2544 RakAssert(removeUserResult.room->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==0);
2545 RakAssert(removeUserResult.room->GetModerator()==&roomsParticipant2);
2546 RakAssert(roomsParticipant1.GetRoom()==0);
2547 roomsErrorCode = agrc.RemoveUser( &roomsParticipant2, &removeUserResult );
2548 RakAssert(roomsErrorCode==REC_SUCCESS);
2549 RakAssert(roomsParticipant2.GetRoom()==0);
2550 agrc.DestroyRoomIfDead(removeUserResult.room);
2551
2552 // Enter roomOutput (member one) (should create a room)
2553 JoinedRoomResult joinedRoomResult;
2554 roomCreationParameters.networkedRoomCreationParameters.slots.publicSlots=0;
2555 roomsErrorCode = agrc.EnterRoom( &roomCreationParameters, RMM_ANY_PLAYABLE, 0, 0, &joinedRoomResult );
2556 RakAssert(roomsErrorCode==REC_SUCCESS);
2557 RakAssert(roomsParticipant1.GetRoom()!=0);
2558 RakAssert(roomsParticipant1.GetRoom()->GetModerator()==&roomsParticipant1);
2559 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_REMAINING_PUBLIC_PLUS_RESERVED_SLOTS)==1);
2560
2561 // Set the properties on the new room
2562 roomsErrorCode = agrc.SetCustomRoomProperties( &roomsParticipant1, &customRoomProperties );
2563 RakAssert(roomsErrorCode==REC_SUCCESS);
2564 RakAssert(agrc.GetPropertyIndex( roomsParticipant1.GetRoom()->GetID(), "LevelName")!=-1);
2565 RakAssert(roomsParticipant1.GetRoom()->GetStringProperty(agrc.GetPropertyIndex( roomsParticipant1.GetRoom()->GetID(), "LevelName"))!=0);
2566
2567 // Invite member two to the new room
2568 roomsErrorCode = agrc.SendInvite( &roomsParticipant1, &roomsParticipant2, false, "SendInviteSubject", "SendInviteBody" );
2569 RakAssert(roomsErrorCode==REC_SUCCESS);
2570
2571 // Quick join (member two) (should join the created roomOutput)
2572 roomsErrorCode = agrc.AddUserToQuickJoin(gameIdentifier1, &quickJoinUser2);
2573 RakAssert(roomsErrorCode==REC_SUCCESS);
2574 RakAssert(roomsParticipant2.GetRoom()==0);
2575 RakAssert(roomsParticipant2.GetInQuickJoin()==true);
2576
2577 // Update quick join. Should join the room, passing the required filter properties
2578 roomsErrorCode = agrc.ProcessQuickJoins( timeoutExpired, joinedRoomMembers, dereferencedPointers, 1000);
2579 RakAssert(roomsErrorCode==REC_SUCCESS);
2580 RakAssert(roomsParticipant1.GetRoom()!=0);
2581 RakAssert(roomsParticipant1.GetRoom()==roomsParticipant2.GetRoom());
2582 RakAssert(joinedRoomMembers.Size()==1);
2583 RakAssert(cells[0].c);
2584 RakAssert(strcmp(roomsParticipant1.GetRoom()->GetStringProperty(agrc.GetPropertyIndex( roomsParticipant1.GetRoom()->GetID(), "LevelName")),cells[0].c)==0);
2585
2586 // Leave roomOutput (member two)
2587 roomsErrorCode = agrc.LeaveRoom( &roomsParticipant2, &removeUserResult );
2588 RakAssert(roomsErrorCode==REC_SUCCESS);
2589 RakAssert(removeUserResult.gotNewModerator==false);
2590 RakAssert(roomCreationParameters.roomOutput->GetModerator()==&roomsParticipant1);
2591 RakAssert(roomsParticipant2.GetRoom()==0);
2592 RakAssert(roomCreationParameters.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_USED_PUBLIC_PLUS_RESERVED_SLOTS)==0);
2593
2594 // Lock Room
2595 roomsErrorCode = agrc.SetRoomLockState( &roomsParticipant1, RLS_PLAYERS_LOCKED );
2596 RakAssert(roomsErrorCode==REC_SUCCESS);
2597
2598 // Set member ready
2599 roomsErrorCode = agrc.SetReadyStatus( &roomsParticipant1, true );
2600 RakAssert(roomsErrorCode==REC_SUCCESS);
2601
2602 // Set member unready
2603 roomsErrorCode = agrc.SetReadyStatus( &roomsParticipant1, false );
2604 RakAssert(roomsErrorCode==REC_SET_READY_STATUS_AUTO_LOCK_ALL_PLAYERS_READY);
2605
2606 // Unlock room
2607 roomsErrorCode = agrc.SetRoomLockState( &roomsParticipant1, RLS_NOT_LOCKED );
2608 RakAssert(roomsErrorCode==REC_SUCCESS);
2609
2610 // Set member unready
2611 room=roomCreationParameters.roomOutput;
2612 roomsErrorCode = agrc.SetReadyStatus( &roomsParticipant1, false );
2613 RakAssert(roomsErrorCode==REC_SUCCESS);
2614
2615 // Try to enter the room (no public slots, tried to create room of same name, failed)
2616 roomCreationParameters.firstUser=&roomsParticipant2;
2617 roomsErrorCode = agrc.EnterRoom( &roomCreationParameters, RMM_ANY_PLAYABLE, 0, 0, &joinedRoomResult );
2618 RakAssert(roomsErrorCode==REC_ROOM_CREATION_PARAMETERS_ROOM_NAME_IN_USE);
2619
2620 // Open a public slot
2621 Slots slots;
2622 slots.publicSlots=1;
2623 roomsErrorCode = agrc.ChangeSlotCounts( &roomsParticipant1, slots );
2624 RakAssert(roomsErrorCode==REC_SUCCESS);
2625
2626 // Enter room
2627 roomCreationParameters.firstUser=&roomsParticipant2;
2628 roomsErrorCode = agrc.EnterRoom( &roomCreationParameters, RMM_ANY_PLAYABLE, 0, 0, &joinedRoomResult );
2629 RakAssert(roomsErrorCode==REC_SUCCESS);
2630 RakAssert(roomsParticipant1.GetRoom()!=0);
2631 RakAssert(roomsParticipant1.GetRoom()->GetModerator()==&roomsParticipant1);
2632 RakAssert(roomsParticipant1.GetRoom()==roomsParticipant2.GetRoom());
2633 RakAssert(joinedRoomResult.roomOutput->GetNumericProperty(DefaultRoomColumns::TC_REMAINING_PUBLIC_PLUS_RESERVED_SLOTS)==1);
2634 room = joinedRoomResult.roomOutput;
2635
2636 // Kick member 2
2637 RakNet::RakString banReason("Don't like you");
2638 roomsErrorCode = agrc.KickMember( &roomsParticipant1, &roomsParticipant2, banReason );
2639 RakAssert(roomsErrorCode==REC_SUCCESS);
2640
2641 // Join by filter
2642 roomsErrorCode = agrc.JoinByFilter( gameIdentifier1, RMM_ANY_PLAYABLE, &roomsParticipant2, (RakNet::RoomID)-1, &roomQuery, &joinedRoomResult);
2643 RakAssert(roomsErrorCode==REC_JOIN_BY_FILTER_NO_ROOMS);
2644
2645 RakNet::RakString banReasonOut;
2646 roomsErrorCode = agrc.GetBanReason( room->GetID(), &room, roomsParticipant2.GetName(), &banReasonOut );
2647 RakAssert(roomsErrorCode==REC_SUCCESS);
2648 RakAssert(banReasonOut==banReason);
2649
2650 // Unban member
2651 roomsErrorCode = agrc.UnbanMember( &roomsParticipant1, roomsParticipant2.GetName());
2652 RakAssert(roomsErrorCode==REC_SUCCESS);
2653
2654 // Get ban reason
2655 roomsErrorCode = agrc.GetBanReason( room->GetID(), &room, roomsParticipant2.GetName(), &banReasonOut );
2656 RakAssert(roomsErrorCode==REC_GET_BAN_REASON_NOT_BANNED);
2657
2658 // Unban member again (should fail)
2659 roomsErrorCode = agrc.UnbanMember( &roomsParticipant1, roomsParticipant2.GetName());
2660 RakAssert(roomsErrorCode==REC_UNBAN_MEMBER_NOT_BANNED);
2661
2662 // Join by filter
2663 roomsErrorCode = agrc.JoinByFilter( gameIdentifier1, RMM_ANY_PLAYABLE, &roomsParticipant2, (RakNet::RoomID)-1, &roomQuery, &joinedRoomResult);
2664 RakAssert(roomsErrorCode==REC_SUCCESS);
2665
2666 // Set both members ready
2667 roomsErrorCode = agrc.SetReadyStatus( &roomsParticipant1, true );
2668 RakAssert(roomsErrorCode==REC_SUCCESS);
2669 roomsErrorCode = agrc.SetReadyStatus( &roomsParticipant2, true );
2670 RakAssert(roomsErrorCode==REC_SUCCESS);
2671
2672 // Set one member unready
2673 roomsErrorCode = agrc.SetReadyStatus( &roomsParticipant1, false );
2674 RakAssert(roomsErrorCode==REC_SUCCESS);
2675
2676 // Kick out 2nd member
2677 roomsErrorCode = agrc.KickMember( &roomsParticipant1, &roomsParticipant2, "Don't like you too" );
2678 RakAssert(roomsErrorCode==REC_SUCCESS);
2679
2680 // Unban member
2681 roomsErrorCode = agrc.UnbanMember( &roomsParticipant1, roomsParticipant2.GetName());
2682 RakAssert(roomsErrorCode==REC_SUCCESS);
2683
2684 // hide roomOutput
2685 roomsErrorCode = agrc.SetHiddenFromSearches( &roomsParticipant1, true );
2686 RakAssert(roomsErrorCode==REC_SUCCESS);
2687
2688 // Join by filter (should fail because hidden)
2689 roomsErrorCode = agrc.JoinByFilter( gameIdentifier1, RMM_ANY_PLAYABLE, &roomsParticipant2, (RakNet::RoomID)-1, &roomQuery, &joinedRoomResult);
2690 RakAssert(roomsErrorCode==REC_JOIN_BY_FILTER_NO_ROOMS);
2691
2692 }
2693