diff --git a/Plugins/SimpleStats/Cheat/Detection.cs b/Plugins/SimpleStats/Cheat/Detection.cs index 5958708f..13ec070c 100644 --- a/Plugins/SimpleStats/Cheat/Detection.cs +++ b/Plugins/SimpleStats/Cheat/Detection.cs @@ -60,7 +60,7 @@ namespace StatsPlugin.Cheat var calculatedVector = Vector3.Subtract(kill.KillOrigin, new Vector3((float)x, (float)y, (float)z)); double angle = trueVector.AngleBetween(calculatedVector); - if (kill.AdsPercent > 0.5) + if (kill.AdsPercent > 0.5 && kill.Distance > 3) { var hitLoc = ClientStats.HitLocations .First(hl => hl.Location == kill.HitLoc); @@ -69,264 +69,264 @@ namespace StatsPlugin.Cheat hitLoc.HitOffsetAverage = (float)newAverage; } -#endregion + #endregion -#region SESSION_RATIOS -if (Kills >= Thresholds.LowSampleMinKills) -{ - double marginOfError = Thresholds.GetMarginOfError(Kills); - // determine what the max headshot percentage can be for current number of kills - double lerpAmount = Math.Min(1.0, (Kills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills)); - double maxHeadshotLerpValueForFlag = Thresholds.Lerp(Thresholds.HeadshotRatioThresholdLowSample(2.0), Thresholds.HeadshotRatioThresholdHighSample(2.0), lerpAmount) + marginOfError; - double maxHeadshotLerpValueForBan = Thresholds.Lerp(Thresholds.HeadshotRatioThresholdLowSample(3.0), Thresholds.HeadshotRatioThresholdHighSample(3.0), lerpAmount) + marginOfError; - // determine what the max bone percentage can be for current number of kills - double maxBoneRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample(2.25), Thresholds.BoneRatioThresholdHighSample(2.25), lerpAmount) + marginOfError; - double maxBoneRatioLerpValueForBan = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample(3.25), Thresholds.BoneRatioThresholdHighSample(3.25), lerpAmount) + marginOfError; + #region SESSION_RATIOS + if (Kills >= Thresholds.LowSampleMinKills) + { + double marginOfError = Thresholds.GetMarginOfError(Kills); + // determine what the max headshot percentage can be for current number of kills + double lerpAmount = Math.Min(1.0, (Kills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills)); + double maxHeadshotLerpValueForFlag = Thresholds.Lerp(Thresholds.HeadshotRatioThresholdLowSample(2.0), Thresholds.HeadshotRatioThresholdHighSample(2.0), lerpAmount) + marginOfError; + double maxHeadshotLerpValueForBan = Thresholds.Lerp(Thresholds.HeadshotRatioThresholdLowSample(3.0), Thresholds.HeadshotRatioThresholdHighSample(3.0), lerpAmount) + marginOfError; + // determine what the max bone percentage can be for current number of kills + double maxBoneRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample(2.25), Thresholds.BoneRatioThresholdHighSample(2.25), lerpAmount) + marginOfError; + double maxBoneRatioLerpValueForBan = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample(3.25), Thresholds.BoneRatioThresholdHighSample(3.25), lerpAmount) + marginOfError; - // calculate headshot ratio - double currentHeadshotRatio = ((HitLocationCount[IW4Info.HitLocation.head] + HitLocationCount[IW4Info.HitLocation.helmet]) / (double)Kills); - // calculate maximum bone - double currentMaxBoneRatio = (HitLocationCount.Values.Select(v => v / (double)Kills).Max()); + // calculate headshot ratio + double currentHeadshotRatio = ((HitLocationCount[IW4Info.HitLocation.head] + HitLocationCount[IW4Info.HitLocation.helmet]) / (double)Kills); + // calculate maximum bone + double currentMaxBoneRatio = (HitLocationCount.Values.Select(v => v / (double)Kills).Max()); - var bone = HitLocationCount.FirstOrDefault(b => b.Value == HitLocationCount.Values.Max()).Key; - #region HEADSHOT_RATIO - // flag on headshot - if (currentHeadshotRatio > maxHeadshotLerpValueForFlag) - { - // ban on headshot - if (currentHeadshotRatio > maxHeadshotLerpValueForFlag) - { - AboveThresholdCount++; - Log.WriteDebug("**Maximum Headshot Ratio Reached For Ban**"); - Log.WriteDebug($"ClientId: {kill.AttackerId}"); - Log.WriteDebug($"**Kills: {Kills}"); - 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()); - Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); + var bone = HitLocationCount.FirstOrDefault(b => b.Value == HitLocationCount.Values.Max()).Key; + #region HEADSHOT_RATIO + // flag on headshot + if (currentHeadshotRatio > maxHeadshotLerpValueForFlag) + { + // ban on headshot + if (currentHeadshotRatio > maxHeadshotLerpValueForFlag) + { + AboveThresholdCount++; + Log.WriteDebug("**Maximum Headshot Ratio Reached For Ban**"); + Log.WriteDebug($"ClientId: {kill.AttackerId}"); + Log.WriteDebug($"**Kills: {Kills}"); + 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()); + Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); + return new DetectionPenaltyResult() + { + ClientPenalty = Penalty.PenaltyType.Ban, + RatioAmount = currentHeadshotRatio, + Bone = IW4Info.HitLocation.head, + KillCount = Kills + }; + } + else + { + AboveThresholdCount++; + Log.WriteDebug("**Maximum Headshot Ratio Reached For Flag**"); + Log.WriteDebug($"ClientId: {kill.AttackerId}"); + Log.WriteDebug($"**Kills: {Kills}"); + 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()); + Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); + + return new DetectionPenaltyResult() + { + ClientPenalty = Penalty.PenaltyType.Flag, + RatioAmount = currentHeadshotRatio, + Bone = IW4Info.HitLocation.head, + KillCount = Kills + }; + } + } + #endregion + + #region BONE_RATIO + // flag on bone ratio + else if (currentMaxBoneRatio > maxBoneRatioLerpValueForFlag) + { + // ban on bone ratio + if (currentMaxBoneRatio > maxBoneRatioLerpValueForBan) + { + Log.WriteDebug("**Maximum Bone Ratio Reached For Ban**"); + Log.WriteDebug($"ClientId: {kill.AttackerId}"); + Log.WriteDebug($"**Kills: {Kills}"); + 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()); + + return new DetectionPenaltyResult() + { + ClientPenalty = Penalty.PenaltyType.Ban, + RatioAmount = currentMaxBoneRatio, + Bone = bone, + KillCount = Kills + }; + } + else + { + Log.WriteDebug("**Maximum Bone Ratio Reached For Flag**"); + Log.WriteDebug($"ClientId: {kill.AttackerId}"); + Log.WriteDebug($"**Kills: {Kills}"); + 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()); + + return new DetectionPenaltyResult() + { + ClientPenalty = Penalty.PenaltyType.Flag, + RatioAmount = currentMaxBoneRatio, + Bone = bone, + KillCount = Kills + }; + } + } + #endregion + } + + #region CHEST_ABDOMEN_RATIO_SESSION + int chestKills = HitLocationCount[IW4Info.HitLocation.torso_upper]; + + if (chestKills >= Thresholds.MediumSampleMinKills) + { + double marginOfError = Thresholds.GetMarginOfError(chestKills); + double lerpAmount = Math.Min(1.0, (chestKills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills)); + // determine max acceptable ratio of chest to abdomen kills + double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(3), Thresholds.ChestAbdomenRatioThresholdHighSample(3), lerpAmount) + marginOfError; + double chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(4), Thresholds.ChestAbdomenRatioThresholdHighSample(4), lerpAmount) + marginOfError; + + double currentChestAbdomenRatio = HitLocationCount[IW4Info.HitLocation.torso_upper] / (double)HitLocationCount[IW4Info.HitLocation.torso_lower]; + + if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag) + { + + if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan && chestKills >= Thresholds.MediumSampleMinKills + 30) + { + Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Ban**"); + Log.WriteDebug($"ClientId: {kill.AttackerId}"); + Log.WriteDebug($"**Chest Kills: {chestKills}"); + 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()); + // Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); + + return new DetectionPenaltyResult() + { + ClientPenalty = Penalty.PenaltyType.Ban, + RatioAmount = currentChestAbdomenRatio, + Bone = 0, + KillCount = chestKills + }; + } + else + { + Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Flag**"); + Log.WriteDebug($"ClientId: {kill.AttackerId}"); + Log.WriteDebug($"**Chest Kills: {chestKills}"); + 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()); + // Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); + + return new DetectionPenaltyResult() + { + ClientPenalty = Penalty.PenaltyType.Flag, + RatioAmount = currentChestAbdomenRatio, + Bone = 0, + KillCount = chestKills + }; + } + } + } + #endregion + #endregion return new DetectionPenaltyResult() { - ClientPenalty = Penalty.PenaltyType.Ban, - RatioAmount = currentHeadshotRatio, - Bone = IW4Info.HitLocation.head, - KillCount = Kills + ClientPenalty = Penalty.PenaltyType.Any, + RatioAmount = 0 }; } - else + + public DetectionPenaltyResult ProcessTotalRatio(EFClientStatistics stats) { - AboveThresholdCount++; - Log.WriteDebug("**Maximum Headshot Ratio Reached For Flag**"); - Log.WriteDebug($"ClientId: {kill.AttackerId}"); - Log.WriteDebug($"**Kills: {Kills}"); - 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()); - Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); + int totalChestKills = stats.HitLocations.Single(c => c.Location == IW4Info.HitLocation.left_arm_upper).HitCount; - return new DetectionPenaltyResult() + if (totalChestKills >= 250) { - ClientPenalty = Penalty.PenaltyType.Flag, - RatioAmount = currentHeadshotRatio, - Bone = IW4Info.HitLocation.head, - KillCount = Kills - }; - } - } - #endregion - - #region BONE_RATIO - // flag on bone ratio - else if (currentMaxBoneRatio > maxBoneRatioLerpValueForFlag) - { - // ban on bone ratio - if (currentMaxBoneRatio > maxBoneRatioLerpValueForBan) - { - Log.WriteDebug("**Maximum Bone Ratio Reached For Ban**"); - Log.WriteDebug($"ClientId: {kill.AttackerId}"); - Log.WriteDebug($"**Kills: {Kills}"); - 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()); - - return new DetectionPenaltyResult() - { - ClientPenalty = Penalty.PenaltyType.Ban, - RatioAmount = currentMaxBoneRatio, - Bone = bone, - KillCount = Kills - }; - } - else - { - Log.WriteDebug("**Maximum Bone Ratio Reached For Flag**"); - Log.WriteDebug($"ClientId: {kill.AttackerId}"); - Log.WriteDebug($"**Kills: {Kills}"); - 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()); - - return new DetectionPenaltyResult() - { - ClientPenalty = Penalty.PenaltyType.Flag, - RatioAmount = currentMaxBoneRatio, - Bone = bone, - KillCount = Kills - }; - } - } - #endregion -} - -#region CHEST_ABDOMEN_RATIO_SESSION -int chestKills = HitLocationCount[IW4Info.HitLocation.torso_upper]; - -if (chestKills >= Thresholds.MediumSampleMinKills) -{ - double marginOfError = Thresholds.GetMarginOfError(chestKills); - double lerpAmount = Math.Min(1.0, (chestKills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills)); - // determine max acceptable ratio of chest to abdomen kills - double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(3), Thresholds.ChestAbdomenRatioThresholdHighSample(3), lerpAmount) + marginOfError; - double chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(4), Thresholds.ChestAbdomenRatioThresholdHighSample(4), lerpAmount) + marginOfError; - - double currentChestAbdomenRatio = HitLocationCount[IW4Info.HitLocation.torso_upper] / (double)HitLocationCount[IW4Info.HitLocation.torso_lower]; - - if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag) - { - - if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan && chestKills >= Thresholds.MediumSampleMinKills + 30) - { - Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Ban**"); - Log.WriteDebug($"ClientId: {kill.AttackerId}"); - Log.WriteDebug($"**Chest Kills: {chestKills}"); - 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()); - // Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); - - return new DetectionPenaltyResult() - { - ClientPenalty = Penalty.PenaltyType.Ban, - RatioAmount = currentChestAbdomenRatio, - Bone = 0, - KillCount = chestKills - }; - } - else - { - Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Flag**"); - Log.WriteDebug($"ClientId: {kill.AttackerId}"); - Log.WriteDebug($"**Chest Kills: {chestKills}"); - 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()); - // Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); - - return new DetectionPenaltyResult() - { - ClientPenalty = Penalty.PenaltyType.Flag, - RatioAmount = currentChestAbdomenRatio, - Bone = 0, - KillCount = chestKills - }; - } - } -} -#endregion -#endregion -return new DetectionPenaltyResult() -{ - ClientPenalty = Penalty.PenaltyType.Any, - RatioAmount = 0 -}; -} - -public DetectionPenaltyResult ProcessTotalRatio(EFClientStatistics stats) -{ -int totalChestKills = stats.HitLocations.Single(c => c.Location == IW4Info.HitLocation.left_arm_upper).HitCount; - -if (totalChestKills >= 250) -{ - double marginOfError = Thresholds.GetMarginOfError(totalChestKills); - double lerpAmount = Math.Min(1.0, (totalChestKills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills)); - // determine max acceptable ratio of chest to abdomen kills - double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(2.25), Thresholds.ChestAbdomenRatioThresholdHighSample(2.25), lerpAmount) + marginOfError; - double chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(3.0), Thresholds.ChestAbdomenRatioThresholdHighSample(3.0), lerpAmount) + marginOfError; + double marginOfError = Thresholds.GetMarginOfError(totalChestKills); + double lerpAmount = Math.Min(1.0, (totalChestKills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills)); + // determine max acceptable ratio of chest to abdomen kills + double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(2.25), Thresholds.ChestAbdomenRatioThresholdHighSample(2.25), lerpAmount) + marginOfError; + double chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(3.0), Thresholds.ChestAbdomenRatioThresholdHighSample(3.0), lerpAmount) + marginOfError; double currentChestAbdomenRatio = stats.HitLocations.Single(hl => hl.Location == IW4Info.HitLocation.torso_upper).HitCount / stats.HitLocations.Single(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount; - if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag) - { + 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 Kills: {totalChestKills}"); - 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()); - // Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); + if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan) + { + Log.WriteDebug("**Maximum Lifetime Chest/Abdomen Ratio Reached For Ban**"); + Log.WriteDebug($"ClientId: {stats.ClientId}"); + Log.WriteDebug($"**Total Chest Kills: {totalChestKills}"); + 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()); + // Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); + + return new DetectionPenaltyResult() + { + ClientPenalty = Penalty.PenaltyType.Ban, + RatioAmount = currentChestAbdomenRatio, + Bone = IW4Info.HitLocation.torso_upper, + KillCount = totalChestKills + }; + } + else + { + Log.WriteDebug("**Maximum Lifetime Chest/Abdomen Ratio Reached For Flag**"); + Log.WriteDebug($"ClientId: {stats.ClientId}"); + Log.WriteDebug($"**Total Chest Kills: {totalChestKills}"); + 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()); + // Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); + + return new DetectionPenaltyResult() + { + ClientPenalty = Penalty.PenaltyType.Flag, + RatioAmount = currentChestAbdomenRatio, + Bone = IW4Info.HitLocation.torso_upper, + KillCount = totalChestKills + }; + } + } + } return new DetectionPenaltyResult() { - ClientPenalty = Penalty.PenaltyType.Ban, - RatioAmount = currentChestAbdomenRatio, - Bone = IW4Info.HitLocation.torso_upper, - KillCount = totalChestKills - }; - } - else - { - Log.WriteDebug("**Maximum Lifetime Chest/Abdomen Ratio Reached For Flag**"); - Log.WriteDebug($"ClientId: {stats.ClientId}"); - Log.WriteDebug($"**Total Chest Kills: {totalChestKills}"); - 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()); - // Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); - - return new DetectionPenaltyResult() - { - ClientPenalty = Penalty.PenaltyType.Flag, - RatioAmount = currentChestAbdomenRatio, - Bone = IW4Info.HitLocation.torso_upper, - KillCount = totalChestKills + Bone = IW4Info.HitLocation.none, + ClientPenalty = Penalty.PenaltyType.Any }; } } } - -return new DetectionPenaltyResult() -{ - Bone = IW4Info.HitLocation.none, - ClientPenalty = Penalty.PenaltyType.Any -}; -} -} -} diff --git a/Plugins/SimpleStats/Helpers/StatManager.cs b/Plugins/SimpleStats/Helpers/StatManager.cs index 0ef8070f..25e0ec6a 100644 --- a/Plugins/SimpleStats/Helpers/StatManager.cs +++ b/Plugins/SimpleStats/Helpers/StatManager.cs @@ -380,7 +380,7 @@ namespace StatsPlugin.Helpers double timeSinceLastActive = (DateTime.UtcNow - clientStats.LastActive).TotalSeconds / 60.0; // prevent NaN or inactive time lowering SPM - if (timeSinceLastCalc == 0 || timeSinceLastActive > 3) + if (timeSinceLastCalc == 0 || timeSinceLastActive > 3 || clientStats.SPM < 1) return clientStats; // calculate the players Score Per Minute for the current session @@ -403,6 +403,9 @@ namespace StatsPlugin.Helpers // calculate the new weight against average times the weight against play time clientStats.SPM = (killSPM * SPMAgainstPlayWeight) + (clientStats.SPM * (1 - SPMAgainstPlayWeight)); + // fixme: how does this happen? + if (clientStats.SPM == double.NaN) + clientStats.SPM = 0; clientStats.SPM = Math.Round(clientStats.SPM, 3); clientStats.Skill = Math.Round((clientStats.SPM * KDRWeight), 3); diff --git a/Plugins/SimpleStats/Plugin.cs b/Plugins/SimpleStats/Plugin.cs index 05d6b2f8..270262ba 100644 --- a/Plugins/SimpleStats/Plugin.cs +++ b/Plugins/SimpleStats/Plugin.cs @@ -105,6 +105,41 @@ namespace StatsPlugin double skill = Math.Round(clientStats.Sum(c => c.Skill) / clientStats.Count, 2); double spm = Math.Round(clientStats.Sum(c => c.SPM), 1); + return new List() + { + new ProfileMeta() + { + Key = "Kills", + Value = kills + }, + new ProfileMeta() + { + Key = "Deaths", + Value = deaths + }, + new ProfileMeta() + { + Key = "KDR", + Value = kdr + }, + new ProfileMeta() + { + Key = "Skill", + Value = skill + }, + new ProfileMeta() + { + Key = "Score Per Minute", + Value = spm + } + }; + } + + async Task> getAnticheatInfo(int clientId) + { + var statsSvc = new GenericRepository(); + var clientStats = await statsSvc.FindAsync(c => c.ClientId == clientId); + double headRatio = 0; double chestRatio = 0; double abdomenRatio = 0; @@ -134,61 +169,36 @@ namespace StatsPlugin return new List() { - new ProfileMeta() - { - Key = "Kills", - Value = kills - }, - new ProfileMeta() - { - Key = "Deaths", - Value = deaths - }, - new ProfileMeta() - { - Key = "KDR", - Value = kdr - }, - new ProfileMeta() - { - Key = "Skill", - Value = skill - }, - new ProfileMeta() - { - Key = "Score Per Minute", - Value = spm - }, - new ProfileMeta() - { - Key = "Chest Ratio", - Value = chestRatio, - Sensitive = true - }, - new ProfileMeta() - { - Key = "Abdomen Ratio", - Value = abdomenRatio, - Sensitive = true - }, - new ProfileMeta() - { - Key = "Chest To Abdomen Ratio", - Value = chestAbdomenRatio, - Sensitive = true - }, - new ProfileMeta() - { - Key = "Headshot Ratio", - Value = headRatio, - Sensitive = true - }, - new ProfileMeta() - { - Key = "Hit Offset Average", - Value = $"{Math.Round(((float)hitOffsetAverage).ToDegrees(), 4)}°", - Sensitive = true - } + new ProfileMeta() + { + Key = "Chest Ratio", + Value = chestRatio, + Sensitive = true + }, + new ProfileMeta() + { + Key = "Abdomen Ratio", + Value = abdomenRatio, + Sensitive = true + }, + new ProfileMeta() + { + Key = "Chest To Abdomen Ratio", + Value = chestAbdomenRatio, + Sensitive = true + }, + new ProfileMeta() + { + Key = "Headshot Ratio", + Value = headRatio, + Sensitive = true + }, + new ProfileMeta() + { + Key = "Hit Offset Average", + Value = $"{Math.Round(((float)hitOffsetAverage).ToDegrees(), 4)}°", + Sensitive = true + } }; } @@ -211,10 +221,13 @@ namespace StatsPlugin return messageMeta; } + MetaService.AddMeta(getStats); + if (Config.Configuration().EnableAntiCheat) { - MetaService.AddMeta(getStats); + MetaService.AddMeta(getAnticheatInfo); } + MetaService.AddMeta(getMessages); // todo: is this fast? make async? @@ -240,10 +253,7 @@ namespace StatsPlugin Manager = new StatManager(manager); } - public async Task OnTickAsync(Server S) - { - - } + public Task OnTickAsync(Server S) => Utilities.CompletedTask; public async Task OnUnloadAsync() { diff --git a/Plugins/Welcome/Plugin.cs b/Plugins/Welcome/Plugin.cs index fc685e66..3debc33d 100644 --- a/Plugins/Welcome/Plugin.cs +++ b/Plugins/Welcome/Plugin.cs @@ -75,13 +75,9 @@ namespace Welcome_Plugin } } - public async Task OnUnloadAsync() - { - } + public Task OnUnloadAsync() => Utilities.CompletedTask; - public async Task OnTickAsync(Server S) - { - } + public Task OnTickAsync(Server S) => Utilities.CompletedTask; public async Task OnEventAsync(Event E, Server S) { diff --git a/SharedLibrary/Commands/NativeCommands.cs b/SharedLibrary/Commands/NativeCommands.cs index 5183a104..b1a32569 100644 --- a/SharedLibrary/Commands/NativeCommands.cs +++ b/SharedLibrary/Commands/NativeCommands.cs @@ -457,6 +457,16 @@ namespace SharedLibrary.Commands await E.Owner.Manager.GetClientService().Update(E.Target); } + try + { + E.Owner.Manager.GetPrivilegedClients().Add(E.Target.ClientId, E.Target); + } + + catch (Exception) + { + E.Owner.Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target; + } + await E.Origin.Tell($"{E.Target.Name} was successfully promoted"); } @@ -989,12 +999,22 @@ namespace SharedLibrary.Commands public override async Task ExecuteAsync(Event E) { + if (E.Data.Length < 5) + { + await E.Origin.Tell("Your password must be atleast 5 characters long"); + return; + } + string[] hashedPassword = Helpers.Hashing.Hash(E.Data); E.Origin.Password = hashedPassword[0]; E.Origin.PasswordSalt = hashedPassword[1]; + // update the password for the client in privileged + E.Owner.Manager.GetPrivilegedClients()[E.Origin.ClientId] = E.Origin; + await E.Owner.Manager.GetClientService().Update(E.Origin); + await E.Origin.Tell("Your password has been set successfully"); } } diff --git a/SharedLibrary/Database/DatabaseContext.cs b/SharedLibrary/Database/DatabaseContext.cs index e5a1835f..cbe8403d 100644 --- a/SharedLibrary/Database/DatabaseContext.cs +++ b/SharedLibrary/Database/DatabaseContext.cs @@ -56,7 +56,18 @@ namespace SharedLibrary.Database #if !DEBUG foreach (string dllPath in System.IO.Directory.GetFiles($"{Utilities.OperatingDirectory}Plugins")) #else - foreach (string dllPath in System.IO.Directory.GetFiles(/*C:\Projects\IW4M - Admin\WebfrontCore */ $@"{Environment.CurrentDirectory}\bin\x86\Debug\Plugins").Where(f => f.Contains(".dll"))) + IEnumerable directoryFiles; + try + { + directoryFiles = Directory.GetFiles($@"{Environment.CurrentDirectory}\bin\x86\Debug\Plugins").Where(f => f.Contains(".dll")); + } + + catch(Exception) + { + directoryFiles = Directory.GetFiles($@"{Environment.CurrentDirectory}\Plugins").Where(f => f.Contains(".dll")); + } + + foreach (string dllPath in directoryFiles) #endif { Assembly library; diff --git a/SharedLibrary/Database/Models/EFClient.cs b/SharedLibrary/Database/Models/EFClient.cs index 52741d9a..726ef086 100644 --- a/SharedLibrary/Database/Models/EFClient.cs +++ b/SharedLibrary/Database/Models/EFClient.cs @@ -2,9 +2,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SharedLibrary.Database.Models { diff --git a/SharedLibrary/Dtos/ServerInfo.cs b/SharedLibrary/Dtos/ServerInfo.cs index 00798cbb..91ed259e 100644 --- a/SharedLibrary/Dtos/ServerInfo.cs +++ b/SharedLibrary/Dtos/ServerInfo.cs @@ -18,5 +18,6 @@ namespace SharedLibrary.Dtos public List Players { get; set; } public Helpers.PlayerHistory[] PlayerHistory { get; set; } public int ID { get; set; } + public bool Online { get; set; } } } diff --git a/SharedLibrary/Interfaces/IManager.cs b/SharedLibrary/Interfaces/IManager.cs index bffcd40a..785f9a6b 100644 --- a/SharedLibrary/Interfaces/IManager.cs +++ b/SharedLibrary/Interfaces/IManager.cs @@ -22,5 +22,6 @@ namespace SharedLibrary.Interfaces ClientService GetClientService(); AliasService GetAliasService(); PenaltyService GetPenaltyService(); + IDictionary GetPrivilegedClients(); } } diff --git a/SharedLibrary/RCon/StaticHelpers.cs b/SharedLibrary/RCon/StaticHelpers.cs index ac2759e6..3e9edf5a 100644 --- a/SharedLibrary/RCon/StaticHelpers.cs +++ b/SharedLibrary/RCon/StaticHelpers.cs @@ -19,6 +19,6 @@ namespace SharedLibrary.RCon } public static char SeperatorChar = (char)int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier); - public static readonly TimeSpan SocketTimeout = new TimeSpan(0, 0, 1); + public static readonly TimeSpan SocketTimeout = new TimeSpan(0, 0, 10); } } diff --git a/SharedLibrary/Server.cs b/SharedLibrary/Server.cs index 0bd28bc9..05c4ff6a 100644 --- a/SharedLibrary/Server.cs +++ b/SharedLibrary/Server.cs @@ -142,6 +142,7 @@ namespace SharedLibrary await this.ExecuteCommandAsync($"{sayCommand} {(CustomSayEnabled ? CustomSayName : "")} {Message}"); #else Logger.WriteVerbose(Message.StripColors()); + await Utilities.CompletedTask; #endif } @@ -159,6 +160,7 @@ namespace SharedLibrary await this.ExecuteCommandAsync($"{tellCommand} {Target.ClientNumber} {(CustomSayEnabled ? CustomSayName : "")} {Message}^7"); #else Logger.WriteVerbose($"{Target.ClientNumber}->{Message.StripColors()}"); + await Utilities.CompletedTask; #endif if (Target.Level == Player.Permission.Console) diff --git a/SharedLibrary/Services/AliasService.cs b/SharedLibrary/Services/AliasService.cs index 979bb1ef..3b7c2330 100644 --- a/SharedLibrary/Services/AliasService.cs +++ b/SharedLibrary/Services/AliasService.cs @@ -16,8 +16,8 @@ namespace SharedLibrary.Services { public async Task Create(EFAlias entity) { - throw new Exception(); - using (var context = new DatabaseContext()) + throw await Task.FromResult(new Exception()); + /*using (var context = new DatabaseContext()) { var alias = new EFAlias() { @@ -32,7 +32,7 @@ namespace SharedLibrary.Services context.Aliases.Add(entity); await context.SaveChangesAsync(); return entity; - } + }*/ } public Task CreateProxy() @@ -80,14 +80,14 @@ namespace SharedLibrary.Services public async Task Update(EFAlias entity) { - throw new Exception(); - using (var context = new DatabaseContext()) + throw await Task.FromResult(new Exception()); + /*using (var context = new DatabaseContext()) { entity = context.Aliases.Attach(entity); context.Entry(entity).State = EntityState.Modified; await context.SaveChangesAsync(); return entity; - } + }*/ } public async Task CreateLink(EFAliasLink link) diff --git a/SharedLibrary/Services/PenaltyService.cs b/SharedLibrary/Services/PenaltyService.cs index 08b04c00..77d4686b 100644 --- a/SharedLibrary/Services/PenaltyService.cs +++ b/SharedLibrary/Services/PenaltyService.cs @@ -59,6 +59,8 @@ namespace SharedLibrary.Services public async Task> Find(Func expression) { + throw await Task.FromResult(new Exception()); + /* return await Task.FromResult(new List()); // fixme: this is so slow! return await Task.Run(() => @@ -70,7 +72,7 @@ namespace SharedLibrary.Services .Where(expression) .Where(p => p.Active) .ToList(); - }); + });*/ } public Task Get(int entityID) diff --git a/SharedLibrary/Utilities.cs b/SharedLibrary/Utilities.cs index b02c1ace..14e70530 100644 --- a/SharedLibrary/Utilities.cs +++ b/SharedLibrary/Utilities.cs @@ -20,6 +20,7 @@ namespace SharedLibrary public static class Utilities { public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar; + public static readonly Task CompletedTask = Task.FromResult(false); //Get string with specified number of spaces -- really only for visual output public static String GetSpaces(int Num) @@ -52,7 +53,7 @@ namespace SharedLibrary return newStr; } - public static List PlayersFromStatus(String[] Status) + public static List PlayersFromStatus(string[] Status) { List StatusPlayers = new List(); diff --git a/WebfrontCore/Application/Logger.cs b/WebfrontCore/Application/Logger.cs index 48fed3e2..358fa8e7 100644 --- a/WebfrontCore/Application/Logger.cs +++ b/WebfrontCore/Application/Logger.cs @@ -40,7 +40,7 @@ namespace IW4MAdmin if (type == LogType.Error || type == LogType.Verbose) Console.WriteLine(LogLine); //if (type != LogType.Debug) - File.AppendAllText(FileName, LogLine + Environment.NewLine); + File.AppendAllText(FileName, $"{LogLine}{Environment.NewLine}"); #endif } } diff --git a/WebfrontCore/Application/Manager.cs b/WebfrontCore/Application/Manager.cs index 1a069b9d..3b9c2863 100644 --- a/WebfrontCore/Application/Manager.cs +++ b/WebfrontCore/Application/Manager.cs @@ -57,8 +57,15 @@ namespace IW4MAdmin PrivilegedClients = new Dictionary(); ServerEventOccurred += EventAPI.OnServerEventOccurred; ConfigHandler = new BaseConfigurationHandler("IW4MAdminSettings"); + Console.CancelKeyPress += new ConsoleCancelEventHandler(OnCancelKey); } + private void OnCancelKey(object sender, ConsoleCancelEventArgs args) + { + Stop(); + } + + public IList GetServers() { return Servers; @@ -305,5 +312,7 @@ namespace IW4MAdmin public PenaltyService GetPenaltyService() => PenaltySvc; public IConfigurationHandler GetApplicationSettings() => ConfigHandler; + + public IDictionary GetPrivilegedClients() => PrivilegedClients; } } diff --git a/WebfrontCore/Application/Server.cs b/WebfrontCore/Application/Server.cs index d8fe6b75..8d1f17b5 100644 --- a/WebfrontCore/Application/Server.cs +++ b/WebfrontCore/Application/Server.cs @@ -788,7 +788,7 @@ namespace IW4MAdmin CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname }; // todo: make this more efficient - ((ApplicationManager)(Manager)).PrivilegedClients = new Dictionary(); + /*((ApplicationManager)(Manager)).PrivilegedClients = new Dictionary(); var ClientSvc = new ClientService(); var ipList = (await ClientSvc.Find(c => c.Level > Player.Permission.Trusted)) .Select(c => new @@ -818,7 +818,7 @@ namespace IW4MAdmin { continue; } - } + }*/ } if (E.Type == Event.GType.MapEnd) diff --git a/WebfrontCore/Controllers/AccountController.cs b/WebfrontCore/Controllers/AccountController.cs index f10bb722..7921510a 100644 --- a/WebfrontCore/Controllers/AccountController.cs +++ b/WebfrontCore/Controllers/AccountController.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication.Cookies; using System.Security.Claims; +using System; namespace WebfrontCore.Controllers { @@ -15,23 +16,37 @@ namespace WebfrontCore.Controllers return Unauthorized(); } - var client = IW4MAdmin.Program.ServerManager.PrivilegedClients[userId]; - string[] hashedPassword = await Task.FromResult(SharedLibrary.Helpers.Hashing.Hash(password, client.PasswordSalt)); - - if (hashedPassword[0] == client.Password) + try { - var claims = new[] + var client = IW4MAdmin.Program.ServerManager.PrivilegedClients[userId]; + string[] hashedPassword = await Task.FromResult(SharedLibrary.Helpers.Hashing.Hash(password, client.PasswordSalt)); + + if (hashedPassword[0] == client.Password) { + var claims = new[] + { new Claim(ClaimTypes.NameIdentifier, client.Name), new Claim(ClaimTypes.Role, client.Level.ToString()), new Claim(ClaimTypes.Sid, client.ClientId.ToString()) }; - var claimsIdentity = new ClaimsIdentity(claims, "login"); - var claimsPrinciple = new ClaimsPrincipal(claimsIdentity); - await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrinciple); + var claimsIdentity = new ClaimsIdentity(claims, "login"); + var claimsPrinciple = new ClaimsPrincipal(claimsIdentity); + await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrinciple, new Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties() + { + AllowRefresh = true, + ExpiresUtc = DateTime.UtcNow.AddDays(30), + IsPersistent = true, + IssuedUtc = DateTime.UtcNow + }); - return Ok(); + return Ok(); + } + } + + catch (Exception) + { + return Unauthorized(); } return Unauthorized(); diff --git a/WebfrontCore/Controllers/ActionController.cs b/WebfrontCore/Controllers/ActionController.cs index ba39b850..286c23a9 100644 --- a/WebfrontCore/Controllers/ActionController.cs +++ b/WebfrontCore/Controllers/ActionController.cs @@ -82,7 +82,7 @@ namespace WebfrontCore.Controllers { new InputInfo() { - Name = "UserID" + Name = "User ID" }, new InputInfo() { diff --git a/WebfrontCore/Controllers/ConsoleController.cs b/WebfrontCore/Controllers/ConsoleController.cs index c727916a..c2171399 100644 --- a/WebfrontCore/Controllers/ConsoleController.cs +++ b/WebfrontCore/Controllers/ConsoleController.cs @@ -30,8 +30,12 @@ namespace WebfrontCore.Controllers { var server = Manager.Servers.First(s => s.GetHashCode() == serverId); - var client = User.AsPlayer(); - client.CurrentServer = server; + var client = new Player() + { + ClientId = User.ClientId, + Level = User.Level, + CurrentServer = server + }; var remoteEvent = new Event(Event.GType.Say, command, client, null, server); diff --git a/WebfrontCore/Controllers/ServerController.cs b/WebfrontCore/Controllers/ServerController.cs index caad8ab9..727e533f 100644 --- a/WebfrontCore/Controllers/ServerController.cs +++ b/WebfrontCore/Controllers/ServerController.cs @@ -35,7 +35,7 @@ namespace WebfrontCore.Controllers LevelInt = (int)p.Level }).ToList(), ChatHistory = s.ChatHistory.OrderBy(c => c.Time).Take((int)Math.Ceiling(s.ClientNum / 2.0)).ToArray(), - PlayerHistory = s.PlayerHistory.ToArray() + PlayerHistory = s.PlayerHistory.ToArray(), }; return PartialView("_ClientActivity", serverInfo); } diff --git a/WebfrontCore/Startup.cs b/WebfrontCore/Startup.cs index e2907dba..2ac451e5 100644 --- a/WebfrontCore/Startup.cs +++ b/WebfrontCore/Startup.cs @@ -55,7 +55,8 @@ namespace WebfrontCore AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme, AutomaticAuthenticate = true, AutomaticChallenge = true, - LoginPath = "/Account/Login/" + LoginPath = "/Account/Login/", + ExpireTimeSpan = TimeSpan.FromDays(30), }); app.UseMvc(routes => @@ -65,7 +66,6 @@ namespace WebfrontCore template: "{controller=Home}/{action=Index}/{id?}"); }); - //app.UseBasicAuthentication(Authentication.Basic.Generate()); } } } diff --git a/WebfrontCore/ViewComponents/ServerListViewComponent.cs b/WebfrontCore/ViewComponents/ServerListViewComponent.cs index 41f80ecc..e14e5d30 100644 --- a/WebfrontCore/ViewComponents/ServerListViewComponent.cs +++ b/WebfrontCore/ViewComponents/ServerListViewComponent.cs @@ -30,7 +30,8 @@ namespace WebfrontCore.ViewComponents Level = p.Level.ToString(), LevelInt = (int)p.Level }).ToList(), - ChatHistory = s.ChatHistory.ToArray() + ChatHistory = s.ChatHistory.ToArray(), + Online = !s.Throttled }).ToList(); return View("_List", serverInfo); } diff --git a/WebfrontCore/Views/Server/_Server.cshtml b/WebfrontCore/Views/Server/_Server.cshtml index 7a599c0c..0d0e373a 100644 --- a/WebfrontCore/Views/Server/_Server.cshtml +++ b/WebfrontCore/Views/Server/_Server.cshtml @@ -17,5 +17,5 @@
-
+
diff --git a/WebfrontCore/Views/Shared/_Layout.cshtml b/WebfrontCore/Views/Shared/_Layout.cshtml index 2a56968f..ca0a40a9 100644 --- a/WebfrontCore/Views/Shared/_Layout.cshtml +++ b/WebfrontCore/Views/Shared/_Layout.cshtml @@ -44,7 +44,6 @@ } else { - } @@ -82,6 +81,8 @@