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