internal bool Join(ClientSession session) { session.Connection.OnDisconnected -= this.OnCreatorDisconnectEarly; MatchListingJoinStatus canJoinStatus = this.CanJoin(session); if (canJoinStatus != MatchListingJoinStatus.Success) { return(false); } if (!this._Clients.TryAdd(session)) { return(false); } session.LobbySession.MatchListing = this; session.LobbySession.RemoveMatch(this); //Send the other clients foreach (ClientSession other in this._Clients.Sessions.OrderBy((c) => c == session)) { session.TrackUserInRoom(this.Name, other.SocketId, other.UserData.Id, other.UserData.Username, other.GetVars("userName", "rank", "hat", "head", "body", "feet", "hatColor", "headColor", "bodyColor", "feetColor", "socketID", "ping")); other.TrackUserInRoom(this.Name, session.SocketId, session.UserData.Id, session.UserData.Username, session.GetVars("userName", "rank", "hat", "head", "body", "feet", "hatColor", "headColor", "bodyColor", "feetColor", "socketID", "ping")); } foreach (ClientSession other in this.LobbyClients.Sessions) { other.TrackUserInRoom(this.Name, session.SocketId, session.UserData.Id, session.UserData.Username, session.GetVars("userName", "rank", "hat", "head", "body", "feet", "hatColor", "headColor", "bodyColor", "feetColor", "socketID", "ping")); } uint currentHost = this._HostSocketId; if (this.Type == MatchListingType.Normal && (currentHost == session.SocketId || (currentHost == 0 && Interlocked.CompareExchange(ref this._HostSocketId, session.SocketId, currentHost) == currentHost))) { session.SendPacket(new MatchOwnerOutgoingMessage(this.Name, true, true, true)); } else if (!session.IsGuest) { bool play = session.HasPermissions(Permissions.ACCESS_FORCE_START_ANY_MATCH_LISTING); bool kick = session.HasPermissions(Permissions.ACCESS_KICK_ANY_MATCH_LISTING); bool ban = session.HasPermissions(Permissions.ACCESS_BAN_ANY_MATCH_LISTING); if (play || kick || ban) { session.SendPacket(new MatchOwnerOutgoingMessage(this.Name, play, kick, ban)); } } this.TryStartFull(); return(true); }
internal MatchListing Join(ClientSession session, string roomName, out MatchListingJoinStatus status) { status = MatchListingJoinStatus.Failed; if (this.MatchListings.TryGetValue(roomName, out MatchListing matchListing)) { if (session.LobbySession.MatchListing == null) { status = matchListing.Join(session); if (status == MatchListingJoinStatus.Success) { return(matchListing); } } else if (session.LobbySession.MatchListing == matchListing) { status = MatchListingJoinStatus.Success; return(matchListing); } } return(null); }
internal MatchListingJoinStatus Join(ClientSession session) { if (!this._Clients.Contains(session)) { MatchListingJoinStatus canJoinStatus = this.CanJoin(session); if (canJoinStatus != MatchListingJoinStatus.Success) { return canJoinStatus; } while (true) //Concurrency complexity { int spotsLeft = this._SpotsLeft; if (spotsLeft > 0) { if (Interlocked.CompareExchange(ref this._SpotsLeft, spotsLeft - 1, spotsLeft) == spotsLeft) { break; } } else { //We are assuming if spotsLeft is int.MinValue it means the match has been started or is in progress of starting return spotsLeft == MatchListing.SPOTS_LEFT_GAME_STARTED ? MatchListingJoinStatus.Started : MatchListingJoinStatus.Full; } } if (this._Clients.Add(session)) { session.OnDisconnect -= this.OnCreatorDisconnectEarly; session.LobbySession.MatchListing = this; session.LobbySession.RemoveMatch(this); //Send the other clients foreach (ClientSession other in this._Clients.Values.OrderBy((c) => c == session)) { session.TrackUserInRoom(this.Name, other.SocketId, other.UserData.Id, other.UserData.Username, other.GetVars("userName", "rank", "hat", "head", "body", "feet", "hatColor", "headColor", "bodyColor", "feetColor", "socketID", "ping")); other.TrackUserInRoom(this.Name, session.SocketId, session.UserData.Id, session.UserData.Username, session.GetVars("userName", "rank", "hat", "head", "body", "feet", "hatColor", "headColor", "bodyColor", "feetColor", "socketID", "ping")); } foreach (ClientSession other in this.LobbyClients.Values) { other.TrackUserInRoom(this.Name, session.SocketId, session.UserData.Id, session.UserData.Username, session.GetVars("userName", "rank", "hat", "head", "body", "feet", "hatColor", "headColor", "bodyColor", "feetColor", "socketID", "ping")); } uint currentHost = this._HostSocketId; if (currentHost == session.SocketId || (currentHost == 0 && InterlockedExtansions.CompareExchange(ref this._HostSocketId, session.SocketId, currentHost) == currentHost)) { session.SendPacket(new MatchOwnerOutgoingMessage(this.Name, true, true, true)); } else if (!session.IsGuest) { bool play = session.HasPermissions(Permissions.ACCESS_FORCE_START_ANY_MATCH_LISTING); bool kick = session.HasPermissions(Permissions.ACCESS_KICK_ANY_MATCH_LISTING); bool ban = session.HasPermissions(Permissions.ACCESS_BAN_ANY_MATCH_LISTING); if (play || kick || ban) { session.SendPacket(new MatchOwnerOutgoingMessage(this.Name, play, kick, ban)); } } //Concurrency complexity if (Interlocked.Increment(ref this.UsersReady) == this.MaxMembers) //Ensures that there is no race condition while the SpotsLeft check is passed and user is being added to the clients list and ensuring safe start { if (Interlocked.CompareExchange(ref this._SpotsLeft, MatchListing.SPOTS_LEFT_GAME_STARTED, 0) == 0) //If no spots are left set the value to int.MinValue and start the match, starting should be thread-safe { this.Start(); } } return MatchListingJoinStatus.Success; } else { while (true) //Concurrency complexity { int spotsLeft = this._SpotsLeft; if (spotsLeft >= 0) { if (Interlocked.CompareExchange(ref this._SpotsLeft, spotsLeft + 1, spotsLeft) == spotsLeft) { break; } } } return MatchListingJoinStatus.Success; //We are gonna assume its failed due to dublication? } } else { return MatchListingJoinStatus.Success; } }