diff --git a/Application/GameEventHandler.cs b/Application/GameEventHandler.cs index f13af1f5d..7c9483820 100644 --- a/Application/GameEventHandler.cs +++ b/Application/GameEventHandler.cs @@ -51,24 +51,8 @@ namespace IW4MAdmin.Application public GameEvent GetNextEvent() { - if (EventQueue.Count > 0) - { -#if DEBUG - Manager.GetLogger().WriteDebug("Getting next event to be processed"); -#endif - if (!EventQueue.TryDequeue(out GameEvent newEvent)) - { - Manager.GetLogger().WriteWarning("Could not dequeue event for processing"); - } - - else - { - return newEvent; - } - } - if (DelayedEventQueue.Count > 0 && - (DateTime.Now - LastDelayedEvent).TotalMilliseconds > DelayAmount) + (DateTime.Now - LastDelayedEvent).TotalMilliseconds > DelayAmount) { LastDelayedEvent = DateTime.Now; #if DEBUG @@ -85,6 +69,22 @@ namespace IW4MAdmin.Application } } + if (EventQueue.Count > 0) + { +#if DEBUG + Manager.GetLogger().WriteDebug("Getting next event to be processed"); +#endif + if (!EventQueue.TryDequeue(out GameEvent newEvent)) + { + Manager.GetLogger().WriteWarning("Could not dequeue event for processing"); + } + + else + { + return newEvent; + } + } + return null; } } diff --git a/Application/Manager.cs b/Application/Manager.cs index cb46c8cd2..0dd930dae 100644 --- a/Application/Manager.cs +++ b/Application/Manager.cs @@ -79,16 +79,29 @@ namespace IW4MAdmin.Application return Instance ?? (Instance = new ApplicationManager()); } - public async Task UpdateStatus(object state) + public async Task UpdateServerStates() { - var taskList = new List(); + // store the server hash code and task for it + var runningUpdateTasks = new Dictionary(); while (Running) { - taskList.Clear(); - foreach (var server in Servers) + // select the server ids that have completed the update task + var serverTasksToRemove = runningUpdateTasks + .Where(ut => ut.Value.Status != TaskStatus.Running) + .Select(ut => ut.Key) + .ToList(); + + // remove the update tasks as they have completd + foreach (int serverId in serverTasksToRemove) { - taskList.Add(Task.Run(async () => + runningUpdateTasks.Remove(serverId); + } + + // select the servers where the tasks have completed + foreach (var server in Servers.Where(s => serverTasksToRemove.Count == 0 ? true : serverTasksToRemove.Contains(GetHashCode()))) + { + runningUpdateTasks.Add(server.GetHashCode(), Task.Run(async () => { try { @@ -104,13 +117,11 @@ namespace IW4MAdmin.Application })); } #if DEBUG - Logger.WriteDebug($"{taskList.Count} servers queued for stats updates"); + Logger.WriteDebug($"{runningUpdateTasks.Count} servers queued for stats updates"); ThreadPool.GetMaxThreads(out int workerThreads, out int n); ThreadPool.GetAvailableThreads(out int availableThreads, out int m); Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks"); #endif - - await Task.WhenAny(taskList); await Task.Delay(ConfigHandler.Configuration().RConPollRate); } } @@ -380,7 +391,7 @@ namespace IW4MAdmin.Application // start heartbeat Task.Run(() => SendHeartbeat(new HeartbeatState())); #endif - Task.Run(() => UpdateStatus(null)); + Task.Run(() => UpdateServerStates()); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed var eventList = new List(); @@ -446,12 +457,6 @@ namespace IW4MAdmin.Application await processEvent(queuedEvent); } - if (taskList.Count > 0) - { - // this should allow parallel processing of events - await Task.WhenAny(taskList); - } - // signal that all events have been processed OnEvent.Reset(); } @@ -462,7 +467,6 @@ namespace IW4MAdmin.Application _servers.Clear(); } - public void Stop() { Running = false; diff --git a/Application/RconParsers/IW4RConParser.cs b/Application/RconParsers/IW4RConParser.cs index f71585b2a..3ac146e79 100644 --- a/Application/RconParsers/IW4RConParser.cs +++ b/Application/RconParsers/IW4RConParser.cs @@ -119,7 +119,8 @@ namespace Application.RconParsers if (P.IsBot) { - P.IPAddress = P.ClientNumber + 1; + // set it to 127.0.0.2 + P.IPAddress = 33554559; } StatusPlayers.Add(P); diff --git a/Application/Server.cs b/Application/Server.cs index d0a64d4ca..6e2aabf5e 100644 --- a/Application/Server.cs +++ b/Application/Server.cs @@ -56,9 +56,11 @@ namespace IW4MAdmin public async Task OnPlayerJoined(Player logClient) { - Logger.WriteDebug($"Log detected {logClient} joining"); - if (Players[logClient.ClientNumber] == null || Players[logClient.ClientNumber].NetworkId != logClient.NetworkId) + + if (Players[logClient.ClientNumber] == null || + Players[logClient.ClientNumber].NetworkId != logClient.NetworkId) { + Logger.WriteDebug($"Log detected {logClient} joining"); Players[logClient.ClientNumber] = logClient; } @@ -78,13 +80,27 @@ namespace IW4MAdmin if (Players[polledPlayer.ClientNumber] != null && Players[polledPlayer.ClientNumber].NetworkId == polledPlayer.NetworkId && // only update if they're unauthenticated - Players[polledPlayer.ClientNumber].IsAuthenticated) + Players[polledPlayer.ClientNumber].IsAuthenticated && + Players[polledPlayer.ClientNumber].State == Player.ClientState.Connected) { // update their ping & score Players[polledPlayer.ClientNumber].Ping = polledPlayer.Ping; Players[polledPlayer.ClientNumber].Score = polledPlayer.Score; return true; } + + if (Players[polledPlayer.ClientNumber] != null && + Players[polledPlayer.ClientNumber].State == Player.ClientState.Connected) + { + return true; + } + + if (Players[polledPlayer.ClientNumber] == null) + { + //prevent duplicates from being added + polledPlayer.State = Player.ClientState.Connecting; + Players[polledPlayer.ClientNumber] = polledPlayer; + } #if !DEBUG if (polledPlayer.Name.Length < 3) { @@ -260,7 +276,7 @@ namespace IW4MAdmin Leaving.TotalConnectionTime += (int)(DateTime.UtcNow - Leaving.ConnectionTime).TotalSeconds; Leaving.LastConnection = DateTime.UtcNow; await Manager.GetClientService().Update(Leaving); - Players.RemoveAt(cNum); + Players[cNum] = null; } } } @@ -372,7 +388,10 @@ namespace IW4MAdmin Owner = this }; - e.Origin.State = Player.ClientState.Disconnecting; + if (e.Origin != null) + { + e.Origin.State = Player.ClientState.Disconnecting; + } Manager.GetEventHandler().AddEvent(e); } @@ -530,7 +549,10 @@ namespace IW4MAdmin // all polled players should be authenticated foreach (var client in AuthQueue.GetAuthenticatedClients()) { - await AddPlayer(client); + if (Players[client.ClientNumber] == null || Players[client.ClientNumber].State == Player.ClientState.Connecting) + { + await AddPlayer(client); + } } return CurrentPlayers.Count; @@ -549,7 +571,7 @@ namespace IW4MAdmin { // todo: fix up disconnect //for (int i = 0; i < Players.Count; i++) - // await RemovePlayer(i); + // await RemovePlayer(i); foreach (var plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins) await plugin.OnUnloadAsync(); diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index 735160ea8..ef5d8ca2d 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -187,7 +187,7 @@ namespace SharedLibraryCore return id; var bot = Regex.Match(str, @"bot[0-9]+").Value; if (!string.IsNullOrEmpty(bot)) - return -Convert.ToInt64(bot.Substring(3)) + 1; + return -1;//Convert.ToInt64(bot.Substring(3)) + 1; return 0; }