diff --git a/Plugins/SimpleStats/Cheat/Detection.cs b/Plugins/SimpleStats/Cheat/Detection.cs index 5ef06890..7fec01d4 100644 --- a/Plugins/SimpleStats/Cheat/Detection.cs +++ b/Plugins/SimpleStats/Cheat/Detection.cs @@ -15,6 +15,8 @@ namespace StatsPlugin.Cheat int Kills; int AboveThresholdCount; double AverageKillTime; + double AverageHitOffset; + int avgcnt; Dictionary HitLocationCount; DateTime LastKill; ILogger Log; @@ -51,271 +53,283 @@ namespace StatsPlugin.Cheat #region VIEWANGLES double distance = Vector3.Distance(kill.KillOrigin, kill.DeathOrigin); - double x = kill.KillOrigin.X + distance * Math.Cos(kill.ViewAngles.Y.ToRadians()) * Math.Cos(kill.ViewAngles.X.ToRadians()); - double y = kill.KillOrigin.Y + (distance * Math.Sin((360.0f - kill.ViewAngles.Y).ToRadians())); - double z = kill.KillOrigin.Z + (distance * Math.Cos(kill.ViewAngles.Y.ToRadians()) * Math.Sin((360.0f - kill.ViewAngles.X).ToRadians())); + double x = kill.KillOrigin.X + distance * Math.Cos(kill.ViewAngles.X.ToRadians()) * Math.Cos(kill.ViewAngles.Y.ToRadians()); + double y = kill.KillOrigin.Y + (distance * Math.Sin(kill.ViewAngles.X.ToRadians()) * Math.Cos(kill.ViewAngles.Y.ToRadians())); + double z = kill.KillOrigin.Z + distance * Math.Sin((360.0f - kill.ViewAngles.Y).ToRadians()); var trueVector = Vector3.Subtract(kill.KillOrigin, kill.DeathOrigin); var calculatedVector = Vector3.Subtract(kill.KillOrigin, new Vector3((float)x, (float)y, (float)z)); double angle = trueVector.AngleBetween(calculatedVector); - // Console.WriteLine(((float)angle).ToDegrees()); - #endregion - - #region SESSION_RATIOS - if (Kills >= Thresholds.LowSampleMinKills) + if (kill.AdsPercent > 0.5) { - 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()); - - 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 + Log.WriteInfo($"{((float)angle).ToDegrees()}"); + AverageHitOffset += angle; + avgcnt++; + double avg = AverageHitOffset / (float)avgcnt; } - #region CHEST_ABDOMEN_RATIO_SESSION - int chestKills = HitLocationCount[IW4Info.HitLocation.torso_upper]; +/*r = distance, +x = playerX + r*cos(yaw)*cos(pitch), +y = playerY + r*sin(yaw)*cos(pitch) +z = playerZ + r*sin(360-pitch)*/ - 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 + +#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()); + + 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.Any, - RatioAmount = 0 + ClientPenalty = Penalty.PenaltyType.Ban, + RatioAmount = currentHeadshotRatio, + Bone = IW4Info.HitLocation.head, + KillCount = Kills }; } - - public DetectionPenaltyResult ProcessTotalRatio(EFClientStatistics stats) + else { - 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 currentChestAbdomenRatio = HitLocationCount[IW4Info.HitLocation.torso_upper] / (double)HitLocationCount[IW4Info.HitLocation.torso_lower]; - - 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 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 = 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 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 = IW4Info.HitLocation.torso_upper, - KillCount = totalChestKills - }; - } - } - } + 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() { - Bone = IW4Info.HitLocation.none, - ClientPenalty = Penalty.PenaltyType.Any + 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 currentChestAbdomenRatio = HitLocationCount[IW4Info.HitLocation.torso_upper] / (double)HitLocationCount[IW4Info.HitLocation.torso_lower]; + + 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 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 = 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 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 = IW4Info.HitLocation.torso_upper, + KillCount = totalChestKills + }; + } + } +} + +return new DetectionPenaltyResult() +{ + Bone = IW4Info.HitLocation.none, + ClientPenalty = Penalty.PenaltyType.Any +}; +} +} +} diff --git a/Plugins/SimpleStats/Helpers/Extensions.cs b/Plugins/SimpleStats/Helpers/Extensions.cs index ef46f109..227e074b 100644 --- a/Plugins/SimpleStats/Helpers/Extensions.cs +++ b/Plugins/SimpleStats/Helpers/Extensions.cs @@ -12,11 +12,11 @@ namespace StatsPlugin.Helpers public static Vector3 FixIW4Angles(this Vector3 vector) { - float X = vector.X > 0 ? 360.0f - vector.X : Math.Abs(vector.X); - float Y = vector.Y > 0 ? 360.0f - vector.Y : Math.Abs(vector.Y); - float Z = vector.Z > 0 ? 360.0f - vector.Z : Math.Abs(vector.Z); + float X = vector.X >= 0 ? vector.X : 360.0f + vector.X; + float Y = vector.Y >= 0 ? vector.Y : 360.0f + vector.Y; + float Z = vector.Z >= 0 ? vector.Z : 360.0f + vector.Z; - return new Vector3(X, Y, Z); + return new Vector3(Y, X, Z); } public static float ToRadians(this float value) => (float)Math.PI * value / 180.0f; diff --git a/Plugins/SimpleStats/Helpers/StatManager.cs b/Plugins/SimpleStats/Helpers/StatManager.cs index 6a68a24f..b7b8bceb 100644 --- a/Plugins/SimpleStats/Helpers/StatManager.cs +++ b/Plugins/SimpleStats/Helpers/StatManager.cs @@ -205,7 +205,7 @@ namespace StatsPlugin.Helpers /// /// public async Task AddScriptKill(Player attacker, Player victim, int serverId, string map, string hitLoc, string type, - string damage, string weapon, string killOrigin, string deathOrigin, string viewAngles, string offset) + string damage, string weapon, string killOrigin, string deathOrigin, string viewAngles, string offset, string isKillstreakKill, string Ads) { var statsSvc = ContextThreads[serverId]; @@ -224,7 +224,9 @@ namespace StatsPlugin.Helpers Weapon = ParseEnum.Get(weapon, typeof(IW4Info.WeaponName)), ViewAngles = Vector3.Parse(viewAngles).FixIW4Angles(), TimeOffset = Int64.Parse(offset), - When = DateTime.UtcNow + When = DateTime.UtcNow, + IsKillstreakKill = isKillstreakKill[0] != '0', + AdsPercent = float.Parse(Ads) }; if (kill.DeathType == IW4Info.MeansOfDeath.MOD_SUICIDE && @@ -236,6 +238,11 @@ namespace StatsPlugin.Helpers await AddStandardKill(attacker, victim); + if (kill.IsKillstreakKill) + { + return; + } + var playerDetection = Servers[serverId].PlayerDetections[attacker.ClientId]; var playerStats = Servers[serverId].PlayerStats[attacker.ClientId]; diff --git a/Plugins/SimpleStats/Models/EFClientKill.cs b/Plugins/SimpleStats/Models/EFClientKill.cs index 948c5a16..316ec623 100644 --- a/Plugins/SimpleStats/Models/EFClientKill.cs +++ b/Plugins/SimpleStats/Models/EFClientKill.cs @@ -32,13 +32,17 @@ namespace StatsPlugin.Models public IW4Info.WeaponName Weapon { get; set; } public Vector3 KillOrigin { get; set; } public Vector3 DeathOrigin { get; set; } + public Vector3 ViewAngles { get; set; } + public DateTime When { get; set; } // http://wiki.modsrepository.com/index.php?title=Call_of_Duty_5:_Gameplay_standards for conversion to meters [NotMapped] public double Distance => Vector3.Distance(KillOrigin, DeathOrigin) * 0.0254; public IW4Info.MapName Map { get; set; } [NotMapped] public long TimeOffset { get; set; } - public Vector3 ViewAngles { get; set; } - public DateTime When { get; set; } + [NotMapped] + public bool IsKillstreakKill { get; set; } + [NotMapped] + public float AdsPercent { get; set; } } } diff --git a/Plugins/SimpleStats/Plugin.cs b/Plugins/SimpleStats/Plugin.cs index bea22473..965d1237 100644 --- a/Plugins/SimpleStats/Plugin.cs +++ b/Plugins/SimpleStats/Plugin.cs @@ -75,7 +75,7 @@ namespace StatsPlugin string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0]; if (killInfo.Length >= 9 && killInfo[0].Contains("ScriptKill") && E.Owner.CustomCallback) await Manager.AddScriptKill(E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8], - killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10]); + killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12]); else if (!E.Owner.CustomCallback) await Manager.AddStandardKill(E.Origin, E.Target); break; diff --git a/SharedLibrary/Helpers/Vector3.cs b/SharedLibrary/Helpers/Vector3.cs index b51c12bd..d1530746 100644 --- a/SharedLibrary/Helpers/Vector3.cs +++ b/SharedLibrary/Helpers/Vector3.cs @@ -38,7 +38,7 @@ namespace SharedLibrary.Helpers public static double Distance(Vector3 a, Vector3 b) { - return Math.Round(Math.Sqrt(Math.Pow(b.X - a.X, 2) + Math.Pow(b.Y - a.Y, 2) + Math.Pow(b.Z - a.Z, 2)), 2); + return Math.Sqrt(Math.Pow(b.X - a.X, 2) + Math.Pow(b.Y - a.Y, 2) + Math.Pow(b.Z - a.Z, 2)); } public static Vector3 Subtract(Vector3 a, Vector3 b) => new Vector3(b.X - a.X, b.Y - a.Y, b.Z - a.Z); diff --git a/SharedLibrary/Server.cs b/SharedLibrary/Server.cs index 581dca47..7869474f 100644 --- a/SharedLibrary/Server.cs +++ b/SharedLibrary/Server.cs @@ -246,7 +246,9 @@ namespace SharedLibrary protected void InitializeMaps() { Maps = new List(); - Maps.AddRange(Manager.GetApplicationSettings().Configuration().Maps.First(m => m.Game == GameName).Maps); + var gameMaps = Manager.GetApplicationSettings().Configuration().Maps.FirstOrDefault(m => m.Game == GameName); + if (gameMaps != null) + Maps.AddRange(gameMaps.Maps); } /// diff --git a/WebfrontCore/Application/Server.cs b/WebfrontCore/Application/Server.cs index 602870d0..da9e98a0 100644 --- a/WebfrontCore/Application/Server.cs +++ b/WebfrontCore/Application/Server.cs @@ -46,6 +46,7 @@ namespace IW4MAdmin return true; } +#if !DEBUG if (polledPlayer.Name.Length < 3) { Logger.WriteDebug($"Kicking {polledPlayer} because their name is too short"); @@ -76,6 +77,7 @@ namespace IW4MAdmin return false; } +#endif Logger.WriteDebug($"Client slot #{polledPlayer.ClientNumber} now reserved"); try @@ -656,7 +658,7 @@ namespace IW4MAdmin LogFile = new IFile(logPath); //#else } - // LogFile = new RemoteFile("https://raidmax.org/IW4MAdmin/getlog.php"); + LogFile = new RemoteFile("https://raidmax.org/IW4MAdmin/getlog.php"); //#endif Logger.WriteInfo($"Log file is {logPath}"); #if !DEBUG diff --git a/WebfrontCore/Controllers/BaseController.cs b/WebfrontCore/Controllers/BaseController.cs index 5c5f7413..57a5e27b 100644 --- a/WebfrontCore/Controllers/BaseController.cs +++ b/WebfrontCore/Controllers/BaseController.cs @@ -23,7 +23,10 @@ namespace WebfrontCore.Controllers ViewBag.Authorized = Authorized; ViewBag.Url = Startup.Configuration["Web:Address"]; string inviteLink = Manager.GetApplicationSettings().Configuration().DiscordInviteCode; - ViewBag.DiscordLink = inviteLink != null && inviteLink.Contains("http") ? inviteLink : $"https://discordapp.com/invite/{inviteLink}"; + if (inviteLink != null) + ViewBag.DiscordLink = inviteLink.Contains("https") ? inviteLink : $"https://discordapp.com/invite/{inviteLink}"; + else + ViewBag.DiscorLink = ""; base.OnActionExecuting(context); } } diff --git a/WebfrontCore/Controllers/PenaltyController.cs b/WebfrontCore/Controllers/PenaltyController.cs index 8a72cf3a..c3836b12 100644 --- a/WebfrontCore/Controllers/PenaltyController.cs +++ b/WebfrontCore/Controllers/PenaltyController.cs @@ -24,7 +24,7 @@ namespace WebfrontCore.Controllers public async Task ListAsync(int offset = 0) { - return View("_List", offset); + return await Task.FromResult(View("_List", offset)); } public async Task PublicAsync() diff --git a/WebfrontCore/Views/Client/Profile/Index.cshtml b/WebfrontCore/Views/Client/Profile/Index.cshtml index d61de3dd..e4da0021 100644 --- a/WebfrontCore/Views/Client/Profile/Index.cshtml +++ b/WebfrontCore/Views/Client/Profile/Index.cshtml @@ -20,6 +20,22 @@ } + @{ + if (ViewBag.Authorized) + { + if (Model.Level == SharedLibrary.Objects.Player.Permission.User.ToString()) + { + + + } + + if (Model.Level == SharedLibrary.Objects.Player.Permission.Banned.ToString()) + { + + } + } + } +
diff --git a/WebfrontCore/Views/Shared/Error.cshtml b/WebfrontCore/Views/Shared/Error.cshtml index 48524426..29656106 100644 --- a/WebfrontCore/Views/Shared/Error.cshtml +++ b/WebfrontCore/Views/Shared/Error.cshtml @@ -2,5 +2,5 @@ ViewData["Title"] = "Error"; } -

