From 8119ff9f83044f58a030621d1639e5f271b5ebca Mon Sep 17 00:00:00 2001 From: RaidMax Date: Mon, 24 Jun 2019 16:56:47 -0500 Subject: [PATCH] adjust detection thresholds for recoil and offset make sure we don't keep adding penalties after first add "Other" penalty for future plugin use --- Plugins/Stats/Cheat/Detection.cs | 159 +----------------- Plugins/Stats/Cheat/Strain.cs | 2 +- Plugins/Stats/Helpers/StatManager.cs | 61 ++++--- .../PartialEntities/EFPenalty.cs | 3 +- 4 files changed, 41 insertions(+), 184 deletions(-) diff --git a/Plugins/Stats/Cheat/Detection.cs b/Plugins/Stats/Cheat/Detection.cs index d7b9f2aff..ede9df77e 100644 --- a/Plugins/Stats/Cheat/Detection.cs +++ b/Plugins/Stats/Cheat/Detection.cs @@ -21,9 +21,9 @@ namespace IW4MAdmin.Plugins.Stats.Cheat }; public ChangeTracking Tracker { get; private set; } - public const int QUEUE_COUNT = 10; + public const int MAX_TRACKED_HIT_COUNT = 10; - public List QueuedHits { get; set; } + public List TrackedHits { get; set; } int Kills; int HitCount; Dictionary HitLocationCount; @@ -54,7 +54,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat ClientStats = clientStats; Strain = new Strain(); Tracker = new ChangeTracking(); - QueuedHits = new List(); + TrackedHits = new List(); } /// @@ -136,7 +136,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat AngleDifferenceAverage = weightedSessionAverage; if (weightedSessionAverage > Thresholds.MaxOffset(totalSessionHits) && - totalSessionHits > 40) + totalSessionHits >= (Thresholds.MediumSampleMinKills * 2)) { Log.WriteDebug("*** Reached Max Session Average for Angle Difference ***"); Log.WriteDebug($"Session Average = {weightedSessionAverage}"); @@ -157,8 +157,11 @@ namespace IW4MAdmin.Plugins.Stats.Cheat Log.WriteDebug($"PredictVsReal={realAgainstPredict}"); #endif } + #endregion - double currentStrain = Strain.GetStrain(isDamage, hit.Damage, hit.Distance / 0.0254, hit.ViewAngles, Math.Max(50, hit.TimeOffset - LastOffset)); + + #region STRAIN + double currentStrain = Strain.GetStrain(hit.Distance / 0.0254, hit.ViewAngles, Math.Max(50, hit.TimeOffset - LastOffset)); #if DEBUG == true Log.WriteDebug($"Current Strain: {currentStrain}"); #endif @@ -213,7 +216,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat }); } - if (ClientStats.AverageRecoilOffset == 0 && HitCount > Thresholds.HighSampleMinKills) + if (ClientStats.AverageRecoilOffset == 0 && HitCount >= Thresholds.LowSampleMinKills) { results.Add(new DetectionPenaltyResult() { @@ -251,19 +254,6 @@ namespace IW4MAdmin.Plugins.Stats.Cheat // ban on headshot if (currentHeadshotRatio > maxHeadshotLerpValueForBan) { - //Log.WriteDebug("**Maximum Headshot Ratio Reached For Ban**"); - //Log.WriteDebug($"ClientId: {hit.AttackerId}"); - //Log.WriteDebug($"**HitCount: {HitCount}"); - //Log.WriteDebug($"**Ratio {currentHeadshotRatio}"); - //Log.WriteDebug($"**MaxRatio {maxHeadshotLerpValueForFlag}"); - //var sb = new StringBuilder(); - //foreach (var kvp in HitLocationCount) - //{ - // sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n"); - //} - - //Log.WriteDebug(sb.ToString()); - results.Add(new DetectionPenaltyResult() { ClientPenalty = EFPenalty.PenaltyType.Ban, @@ -275,19 +265,6 @@ namespace IW4MAdmin.Plugins.Stats.Cheat } else { - //Log.WriteDebug("**Maximum Headshot Ratio Reached For Flag**"); - //Log.WriteDebug($"ClientId: {hit.AttackerId}"); - //Log.WriteDebug($"**HitCount: {HitCount}"); - //Log.WriteDebug($"**Ratio {currentHeadshotRatio}"); - //Log.WriteDebug($"**MaxRatio {maxHeadshotLerpValueForFlag}"); - //var sb = new StringBuilder(); - //foreach (var kvp in HitLocationCount) - //{ - // sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n"); - //} - - //Log.WriteDebug(sb.ToString()); - results.Add(new DetectionPenaltyResult() { ClientPenalty = EFPenalty.PenaltyType.Flag, @@ -307,19 +284,6 @@ namespace IW4MAdmin.Plugins.Stats.Cheat // ban on bone ratio if (currentMaxBoneRatio > maxBoneRatioLerpValueForBan) { - //Log.WriteDebug("**Maximum Bone Ratio Reached For Ban**"); - //Log.WriteDebug($"ClientId: {hit.AttackerId}"); - //Log.WriteDebug($"**HitCount: {HitCount}"); - //Log.WriteDebug($"**Ratio {currentMaxBoneRatio}"); - //Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValueForBan}"); - //var sb = new StringBuilder(); - //foreach (var kvp in HitLocationCount) - //{ - // sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n"); - //} - - //Log.WriteDebug(sb.ToString()); - results.Add(new DetectionPenaltyResult() { ClientPenalty = EFPenalty.PenaltyType.Ban, @@ -331,19 +295,6 @@ namespace IW4MAdmin.Plugins.Stats.Cheat } else { - //Log.WriteDebug("**Maximum Bone Ratio Reached For Flag**"); - //Log.WriteDebug($"ClientId: {hit.AttackerId}"); - //Log.WriteDebug($"**HitCount: {HitCount}"); - //Log.WriteDebug($"**Ratio {currentMaxBoneRatio}"); - //Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValueForFlag}"); - //var sb = new StringBuilder(); - //foreach (var kvp in HitLocationCount) - //{ - // sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n"); - //} - - //Log.WriteDebug(sb.ToString()); - results.Add(new DetectionPenaltyResult() { ClientPenalty = EFPenalty.PenaltyType.Flag, @@ -375,16 +326,6 @@ namespace IW4MAdmin.Plugins.Stats.Cheat if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan && chestHits >= Thresholds.MediumSampleMinKills * 2) { - //Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Ban**"); - //Log.WriteDebug($"ClientId: {hit.AttackerId}"); - //Log.WriteDebug($"**Chest Hits: {chestHits}"); - //Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}"); - //Log.WriteDebug($"**MaxRatio {chestAbdomenLerpValueForBan}"); - //var sb = new StringBuilder(); - //foreach (var kvp in HitLocationCount) - // sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n"); - //Log.WriteDebug(sb.ToString()); - results.Add(new DetectionPenaltyResult() { ClientPenalty = EFPenalty.PenaltyType.Ban, @@ -396,16 +337,6 @@ namespace IW4MAdmin.Plugins.Stats.Cheat } else { - //Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Flag**"); - //Log.WriteDebug($"ClientId: {hit.AttackerId}"); - //Log.WriteDebug($"**Chest Hits: {chestHits}"); - //Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}"); - //Log.WriteDebug($"**MaxRatio {chestAbdomenRatioLerpValueForFlag}"); - //var sb = new StringBuilder(); - //foreach (var kvp in HitLocationCount) - // sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n"); - //Log.WriteDebug(sb.ToString()); - results.Add(new DetectionPenaltyResult() { ClientPenalty = EFPenalty.PenaltyType.Flag, @@ -457,77 +388,5 @@ namespace IW4MAdmin.Plugins.Stats.Cheat ClientPenalty = EFPenalty.PenaltyType.Any, }; } - - public DetectionPenaltyResult ProcessTotalRatio(EFClientStatistics stats) - { - int totalChestHits = stats.HitLocations.Single(c => c.Location == IW4Info.HitLocation.torso_upper).HitCount; - var results = new List(); - - if (totalChestHits >= Thresholds.MediumSampleMinKills * 2) - { - double marginOfError = Thresholds.GetMarginOfError(totalChestHits); - double lerpAmount = Math.Min(1.0, (totalChestHits - 60) / 250.0); - // determine max acceptable ratio of chest to abdomen kills - double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdHighSample(3.0), Thresholds.ChestAbdomenRatioThresholdHighSample(2.0), lerpAmount) + marginOfError; - double chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdHighSample(4.0), Thresholds.ChestAbdomenRatioThresholdHighSample(3.0), lerpAmount) + marginOfError; - - double currentChestAbdomenRatio = totalChestHits / - stats.HitLocations.Single(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount; - - if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag) - { - - if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan) - { - //Log.WriteDebug("**Maximum Lifetime Chest/Abdomen Ratio Reached For Ban**"); - //Log.WriteDebug($"ClientId: {stats.ClientId}"); - //Log.WriteDebug($"**Total Chest Hits: {totalChestHits}"); - //Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}"); - //Log.WriteDebug($"**MaxRatio {chestAbdomenLerpValueForBan}"); - //var sb = new StringBuilder(); - //foreach (var location in stats.HitLocations) - // sb.Append($"HitLocation: {location.Location} -> {location.HitCount}\r\n"); - //Log.WriteDebug(sb.ToString()); - - results.Add(new DetectionPenaltyResult() - { - ClientPenalty = EFPenalty.PenaltyType.Ban, - Value = currentChestAbdomenRatio, - Location = IW4Info.HitLocation.torso_upper, - HitCount = totalChestHits, - Type = DetectionType.Chest - }); - } - else - { - //Log.WriteDebug("**Maximum Lifetime Chest/Abdomen Ratio Reached For Flag**"); - //Log.WriteDebug($"ClientId: {stats.ClientId}"); - //Log.WriteDebug($"**Total Chest Hits: {totalChestHits}"); - //Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}"); - //Log.WriteDebug($"**MaxRatio {chestAbdomenRatioLerpValueForFlag}"); - //var sb = new StringBuilder(); - //foreach (var location in stats.HitLocations) - // sb.Append($"HitLocation: {location.Location} -> {location.HitCount}\r\n"); - //Log.WriteDebug(sb.ToString()); - - results.Add(new DetectionPenaltyResult() - { - ClientPenalty = EFPenalty.PenaltyType.Flag, - Value = currentChestAbdomenRatio, - Location = IW4Info.HitLocation.torso_upper, - HitCount = totalChestHits, - Type = DetectionType.Chest - }); - } - } - } - - return results.FirstOrDefault(_result => _result.ClientPenalty == EFPenalty.PenaltyType.Ban) ?? - results.FirstOrDefault(_result => _result.ClientPenalty == EFPenalty.PenaltyType.Flag) ?? - new DetectionPenaltyResult() - { - ClientPenalty = EFPenalty.PenaltyType.Any, - }; - } } } diff --git a/Plugins/Stats/Cheat/Strain.cs b/Plugins/Stats/Cheat/Strain.cs index fdded1d7d..56aee14b1 100644 --- a/Plugins/Stats/Cheat/Strain.cs +++ b/Plugins/Stats/Cheat/Strain.cs @@ -14,7 +14,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat public Vector3 LastAngle { get; private set; } public double LastDeltaTime { get; private set; } - public double GetStrain(bool isDamage, int damage, double killDistance, Vector3 newAngle, double deltaTime) + public double GetStrain(double killDistance, Vector3 newAngle, double deltaTime) { if (LastAngle == null) LastAngle = newAngle; diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs index 581ee9d8b..6fd38b8ba 100644 --- a/Plugins/Stats/Helpers/StatManager.cs +++ b/Plugins/Stats/Helpers/StatManager.cs @@ -502,11 +502,11 @@ namespace IW4MAdmin.Plugins.Stats.Helpers DeathOrigin = vDeathOrigin, KillOrigin = vKillOrigin, DeathType = ParseEnum.Get(type, typeof(IW4Info.MeansOfDeath)), - Damage = Int32.Parse(damage), + Damage = int.Parse(damage), HitLoc = ParseEnum.Get(hitLoc, typeof(IW4Info.HitLocation)), Weapon = ParseEnum.Get(weapon, typeof(IW4Info.WeaponName)), ViewAngles = vViewAngles, - TimeOffset = Int64.Parse(offset), + TimeOffset = long.Parse(offset), When = time, IsKillstreakKill = isKillstreakKill[0] != '0', AdsPercent = float.Parse(Ads, System.Globalization.CultureInfo.InvariantCulture), @@ -542,12 +542,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers var clientDetection = _servers[serverId].PlayerDetections[attacker.ClientId]; var clientStats = _servers[serverId].PlayerStats[attacker.ClientId]; - using (var ctx = new DatabaseContext(disableTracking: true)) - { - ctx.Set().Update(clientStats); - await ctx.SaveChangesAsync(); - } - // increment their hit count if (hit.DeathType == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET || hit.DeathType == IW4Info.MeansOfDeath.MOD_RIFLE_BULLET || @@ -556,10 +550,14 @@ namespace IW4MAdmin.Plugins.Stats.Helpers clientStats.HitLocations.Single(hl => hl.Location == hit.HitLoc).HitCount += 1; } + using (var ctx = new DatabaseContext(disableTracking: true)) + { + ctx.Set().Update(clientStats); + await ctx.SaveChangesAsync(); + } + using (var ctx = new DatabaseContext()) { - await OnProcessingPenalty.WaitAsync(); - try { if (Plugin.Config.Configuration().StoreClientKills) @@ -573,40 +571,41 @@ namespace IW4MAdmin.Plugins.Stats.Helpers #if DEBUG if (clientDetection.QueuedHits.Count > 0) #else - if (clientDetection.QueuedHits.Count > Detection.QUEUE_COUNT) + if (clientDetection.TrackedHits.Count > Detection.MAX_TRACKED_HIT_COUNT) #endif { - while (clientDetection.QueuedHits.Count > 0) + while (clientDetection.TrackedHits.Count > 0) { - clientDetection.QueuedHits = clientDetection.QueuedHits.OrderBy(_hits => _hits.TimeOffset).ToList(); - var oldestHit = clientDetection.QueuedHits.First(); - clientDetection.QueuedHits.RemoveAt(0); + await OnProcessingPenalty.WaitAsync(); + + var oldestHit = clientDetection.TrackedHits.OrderBy(_hits => _hits.TimeOffset).First(); + clientDetection.TrackedHits.Remove(oldestHit); + result = clientDetection.ProcessHit(oldestHit, isDamage); await ApplyPenalty(result, attacker, ctx); if (clientDetection.Tracker.HasChanges && result.ClientPenalty != EFPenalty.PenaltyType.Any) { SaveTrackedSnapshots(clientDetection, ctx); + + if (result.ClientPenalty == EFPenalty.PenaltyType.Ban) + { + OnProcessingPenalty.Release(1); + break; + } } - } - result = clientDetection.ProcessTotalRatio(clientStats); - await ApplyPenalty(result , attacker, ctx); - - if (clientDetection.Tracker.HasChanges && result.ClientPenalty != EFPenalty.PenaltyType.Any) - { - SaveTrackedSnapshots(clientDetection, ctx); + OnProcessingPenalty.Release(1); } } else { - clientDetection.QueuedHits.Add(hit); + clientDetection.TrackedHits.Add(hit); } } ctx.Set().UpdateRange(clientStats.HitLocations); - await ctx.SaveChangesAsync(); } @@ -615,8 +614,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers _log.WriteError("Could not save hit or AC info"); _log.WriteDebug(ex.GetExceptionInfo()); } - - OnProcessingPenalty.Release(1); } } @@ -859,7 +856,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers ctx.Add(clientHistory); } -#region INDIVIDUAL_SERVER_PERFORMANCE + #region INDIVIDUAL_SERVER_PERFORMANCE // get the client ranking for the current server int individualClientRanking = await ctx.Set() .Where(GetRankingFunc(clientStats.ServerId)) @@ -910,8 +907,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers // add new rating for current server ctx.Add(newServerRating); -#endregion -#region OVERALL_RATING + #endregion + #region OVERALL_RATING // select all performance & time played for current client var iqClientStats = from stats in ctx.Set() where stats.ClientId == client.ClientId @@ -986,7 +983,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers }; ctx.Add(averageRating); -#endregion + #endregion await ctx.SaveChangesAsync(); } @@ -1021,7 +1018,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers // calulate elo if (_servers[attackerStats.ServerId].PlayerStats.Count > 1) { -#region DEPRECATED + #region DEPRECATED /* var validAttackerLobbyRatings = Servers[attackerStats.ServerId].PlayerStats .Where(cs => cs.Value.ClientId != attackerStats.ClientId) .Where(cs => @@ -1045,7 +1042,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers double victimLobbyRating = validVictimLobbyRatings.Count() > 0 ? validVictimLobbyRatings.Average(cs => cs.Value.EloRating) : victimStats.EloRating;*/ -#endregion + #endregion double attackerEloDifference = Math.Log(Math.Max(1, victimStats.EloRating)) - Math.Log(Math.Max(1, attackerStats.EloRating)); double winPercentage = 1.0 / (1 + Math.Pow(10, attackerEloDifference / Math.E)); diff --git a/SharedLibraryCore/PartialEntities/EFPenalty.cs b/SharedLibraryCore/PartialEntities/EFPenalty.cs index 023bcdf97..8663d6b93 100644 --- a/SharedLibraryCore/PartialEntities/EFPenalty.cs +++ b/SharedLibraryCore/PartialEntities/EFPenalty.cs @@ -15,7 +15,8 @@ namespace SharedLibraryCore.Database.Models Ban, Unban, Any, - Unflag + Unflag, + Other = 100 } } }