1 #ifndef __LOBBY_ROOM_H 2 #define __LOBBY_ROOM_H 3 4 #include "DS_Map.h" 5 #include "DS_Table.h" 6 #include "RoomsErrorCodes.h" 7 #include "DS_List.h" 8 #include "RakNetTypes.h" 9 #include "IntervalTimer.h" 10 #include "RoomTypes.h" 11 12 class ProfanityFilter; 13 14 namespace RakNet 15 { 16 17 class Room; 18 class PerGameRoomList; 19 class PerGameRoomsContainer; 20 class BitStream; 21 typedef unsigned int RoomID; 22 struct QuickJoinUser; 23 struct RoomMember; 24 class AllGamesRoomsContainer; 25 26 class RoomsParticipant 27 { 28 public: RoomsParticipant()29 RoomsParticipant() {room=0; inQuickJoin=false;} ~RoomsParticipant()30 ~RoomsParticipant() {} GetRoom(void)31 Room * GetRoom(void) const {return room;} SetPerGameRoomsContainer(PerGameRoomsContainer * p)32 void SetPerGameRoomsContainer(PerGameRoomsContainer *p) {perGameRoomsContainer=p;} SetRoom(Room * _room)33 void SetRoom(Room *_room) {room=_room; inQuickJoin=false;} SetInQuickJoin(bool b)34 void SetInQuickJoin(bool b) {inQuickJoin=b; if (b) room=0;} 35 36 // Name is used for persistent invites and bans. Name should be unique among all participants or else the invites and bans will be applied to the wrong players GetName(void)37 RakNet::RakString GetName(void) const {return name;} SetName(const char * str)38 void SetName(const char *str) {name = str;} SetSystemAddress(SystemAddress sa)39 void SetSystemAddress(SystemAddress sa) {systemAddress=sa;} GetSystemAddress(void)40 SystemAddress GetSystemAddress(void) const {return systemAddress;} SetGUID(RakNetGUID g)41 void SetGUID(RakNetGUID g) {guid=g;} GetGUID(void)42 RakNetGUID GetGUID(void) const {return guid;} 43 GetPerGameRoomsContainer(void)44 PerGameRoomsContainer *GetPerGameRoomsContainer(void) const {return perGameRoomsContainer;} GetInQuickJoin(void)45 bool GetInQuickJoin(void) const {return inQuickJoin;} 46 protected: 47 RakNet::RakString name; 48 SystemAddress systemAddress; 49 RakNetGUID guid; 50 Room *room; 51 bool inQuickJoin; 52 PerGameRoomsContainer *perGameRoomsContainer; 53 }; 54 55 typedef RakNet::RakString GameIdentifier; 56 57 enum RoomLockState 58 { 59 // Anyone can join or leave 60 RLS_NOT_LOCKED, 61 // Anyone can join as spectator or become spectator. New players are not allowed. You cannot leave spectator. 62 RLS_PLAYERS_LOCKED, 63 // No new players are allowed, and you cannot toggle spectator 64 RLS_ALL_LOCKED 65 }; 66 67 enum ParticipantCanJoinRoomResult 68 { 69 PCJRR_SUCCESS, 70 PCJRR_BANNED, 71 PCJRR_NO_PUBLIC_SLOTS, 72 PCJRR_NO_PUBLIC_OR_RESERVED_SLOTS, 73 PCJRR_NO_SPECTATOR_SLOTS, 74 PCJRR_LOCKED, 75 PCJRR_SLOT_ALREADY_USED, 76 }; 77 78 struct Slots 79 { 80 Slots(); 81 ~Slots(); 82 unsigned int publicSlots; 83 unsigned int reservedSlots; 84 unsigned int spectatorSlots; GetTotalSlotsSlots85 unsigned int GetTotalSlots(void) const {return publicSlots+reservedSlots+spectatorSlots;} 86 void Serialize(bool writeToBitstream, RakNet::BitStream *bitStream); 87 RoomsErrorCode Validate(void) const; 88 }; 89 90 struct InvitedUser 91 { InvitedUserInvitedUser92 InvitedUser() {room=0; roomId=0; invitedAsSpectator=false;} 93 Room *room; 94 RoomID roomId; 95 RakNet::RakString invitorName; 96 SystemAddress invitorSystemAddress; 97 RakNet::RakString target; 98 RakNet::RakString subject; 99 RakNet::RakString body; 100 bool invitedAsSpectator; 101 102 void Serialize(bool writeToBitstream, RakNet::BitStream *bitStream); 103 }; 104 105 struct BannedUser 106 { 107 RakNet::RakString target; 108 RakNet::RakString reason; 109 void Serialize(bool writeToBitstream, RakNet::BitStream *bitStream); 110 }; 111 112 struct RemoveUserResult 113 { 114 RemoveUserResult(); 115 ~RemoveUserResult(); 116 117 // Why return a deleted pointer? 118 // RoomsParticipant *removedUser; 119 bool removedFromQuickJoin; 120 bool removedFromRoom; 121 SystemAddress removedUserAddress; 122 RakNet::RakString removedUserName; 123 124 // Following members only apply if removedFromRoom==true 125 Room *room; 126 RoomID roomId; 127 bool gotNewModerator; // If you were the moderator before, this is true 128 DataStructures::List<InvitedUser> clearedInvitations; // If invitations were cleared when you leave, these are the invitations 129 bool roomDestroyed; // Up to caller to deallocate 130 131 QuickJoinUser *qju; 132 void Serialize(bool writeToBitstream, RakNet::BitStream *bitStream); 133 }; 134 135 136 struct RoomMemberDescriptor 137 { 138 RakNet::RakString name; 139 RoomMemberMode roomMemberMode; 140 bool isReady; 141 // Filled externally 142 SystemAddress systemAddress; 143 RakNetGUID guid; 144 145 void FromRoomMember(RoomMember *roomMember); 146 void Serialize(bool writeToBitstream, RakNet::BitStream *bitStream); 147 }; 148 149 struct NetworkedRoomCreationParameters 150 { NetworkedRoomCreationParametersNetworkedRoomCreationParameters151 NetworkedRoomCreationParameters() {hiddenFromSearches=false; destroyOnModeratorLeave=false; autoLockReadyStatus=false; inviteToRoomPermission=INVITE_MODE_ANYONE_CAN_INVITE; inviteToSpectatorSlotPermission=INVITE_MODE_ANYONE_CAN_INVITE; clearInvitesOnNewModerator=false;} 152 // Checked by Validate 153 Slots slots; 154 bool hiddenFromSearches; 155 bool destroyOnModeratorLeave; 156 bool autoLockReadyStatus; // When everyone is ready and (the room is full or the room is locked), don't allow users to set unready. 157 enum SendInvitePermission 158 { 159 INVITE_MODE_ANYONE_CAN_INVITE, 160 INVITE_MODE_MODERATOR_CAN_INVITE, 161 INVITE_MODE_PUBLIC_SLOTS_CAN_INVITE, 162 INVITE_MODE_RESERVED_SLOTS_CAN_INVITE, 163 INVITE_MODE_SPECTATOR_SLOTS_CAN_INVITE, 164 INVITE_MODE_MODERATOR_OR_PUBLIC_SLOTS_CAN_INVITE, 165 INVITE_MODE_MODERATOR_OR_PUBLIC_OR_RESERVED_SLOTS_CAN_INVITE, 166 } inviteToRoomPermission, inviteToSpectatorSlotPermission; 167 bool clearInvitesOnNewModerator; // Leave or change 168 RakNet::RakString roomName; 169 170 void Serialize(bool writeToBitstream, RakNet::BitStream *bitStream); 171 static const char *SendInvitePermissionToEnum(SendInvitePermission e); 172 }; 173 struct RoomDescriptor 174 { 175 DataStructures::List<RoomMemberDescriptor> roomMemberList; 176 DataStructures::List<BannedUser> banList; 177 RoomLockState roomLockState; 178 RoomID lobbyRoomId; 179 bool autoLockReadyStatus; 180 bool hiddenFromSearches; 181 NetworkedRoomCreationParameters::SendInvitePermission inviteToRoomPermission; 182 NetworkedRoomCreationParameters::SendInvitePermission inviteToSpectatorSlotPermission; 183 DataStructures::Table roomProperties; 184 GetPropertyRoomDescriptor185 DataStructures::Table::Cell *GetProperty(const char* columnName) 186 { 187 return roomProperties.GetRowByIndex(0,0)->cells[roomProperties.ColumnIndex(columnName)]; 188 } GetPropertyRoomDescriptor189 DataStructures::Table::Cell *GetProperty(int index) 190 { 191 return roomProperties.GetRowByIndex(0,0)->cells[index]; 192 } 193 ClearRoomDescriptor194 void Clear(void) 195 { 196 roomMemberList.Clear(false, __FILE__, __LINE__); 197 banList.Clear(false, __FILE__, __LINE__); 198 roomProperties.Clear(); 199 } 200 void FromRoom(Room *room, AllGamesRoomsContainer *agrc); 201 void Serialize(bool writeToBitstream, RakNet::BitStream *bitStream); 202 }; 203 204 struct JoinedRoomResult 205 { JoinedRoomResultJoinedRoomResult206 JoinedRoomResult() {roomOutput=0; acceptedInvitor=0; agrc=0; joiningMember=0;} ~JoinedRoomResultJoinedRoomResult207 ~JoinedRoomResult() {} 208 Room* roomOutput; 209 RoomDescriptor roomDescriptor; 210 RoomsParticipant* acceptedInvitor; 211 RakNet::RakString acceptedInvitorName; 212 SystemAddress acceptedInvitorAddress; 213 RoomsParticipant* joiningMember; 214 RakNet::RakString joiningMemberName; 215 SystemAddress joiningMemberAddress; 216 217 // Needed to serialize 218 AllGamesRoomsContainer *agrc; 219 220 void Serialize(bool writeToBitstream, RakNet::BitStream *bitStream ); 221 }; 222 223 224 struct RoomCreationParameters 225 { 226 RoomCreationParameters(); 227 ~RoomCreationParameters(); 228 229 NetworkedRoomCreationParameters networkedRoomCreationParameters; 230 231 // Not checked 232 RoomsParticipant* firstUser; 233 GameIdentifier gameIdentifier; 234 235 // Output parameters: 236 // Was the room created? 237 bool createdRoom; 238 Room *roomOutput; 239 240 // May return REC_ROOM_CREATION_PARAMETERS_* or REC_SUCCESS 241 RoomsErrorCode Validate( 242 const DataStructures::List<RakNet::RakString> &otherRoomNames, 243 ProfanityFilter *profanityFilter) const; 244 }; 245 246 struct RoomMember 247 { 248 RoomMember(); 249 ~RoomMember(); 250 RoomsParticipant* roomsParticipant; 251 RoomMemberMode roomMemberMode; 252 RakNetTime joinTime; 253 bool isReady; 254 // Internal - set to false when a new member is added. When the other members have been told about this member, it is set to true 255 bool newMemberNotificationProcessed; 256 }; 257 struct KickedUser 258 { 259 RoomsParticipant* roomsParticipant; 260 RakNet::RakString reason; 261 }; 262 263 struct RoomQuery 264 { 265 RoomQuery(); 266 ~RoomQuery(); 267 268 // Point to an externally allocated array of FilterQuery, or use the helper functions below to use a static array (not threadsafe to use the static array) 269 DataStructures::Table::FilterQuery *queries; 270 // Size of the queries array 271 unsigned int numQueries; 272 // Not used 273 bool queriesAllocated; 274 275 // Helper functions 276 // Easier to use, but not threadsafe 277 void AddQuery_NUMERIC(const char *columnName, double numericValue, DataStructures::Table::FilterQueryType op=DataStructures::Table::QF_EQUAL); 278 void AddQuery_STRING(const char *columnName, const char *charValue, DataStructures::Table::FilterQueryType op=DataStructures::Table::QF_EQUAL); 279 void AddQuery_BINARY(const char *columnName, const char *input, int inputLength, DataStructures::Table::FilterQueryType op=DataStructures::Table::QF_EQUAL); 280 void AddQuery_POINTER(const char *columnName, void *ptr, DataStructures::Table::FilterQueryType op=DataStructures::Table::QF_EQUAL); 281 RoomsErrorCode Validate(void); 282 283 void Serialize(bool writeToBitstream, RakNet::BitStream *bitStream); 284 285 /// \internal 286 void SetQueriesToStatic(void); 287 288 private: 289 static DataStructures::Table::FilterQuery fq[32]; 290 static DataStructures::Table::Cell cells[32]; 291 void SetupNextQuery(const char *columnName,DataStructures::Table::FilterQueryType op); 292 }; 293 294 295 struct NetworkedQuickJoinUser 296 { NetworkedQuickJoinUserNetworkedQuickJoinUser297 NetworkedQuickJoinUser() {timeout=60000; minimumPlayers=2;} 298 299 // How long to wait for 300 RakNetTime timeout; 301 // What queries to join the room on. 302 RoomQuery query; 303 // Minimum number of slots to join 304 int minimumPlayers; 305 306 void Serialize(bool writeToBitstream, RakNet::BitStream *bitStream); 307 }; 308 309 struct QuickJoinUser 310 { 311 QuickJoinUser(); 312 ~QuickJoinUser(); 313 314 NetworkedQuickJoinUser networkedQuickJoinUser; 315 316 // Total amount of time spent waiting 317 RakNetTime totalTimeWaiting; 318 319 // Which user 320 RoomsParticipant* roomsParticipant; 321 static int SortByTotalTimeWaiting( QuickJoinUser* const &key, QuickJoinUser* const &data ); 322 static int SortByMinimumSlots( QuickJoinUser* const &key, QuickJoinUser* const &data ); 323 }; 324 325 int RoomPriorityComp( Room * const &key, Room * const &data ); 326 327 // PerGameRoomsContainer, mapped by game id 328 class AllGamesRoomsContainer 329 { 330 public: 331 AllGamesRoomsContainer(); 332 ~AllGamesRoomsContainer(); 333 static void UnitTest(void); 334 335 RoomsErrorCode CreateRoom(RoomCreationParameters *roomCreationParameters, 336 ProfanityFilter *profanityFilter); 337 338 // Enters a room based on the search queries. If no rooms are available to join, will create a room instead 339 RoomsErrorCode EnterRoom(RoomCreationParameters *roomCreationParameters, 340 RoomMemberMode roomMemberMode, 341 ProfanityFilter *profanityFilter, 342 RoomQuery *query, 343 JoinedRoomResult *joinRoomResult); 344 345 // Attempts to join a room by search query filters 346 // Returns REC_JOIN_BY_FILTER_* 347 RoomsErrorCode JoinByFilter(GameIdentifier gameIdentifier, RoomMemberMode roomMemberMode, RoomsParticipant* roomsParticipant, RoomID lastRoomJoined, RoomQuery *query, JoinedRoomResult *joinRoomResult); 348 349 // Add a new title to host games with 350 RoomsErrorCode AddTitle(GameIdentifier gameIdentifier); 351 352 // Get all pending invites to you 353 RoomsErrorCode GetInvitesToParticipant(RoomsParticipant* roomsParticipant, DataStructures::List<InvitedUser*> &invites); 354 355 RoomsErrorCode RemoveUser(RoomsParticipant* roomsParticipant, RemoveUserResult *removeMemberResult); 356 357 // ROOMS OPERATIONS, implicit room 358 RoomsErrorCode SendInvite(RoomsParticipant* roomsParticipant, RoomsParticipant* inviteeId, bool inviteToSpectatorSlot, RakNet::RakString subject, RakNet::RakString body); 359 RoomsErrorCode AcceptInvite(RoomID roomId, Room **room, RoomsParticipant* roomsParticipant, RakNet::RakString inviteSender); 360 RoomsErrorCode StartSpectating(RoomsParticipant* roomsParticipant); 361 RoomsErrorCode StopSpectating(RoomsParticipant* roomsParticipant); 362 RoomsErrorCode GrantModerator(RoomsParticipant* roomsParticipant, RoomsParticipant *newModerator, DataStructures::List<InvitedUser> &clearedInvites); 363 RoomsErrorCode ChangeSlotCounts(RoomsParticipant* roomsParticipant, Slots slots); 364 RoomsErrorCode SetCustomRoomProperties(RoomsParticipant* roomsParticipant, DataStructures::Table *table); 365 RoomsErrorCode ChangeRoomName(RoomsParticipant* roomsParticipant, RakNet::RakString newRoomName, ProfanityFilter *profanityFilter); 366 RoomsErrorCode SetHiddenFromSearches(RoomsParticipant* roomsParticipant, bool _hiddenFromSearches); 367 RoomsErrorCode SetDestroyOnModeratorLeave(RoomsParticipant* roomsParticipant, bool destroyOnModeratorLeave); 368 RoomsErrorCode SetReadyStatus(RoomsParticipant* roomsParticipant, bool isReady); 369 RoomsErrorCode GetReadyStatus( RoomID roomId, Room **room, DataStructures::List<RoomsParticipant*> &readyUsers, DataStructures::List<RoomsParticipant*> &unreadyUsers); 370 RoomsErrorCode SetRoomLockState(RoomsParticipant* roomsParticipant, RoomLockState _roomLockState); 371 RoomsErrorCode GetRoomLockState(RoomID roomId, Room **room, RoomLockState *roomLockState); 372 RoomsErrorCode AreAllMembersReady(RoomID roomId, Room **room, bool *allReady); 373 RoomsErrorCode KickMember(RoomsParticipant* roomsParticipant, RoomsParticipant *kickedParticipant, RakNet::RakString reason); 374 RoomsErrorCode UnbanMember(RoomsParticipant* roomsParticipant, RakNet::RakString name); 375 RoomsErrorCode GetBanReason( RoomID lobbyRoomId, Room **room, RakNet::RakString name, RakNet::RakString *reason); 376 RoomsErrorCode LeaveRoom(RoomsParticipant* roomsParticipant, RemoveUserResult *removeUserResult); 377 //RoomsErrorCode GetKickReason(RoomsParticipant* roomsParticipant, RakNet::RakString *kickReason); 378 379 380 void GetRoomProperties(RoomID roomId, Room **room, DataStructures::Table *table); 381 382 // Quick join algorithm: 383 // 384 // -- ROOM JOIN -- 385 // 386 // For all rooms: 387 // 1. Clear all quickJoinWorkingList from all rooms 388 // For all quick join members 389 // 2. Use RoomPrioritySort to get all rooms they can potentially join 390 // 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 391 // For all rooms: 392 // 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. 393 // 394 // -- ROOM CREATE -- 395 // 396 // 5. Sort quick join members by minimumPlayers, excluding members where minimumPlayers > total number of quick join members 397 // From greatest minimumPlayers to least 398 // 6. If the current member created a room, find out how many subsequent members would join based on the custom filter 399 // 7. If this satisfies minimumPlayers, have that user create a room and those subsequent members join. 400 // 401 // -- EXPIRE 402 // 403 // 5. Remove from list if timeout has expired. 404 // 6. Return results of operation (List<timeoutExpired>, List<joinedARoom>, List<RoomsThatWereJoined> 405 // 406 // Returns false if processing skipped due to optimization timer 407 RoomsErrorCode ProcessQuickJoins( 408 DataStructures::List<QuickJoinUser*> &timeoutExpired, 409 DataStructures::List<JoinedRoomResult> &joinedRoomMembers, 410 DataStructures::List<QuickJoinUser*> &dereferencedPointers, 411 RakNetTime elapsedTime); 412 413 // Quick join - Store a list of all members waiting to quick join. 414 // Quick join ends when 415 // 1. An existing room can be fully populated using waiting quick join members. 416 // 2. Enough quick join members are waiting that a new room can be created with the number of members >= minimumPlayers for all members 417 // It also ends if timeToWaitMS expires. 418 // Returns REC_ADD_TO_QUICK_JOIN_* 419 // Passed pointer is stored on REC_SUCCESS, allocate, and do not deallocate unless not successful 420 RoomsErrorCode AddUserToQuickJoin(GameIdentifier gameIdentifier, QuickJoinUser *quickJoinMember); 421 422 // Returns REC_REMOVE_FROM_QUICK_JOIN_* 423 RoomsErrorCode RemoveUserFromQuickJoin(RoomsParticipant* roomsParticipant, QuickJoinUser **qju); 424 425 // Is this user in quick join? 426 bool IsInQuickJoin(RoomsParticipant* roomsParticipant); 427 428 // Get all rooms for a certain title 429 static int RoomsSortByName( Room* const &key, Room* const &data ); 430 RoomsErrorCode SearchByFilter( GameIdentifier gameIdentifier, RoomsParticipant* roomsParticipant, RoomQuery *roomQuery, DataStructures::OrderedList<Room*, Room*, RoomsSortByName> &roomsOutput, bool onlyJoinable ); 431 432 // Deallocate a room 433 void DestroyRoomIfDead(Room *room); 434 435 // If a handle changes, you have to tell the system here. Otherwise ban and invite names will be out of synch 436 // System does not verify that the handle is not currently in use since it does not necessarily know about all online players 437 // This is an invariant up to the caller to uphold. Failure to do so will result in the wrong players being banned or invited 438 void ChangeHandle(RakNet::RakString oldHandle, RakNet::RakString newHandle); 439 440 unsigned int GetPropertyIndex(RoomID lobbyRoomId, const char *propertyName) const; 441 442 DataStructures::Map<GameIdentifier, PerGameRoomsContainer*> perGamesRoomsContainers; 443 444 Room * GetRoomByLobbyRoomID(RoomID lobbyRoomID); 445 Room * GetRoomByName(RakNet::RakString roomName); 446 447 protected: 448 RoomID nextRoomId; 449 }; 450 451 class PerGameRoomsContainer 452 { 453 public: 454 PerGameRoomsContainer(); 455 ~PerGameRoomsContainer(); 456 457 // Has pointer column to class Room 458 DataStructures::Table roomsTable; 459 460 // Members that are waiting to quick join 461 DataStructures::List<QuickJoinUser*> quickJoinList; 462 463 static int RoomsSortByTimeThenTotalSlots( Room* const &key, Room* const &data ); 464 465 protected: 466 467 RoomsErrorCode CreateRoom(RoomCreationParameters *roomCreationParameters, 468 ProfanityFilter *profanityFilter, 469 RoomID lobbyRoomId, 470 bool validate); 471 RoomsErrorCode LeaveRoom(RoomsParticipant* roomsParticipant, bool *gotNewModerator); 472 RoomsErrorCode JoinByFilter(RoomMemberMode roomMemberMode, RoomsParticipant* roomsParticipant, RoomID lastRoomJoined, RoomQuery *query, JoinedRoomResult *joinRoomResult); 473 RoomsErrorCode AddUserToQuickJoin(QuickJoinUser *quickJoinMember); 474 RoomsErrorCode RemoveUserFromQuickJoin(RoomsParticipant* roomsParticipant, QuickJoinUser **qju); 475 bool IsInQuickJoin(RoomsParticipant* roomsParticipant); 476 unsigned int GetQuickJoinIndex(RoomsParticipant* roomsParticipant); 477 void GetRoomNames(DataStructures::List<RakNet::RakString> &roomNames); 478 void GetAllRooms(DataStructures::List<Room*> &rooms); 479 // Looks for a particular room that has a particular ID 480 Room * GetRoomByLobbyRoomID(RoomID lobbyRoomID); 481 Room * GetRoomByName(RakNet::RakString roomName); 482 RoomsErrorCode GetInvitesToParticipant(RoomsParticipant* roomsParticipant, DataStructures::List<InvitedUser*> &invites); 483 void DestroyRoomIfDead(Room *room); 484 void ChangeHandle(RakNet::RakString oldHandle, RakNet::RakString newHandle); 485 486 unsigned ProcessQuickJoins( DataStructures::List<QuickJoinUser*> &timeoutExpired, 487 DataStructures::List<JoinedRoomResult> &joinedRooms, 488 DataStructures::List<QuickJoinUser*> &dereferencedPointers, 489 RakNetTime elapsedTime, 490 RoomID startingRoomId); 491 492 // Sort an input list of rooms 493 // Rooms are sorted by time created (longest is higher priority). If within one minute, then subsorted by total playable slot count (lower is higher priority). 494 // When using EnterRoom or JoinByFilter, record the last roomOutput joined, and try to avoid rejoining the same roomOutput just left 495 void RoomPrioritySort( RoomsParticipant* roomsParticipant, RoomQuery *roomQuery, DataStructures::OrderedList<Room*, Room*, RoomsSortByTimeThenTotalSlots> &roomsOutput ); 496 497 RoomsErrorCode SearchByFilter( RoomsParticipant* roomsParticipant, RoomQuery *roomQuery, DataStructures::OrderedList<Room*, Room*, AllGamesRoomsContainer::RoomsSortByName> &roomsOutput, bool onlyJoinable ); 498 499 friend class AllGamesRoomsContainer; 500 IntervalTimer nextQuickJoinProcess; 501 }; 502 503 // Holds all the members of a particular roomOutput 504 class Room 505 { 506 public: 507 Room( RoomID _roomId, RoomCreationParameters *roomCreationParameters, DataStructures::Table::Row *_row, RoomsParticipant* roomsParticipant ); 508 ~Room(); 509 RoomsErrorCode SendInvite(RoomsParticipant* roomsParticipant, RoomsParticipant* inviteeId, bool inviteToSpectatorSlot, RakNet::RakString subject, RakNet::RakString body); 510 RoomsErrorCode AcceptInvite(RoomsParticipant* roomsParticipant, RakNet::RakString inviteSender); 511 RoomsErrorCode StartSpectating(RoomsParticipant* roomsParticipant); 512 RoomsErrorCode StopSpectating(RoomsParticipant* roomsParticipant); 513 RoomsErrorCode GrantModerator(RoomsParticipant* roomsParticipant, RoomsParticipant *newModerator, DataStructures::List<InvitedUser> &clearedInvites); 514 RoomsErrorCode ChangeSlotCounts(RoomsParticipant* roomsParticipant, Slots slots); 515 RoomsErrorCode SetCustomRoomProperties(RoomsParticipant* roomsParticipant, DataStructures::Table *table); 516 RoomsErrorCode ChangeRoomName(RoomsParticipant* roomsParticipant, RakNet::RakString newRoomName, ProfanityFilter *profanityFilter); 517 RoomsErrorCode SetHiddenFromSearches(RoomsParticipant* roomsParticipant, bool _hiddenFromSearches); 518 RoomsErrorCode SetDestroyOnModeratorLeave(RoomsParticipant* roomsParticipant, bool destroyOnModeratorLeave); 519 RoomsErrorCode SetReadyStatus(RoomsParticipant* roomsParticipant, bool isReady); 520 RoomsErrorCode GetReadyStatus(DataStructures::List<RoomsParticipant*> &readyUsers, DataStructures::List<RoomsParticipant*> &unreadyUsers); 521 RoomsErrorCode SetRoomLockState(RoomsParticipant* roomsParticipant, RoomLockState _roomLockState); 522 RoomsErrorCode GetRoomLockState(RoomLockState *_roomLockState); 523 RoomsErrorCode AreAllMembersReady(unsigned int exceptThisIndex, bool *allReady); 524 RoomsErrorCode KickMember(RoomsParticipant* roomsParticipant, RoomsParticipant *kickedParticipant, RakNet::RakString reason); 525 RoomsErrorCode UnbanMember(RoomsParticipant* roomsParticipant, RakNet::RakString name); 526 RoomsErrorCode GetBanReason(RakNet::RakString name, RakNet::RakString *reason); 527 RoomsErrorCode LeaveRoom(RoomsParticipant* roomsParticipant, RemoveUserResult *removeUserResult); 528 //RoomsErrorCode GetKickReason(RoomsParticipant* roomsParticipant, RakNet::RakString *kickReason); 529 530 RoomsErrorCode JoinByFilter(RoomsParticipant* roomsParticipant, RoomMemberMode roomMemberMode, JoinedRoomResult *joinRoomResult); 531 RoomsErrorCode JoinByQuickJoin(RoomsParticipant* roomsParticipant, RoomMemberMode roomMemberMode, JoinedRoomResult *joinRoomResult); 532 533 bool IsHiddenToParticipant(RoomsParticipant* roomsParticipant) const; 534 535 // Can this user join this roomOutput? 536 ParticipantCanJoinRoomResult ParticipantCanJoinAsPlayer( RoomsParticipant* roomsParticipant, bool asSpectator, bool checkHasInvite ); 537 ParticipantCanJoinRoomResult ParticipantCanJoinRoom( RoomsParticipant* roomsParticipant, bool asSpectator, bool checkHasInvite ); 538 539 // Returns true if there are only spectators, or nobody at all 540 bool IsRoomDead(void) const; 541 542 RoomsErrorCode GetInvitesToParticipant(RoomsParticipant* roomsParticipant, DataStructures::List<InvitedUser*> &invites); 543 544 RoomsParticipant* GetModerator(void) const; 545 546 // Gets the roomOutput ID 547 RoomID GetID(void) const; 548 549 double GetNumericProperty(RoomID lobbyRoomId, const char *propertyName) const; 550 const char *GetStringProperty(RoomID lobbyRoomId, const char *propertyName) const; 551 552 double GetNumericProperty(int index) const; 553 const char *GetStringProperty(int index) const; 554 void SetNumericProperty(int index, double value); 555 void SetStringProperty(int index, const char *value); 556 557 // Public for easy access 558 DataStructures::List<RoomMember*> roomMemberList; 559 560 DataStructures::List<InvitedUser> inviteList; 561 DataStructures::List<BannedUser> banList; 562 563 // Don't store - slow because when removing users I have to iterate through every room 564 // DataStructures::List<KickedUser> kickedList; 565 566 // Internal 567 DataStructures::List<QuickJoinUser*> quickJoinWorkingList; 568 569 static void UpdateRowSlots( DataStructures::Table::Row* row, Slots *totalSlots, Slots *usedSlots); 570 571 void ChangeHandle(RakNet::RakString oldHandle, RakNet::RakString newHandle); 572 protected: 573 Room(); 574 575 // Updates the table row 576 RoomsErrorCode RemoveUser(RoomsParticipant* roomsParticipant,RemoveUserResult *removeUserResult); 577 578 bool IsRoomLockedToSpectators(void) const; 579 bool IsRoomLockedToPlayers(void) const; 580 581 bool IsInRoom(RoomsParticipant* roomsParticipant) const; 582 bool HasInvite(RakNet::RakString roomsParticipant); 583 unsigned int GetRoomIndex(RoomsParticipant* roomsParticipant) const; 584 unsigned int GetBannedIndex(RakNet::RakString username) const; 585 unsigned int GetInviteIndex(RakNet::RakString invitee, RakNet::RakString invitor) const; 586 unsigned int GetFirstInviteIndex(RakNet::RakString invitee) const; 587 bool AreAllPlayableSlotsFilled(void) const; 588 bool HasOpenPublicSlots(void) const; 589 bool HasOpenReservedSlots(void) const; 590 bool HasOpenSpectatorSlots(void) const; 591 void UpdateUsedSlots( void ); 592 void UpdateUsedSlots( Slots *totalSlots, Slots *usedSlots ); 593 static void UpdateUsedSlots( DataStructures::Table::Row* tableRow, Slots *totalSlots, Slots *usedSlots ); 594 Slots GetTotalSlots(void) const; 595 void SetTotalSlots(Slots *totalSlots); 596 Slots GetUsedSlots(void) const; 597 598 599 RoomLockState roomLockState; 600 601 friend struct RoomDescriptor; 602 friend class PerGameRoomsContainer; 603 friend class AllGamesRoomsContainer; 604 605 RoomID lobbyRoomId; 606 DataStructures::Table::Row *tableRow; 607 608 bool autoLockReadyStatus; 609 bool hiddenFromSearches; 610 // bool destroyOnModeratorLeave; 611 bool clearInvitesOnNewModerator; 612 NetworkedRoomCreationParameters::SendInvitePermission inviteToRoomPermission, inviteToSpectatorSlotPermission; 613 614 bool roomDestroyed; 615 616 }; 617 618 619 } // namespace Lobby2 620 621 #endif 622