Error.

-

An error occurred while processing your request.

+

Sorry!

+

An error occurred while processing your request.

diff --git a/WebfrontCore/Views/Shared/_Layout.cshtml b/WebfrontCore/Views/Shared/_Layout.cshtml index 9afb77e3..dd9349ee 100644 --- a/WebfrontCore/Views/Shared/_Layout.cshtml +++ b/WebfrontCore/Views/Shared/_Layout.cshtml @@ -6,7 +6,7 @@ @ViewBag.Title | IW4MAdmin - + diff --git a/_customcallbacks.gsc b/_customcallbacks.gsc index 60ef6816..5bf29bcd 100644 --- a/_customcallbacks.gsc +++ b/_customcallbacks.gsc @@ -68,12 +68,12 @@ Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vD _attacker = attacker.owner; else if(!isPlayer(attacker) && sMeansOfDeath == "MOD_FALLING") _attacker = victim; - + + location = victim GetTagOrigin(hitLocationToBone(sHitLoc)); - //attacker iPrintLnBold(location); - //attacker iPrintLnBold(attacker.origin[0]); + isKillstreakKill = !isPlayer(attacker) || isKillstreakWeapon(sWeapon); /*BulletTrace(_attacker GetTagOrigin("tag_eye"), VectorScale(anglesToForward(attacker getPlayerAngles())), true, attacker)["entity"]*/ - logPrint("ScriptKill;" + _attacker.guid + ";" + victim.guid + ";" + _attacker GetTagOrigin("tag_eye") + ";" + location + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + ";" + _attacker getPlayerAngles() + ";" + gettime() + "\n"); + logPrint("ScriptKill;" + _attacker.guid + ";" + victim.guid + ";" + _attacker GetTagOrigin("tag_eye") + ";" + location + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + ";" + _attacker getPlayerAngles() + ";" + gettime() + ";" + isKillstreakKill + ";" + _attacker playerADS() + "\n"); self maps\mp\gametypes\_damage::Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration ); } \ No newline at end of file