From 5be6b75ccf2c259f2c69a6169bab0ed3819ed05e Mon Sep 17 00:00:00 2001 From: RaidMax Date: Thu, 7 Jun 2018 21:19:12 -0500 Subject: [PATCH] [webfront] search by ip and name [application] levels set properly with multiple GUIDs [stats] require 3 hours of playtime for top stats recognition [application] configurable rcon polling rate --- Application/EventParsers/IW4EventParser.cs | 25 +++++++++++++++++- Application/Manager.cs | 2 +- Application/Server.cs | 5 ++++ Plugins/Stats/Helpers/ServerStats.cs | 2 +- Plugins/Stats/Helpers/StatManager.cs | 16 +++++------- .../Stats/Web/Views/Stats/_PenaltyInfo.cshtml | 2 +- .../Configuration/ApplicationConfiguration.cs | 3 +++ SharedLibraryCore/Services/ClientService.cs | 26 +++++++++++++------ .../wwwroot/css/bootstrap-custom.scss | 5 ++-- WebfrontCore/wwwroot/js/profile.js | 1 + 10 files changed, 64 insertions(+), 23 deletions(-) diff --git a/Application/EventParsers/IW4EventParser.cs b/Application/EventParsers/IW4EventParser.cs index 45eec4d38..834697fa5 100644 --- a/Application/EventParsers/IW4EventParser.cs +++ b/Application/EventParsers/IW4EventParser.cs @@ -15,6 +15,7 @@ namespace IW4MAdmin.Application.EventParsers string[] lineSplit = logLine.Split(';'); string cleanedEventLine = Regex.Replace(lineSplit[0], @"([0-9]+:[0-9]+ |^[0-9]+ )", "").Trim(); + // kill if (cleanedEventLine[0] == 'K') { if (!server.CustomCallback) @@ -30,7 +31,7 @@ namespace IW4MAdmin.Application.EventParsers } } - if(cleanedEventLine.Contains("JoinTeam")) + if (cleanedEventLine.Contains("JoinTeam")) { return new GameEvent() { @@ -91,6 +92,7 @@ namespace IW4MAdmin.Application.EventParsers }; } + // damage if (cleanedEventLine[0] == 'D') { if (Regex.Match(cleanedEventLine, @"^(D);((?:bot[0-9]+)|(?:[A-Z]|[0-9])+);([0-9]+);(axis|allies);(.+);((?:[A-Z]|[0-9])+);([0-9]+);(axis|allies);(.+);((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$").Success) @@ -106,6 +108,27 @@ namespace IW4MAdmin.Application.EventParsers } } + // join + if (cleanedEventLine[0] == 'J') + { + var regexMatch = Regex.Match(cleanedEventLine, @"^(J;)(.{4,32});([0-9]+);(.*)$"); + if (regexMatch.Success) + { + return new GameEvent() + { + Type = GameEvent.EventType.Join, + Data = cleanedEventLine, + Owner = server, + Origin = new Player() + { + Name = regexMatch.Groups[4].ToString(), + NetworkId = regexMatch.Groups[2].ToString().ConvertLong(), + ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString()) + } + }; + } + } + if (cleanedEventLine.Contains("ExitLevel")) { return new GameEvent() diff --git a/Application/Manager.cs b/Application/Manager.cs index d55dde26c..f16866216 100644 --- a/Application/Manager.cs +++ b/Application/Manager.cs @@ -139,7 +139,7 @@ namespace IW4MAdmin.Application sensitiveEvent.OnProcessed.Set(); } - await Task.Delay(2500); + await Task.Delay(ConfigHandler.Configuration().RConPollRate); } } diff --git a/Application/Server.cs b/Application/Server.cs index 69be8fe60..3a6c8b13e 100644 --- a/Application/Server.cs +++ b/Application/Server.cs @@ -480,6 +480,11 @@ namespace IW4MAdmin await AddPlayer(client); } + + /*else + { + await AddPlayer(E.Origin); + }*/ } else if (E.Type == GameEvent.EventType.Disconnect) diff --git a/Plugins/Stats/Helpers/ServerStats.cs b/Plugins/Stats/Helpers/ServerStats.cs index d5339bc53..ac76e3776 100644 --- a/Plugins/Stats/Helpers/ServerStats.cs +++ b/Plugins/Stats/Helpers/ServerStats.cs @@ -23,7 +23,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers public int TeamCount(IW4Info.Team teamName) { - if (PlayerStats.Count(p => p.Value.Team == IW4Info.Team.Spectator) / (double)PlayerStats.Count <= 0.25) + if (PlayerStats.Count(p => p.Value.Team == IW4Info.Team.None) / (double)PlayerStats.Count <= 0.25) { return IsTeamBased ? Math.Max(PlayerStats.Count(p => p.Value.Team == teamName), 1) : Math.Max(PlayerStats.Count - 1, 1); } diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs index fff067498..75bd7452f 100644 --- a/Plugins/Stats/Helpers/StatManager.cs +++ b/Plugins/Stats/Helpers/StatManager.cs @@ -53,7 +53,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers var thirtyDaysAgo = DateTime.UtcNow.AddMonths(-1); var iqClientRatings = (from rating in context.Set() #if !DEBUG - where rating.ActivityAmount > 3600 + where rating.ActivityAmount > 10800 #endif where rating.RatingHistory.Client.Level != Player.Permission.Banned where rating.RatingHistory.Client.LastConnection > thirtyDaysAgo @@ -255,6 +255,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers clientStats.LastActive = DateTime.UtcNow; clientStats.LastStatCalculation = DateTime.UtcNow; clientStats.SessionScore = pl.Score; + clientStats.LastScore = pl.Score; Log.WriteInfo($"Adding {pl} to stats"); @@ -429,14 +430,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers { async Task executePenalty(Cheat.DetectionPenaltyResult penalty) { - // prevent multiple bans/flags from occuring - if (attacker.Level != Player.Permission.User) - { - return; - } - - // this happens when a client is detected as cheating - if (penalty.ClientPenalty != Penalty.PenaltyType.Any) + async Task saveLog() { using (var ctx = new DatabaseContext()) { @@ -451,6 +445,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers switch (penalty.ClientPenalty) { case Penalty.PenaltyType.Ban: + await saveLog(); await attacker.Ban(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_CHEAT_DETECTED"], new Player() { ClientId = 1, @@ -466,6 +461,9 @@ namespace IW4MAdmin.Plugins.Stats.Helpers }); break; case Penalty.PenaltyType.Flag: + if (attacker.Level == Player.Permission.Flagged) + break; + await saveLog(); var e = new GameEvent() { Data = penalty.Type == Cheat.Detection.DetectionType.Bone ? diff --git a/Plugins/Stats/Web/Views/Stats/_PenaltyInfo.cshtml b/Plugins/Stats/Web/Views/Stats/_PenaltyInfo.cshtml index e3771157f..08f091a30 100644 --- a/Plugins/Stats/Web/Views/Stats/_PenaltyInfo.cshtml +++ b/Plugins/Stats/Web/Views/Stats/_PenaltyInfo.cshtml @@ -3,7 +3,7 @@ Layout = null; } -
+
@foreach (var snapshot in Model) { diff --git a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs index 0d4a7c3fb..4a6fa88dc 100644 --- a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs +++ b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs @@ -21,6 +21,7 @@ namespace SharedLibraryCore.Configuration public string CustomParserEncoding { get; set; } public string CustomLocale { get; set; } public string ConnectionString { get; set; } + public int RConPollRate { get; set; } = 5000; public string Id { get; set; } public List Servers { get; set; } public int AutoMessagePeriod { get; set; } @@ -59,6 +60,8 @@ namespace SharedLibraryCore.Configuration SocialLinkAddress = Utilities.PromptString(loc["SETUP_SOCIAL_LINK"]); } + RConPollRate = 5000; + return this; } diff --git a/SharedLibraryCore/Services/ClientService.cs b/SharedLibraryCore/Services/ClientService.cs index 87891a104..d811cd9da 100644 --- a/SharedLibraryCore/Services/ClientService.cs +++ b/SharedLibraryCore/Services/ClientService.cs @@ -57,7 +57,9 @@ namespace SharedLibraryCore.Services // set the level to the level of the existing client if they have the same IP + Name but new NetworkId // fixme: issues? Level = hasExistingAlias ? - context.Clients.First(c => c.AliasLinkId == existingAlias.LinkId).Level : + (await context.Clients.Where(c => c.AliasLinkId == existingAlias.LinkId) + .OrderByDescending(c => c.Level) + .FirstAsync()).Level : Player.Permission.User, FirstConnection = DateTime.UtcNow, Connections = 1, @@ -119,12 +121,12 @@ namespace SharedLibraryCore.Services { Client = client, LinkedAccounts = (from linkedClient in context.Clients - where client.AliasLinkId == linkedClient.AliasLinkId - select new - { - linkedClient.ClientId, - linkedClient.NetworkId - }) + where client.AliasLinkId == linkedClient.AliasLinkId + select new + { + linkedClient.ClientId, + linkedClient.NetworkId + }) }; var foundClient = await iqClient.FirstOrDefaultAsync(); @@ -260,10 +262,18 @@ namespace SharedLibraryCore.Services using (var context = new DatabaseContext()) { + context.ChangeTracker.AutoDetectChangesEnabled = false; + context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; + + int asIP = name.ConvertToIP(); + // hack: so IW4MAdmin doesn't show up in search results + asIP = asIP == 0 ? int.MinValue : asIP; + var iqClients = (from alias in context.Aliases .AsNoTracking() where alias.Name.ToLower() - .Contains(name.ToLower()) + .Contains(name.ToLower()) || + alias.IPAddress == asIP join link in context.AliasLinks on alias.LinkId equals link.AliasLinkId join client in context.Clients diff --git a/WebfrontCore/wwwroot/css/bootstrap-custom.scss b/WebfrontCore/wwwroot/css/bootstrap-custom.scss index 5a0bb38fd..fcfdebe47 100644 --- a/WebfrontCore/wwwroot/css/bootstrap-custom.scss +++ b/WebfrontCore/wwwroot/css/bootstrap-custom.scss @@ -202,6 +202,7 @@ select { font-size: 1rem; } -.client-message { - cursor:pointer; +.client-message, .automated-penalty-info-detailed { + cursor: pointer; } + diff --git a/WebfrontCore/wwwroot/js/profile.js b/WebfrontCore/wwwroot/js/profile.js index 9f0b4b14c..dc8ba4648 100644 --- a/WebfrontCore/wwwroot/js/profile.js +++ b/WebfrontCore/wwwroot/js/profile.js @@ -85,6 +85,7 @@ $(document).ready(function () { 'clientId': $(this).data('clientid'), }) .done(function (response) { + $('.penalty-info-context').remove(); location.after(response); hideLoader(); })