public void RemovePlayersSafe() { object _lock = new object(); lock (_lock) { RemovePlayers.ForEach(o => Game.Players.Remove(o)); RemovePlayers.Clear(); } }
public void Update(ServerState newState, Connection connection) { lock (ServerStateLock) { if (Status != newState.Status) { connection.RecordMatchResults(this); } if (connection.ServerHookEnabled && Teams != newState.Teams) { Scoreboard.RegenerateScoreboardImage = true; } Name = newState.Name; Port = newState.Port; HostPlayer = newState.HostPlayer; SprintEnabled = newState.SprintEnabled; SprintUnlimitedEnabled = newState.SprintUnlimitedEnabled; DualWielding = newState.DualWielding; AssassinationEnabled = newState.AssassinationEnabled; VotingEnabled = newState.VotingEnabled; Teams = newState.Teams; Map = newState.Map; MapFile = newState.MapFile; Variant = newState.Variant; VariantType = newState.VariantType; NumPlayers = newState.NumPlayers; MaxPlayers = newState.MaxPlayers; TeamScores = newState.TeamScores; Passworded = newState.Passworded; Xnkid = newState.Xnkid; Xnaddr = newState.Xnaddr; IsDedicated = newState.IsDedicated; GameVersion = newState.GameVersion; EldewritoVersion = newState.EldewritoVersion; PreviousStatus = Status; Status = newState.Status; inLobby = Status == "InLobby"; isLoading = Status == "Loading"; GameVariantType = GameVariant.GetBaseGameID(VariantType); } //string date = System.DateTime.Now.ToString("[MM-dd-yyyy HH:mm:ss] "); string date = $"[{DateTimeUTC()}] "; // Detect Match Start and End if (Status != PreviousStatus) { // Game Started if (Status == Connection.StatusStringInGame) { connection.InvokeMatchBeganOrEnded(new Connection.MatchBeginEndArgs(true, connection)); //connection.OnMatchBeginOrEnd(this, new Connection.MatchBeginEndArgs(true, connection)); connection.PrintToConsole("Game Started: " + newState.Variant + " ON " + newState.Map); } // Game Ended else if (Status == Connection.StatusStringInLobby && PreviousStatus == Connection.StatusStringInGame) { connection.InvokeMatchBeganOrEnded(new Connection.MatchBeginEndArgs(false, connection)); //connection.OnMatchBeginOrEnd(this, new Connection.MatchBeginEndArgs(false, connection)); connection.PrintToConsole("Game Ended"); PlayerStatsRecord match; foreach (PlayerInfo player in Players) { match = App.PlayerStatsRecords.Value.Find(x => x.Uid == player.Uid); if (match != null) { match.Kills += player.Kills; match.Deaths += player.Deaths; } else { match = new PlayerStatsRecord(player); if (match.IsValid) { App.PlayerStatsRecords.Value.Add(match); } } } App.PlayerStatsRecords.Save(); } } // For each player in the new server state's player list foreach (PlayerInfo player in newState.Players) { if (player.Name.Length == 0) { continue; } if (!Teams) { player.Team = -1; } else if (Status == Connection.StatusStringInLobby) { player.Team = -1; } else if (Status == Connection.StatusStringLoading) { player.Team = -1; } // If the player list does not contain this player, this player has just joined the game PlayerInfo match = Players.Find(x => x.Uid == player.Uid); if (match == null) { connection.PrintToPlayerLog(player.Name + " - " + player.ServiceTag + " : " + player.Uid + " has Joined."); connection.OnPlayerJoined(new Connection.PlayerJoinLeaveEventArgs(player, true, newState.Players.Count, date, connection)); lock (ServerStateLock) { // add new player to the player list Players.Add(player); } } } // For each player in the player list foreach (PlayerInfo player in Players) { // If the new server state's player list does not contain this player, this player has just left the game //NOTE added '&& x.Name == player.Name', so if any bugs crop up check here PlayerInfo match = newState.Players.Find(x => x.Uid == player.Uid && x.Name == player.Name); if (match == null) { connection.PrintToPlayerLog(player.Name + " - " + player.ServiceTag + " : " + player.Uid + " has Left."); connection.OnPlayerLeft(new Connection.PlayerJoinLeaveEventArgs(player, false, newState.Players.Count, date, connection)); // Mark player for removal from players list RemovePlayers.Add(player); } else { if (player.Team != match.Team && player.Team != -1 && match.Team != -1) { // Player has switched teams connection.OnPlayerTeamChanged(this, new Connection.PlayerTeamChangeEventArgs(match, player, connection)); } lock (ServerStateLock) { // Update the player's stats player.Update(match); } } } lock (ServerStateLock) { // Remove players that left from the player list foreach (PlayerInfo removePlayer in RemovePlayers) { Players.Remove(removePlayer); } RemovePlayers.Clear(); // Sort by team and then by score List <IGrouping <int, PlayerInfo> > teams = Players.GroupBy(x => x.Team).OrderBy(x => x.Key).ToList(); Players.Clear(); foreach (IGrouping <int, PlayerInfo> team in teams) { Players.AddRange(team.OrderByDescending(x => x.Score)); } OrderedTeamScores.Clear(); OrderedTeams.Clear(); RankedPlayers.Clear(); // Sort team scores for scoreboard display if (Teams) { OrderedTeamScores = TeamScores.Select( (x, i) => (Players.Any(p => p.Team == i)) ? new Tuple <int, int>(i, x) : new Tuple <int, int>(-1, x) ) // Mark all empty teams with -1 .Where(x => x.Item1 > -1) // Grab all non-empty teams .OrderByDescending(x => x.Item2).ToList(); // Order teams by score (descending) connection.PopulatedTeams = OrderedTeamScores?.Count ?? 1; for (int i = 0; i < OrderedTeamScores.Count; i++) { OrderedTeams.Add( new Tuple <Tuple <int, int>, List <PlayerInfo> >( OrderedTeamScores[i], Players.Where(x => x.Team == OrderedTeamScores[i].Item1).ToList() ) ); } } } }