fix T6 reading
add WaW support fix stats threading
This commit is contained in:
parent
e964013700
commit
6e5501b32d
@ -13,7 +13,7 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
public virtual GameEvent GetEvent(Server server, string logLine)
|
||||
{
|
||||
string[] lineSplit = logLine.Split(';');
|
||||
string cleanedEventLine = Regex.Replace(lineSplit[0], @"[0-9]+:[0-9]+\ ", "").Trim();
|
||||
string cleanedEventLine = Regex.Replace(lineSplit[0], @"([0-9]+:[0-9]+ |^[0-9]+ )", "").Trim();
|
||||
|
||||
if (cleanedEventLine[0] == 'K')
|
||||
{
|
||||
|
@ -9,9 +9,9 @@ using SharedLibraryCore.Objects;
|
||||
|
||||
namespace IW4MAdmin.Application.EventParsers
|
||||
{
|
||||
class T6MEventParser : IEventParser
|
||||
class T6MEventParser : IW4EventParser
|
||||
{
|
||||
public GameEvent GetEvent(Server server, string logLine)
|
||||
/*public GameEvent GetEvent(Server server, string logLine)
|
||||
{
|
||||
string cleanedEventLine = Regex.Replace(logLine, @"^ *[0-9]+:[0-9]+ *", "").Trim();
|
||||
string[] lineSplit = cleanedEventLine.Split(';');
|
||||
@ -104,8 +104,8 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
},
|
||||
Owner = server
|
||||
};
|
||||
}
|
||||
}*/
|
||||
|
||||
public string GetGameDir() => $"t6r{Path.DirectorySeparatorChar}data";
|
||||
public override string GetGameDir() => $"t6r{Path.DirectorySeparatorChar}data";
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ namespace IW4MAdmin.Application
|
||||
sensitiveEvent.OnProcessed.Set();
|
||||
}
|
||||
|
||||
await Task.Delay(5000);
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
22
Application/RconParsers/IW3RConParser.cs
Normal file
22
Application/RconParsers/IW3RConParser.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using Application.RconParsers;
|
||||
using SharedLibraryCore.RCon;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Application.RconParsers
|
||||
{
|
||||
class IW3RConParser : IW4RConParser
|
||||
{
|
||||
private static CommandPrefix Prefixes = new CommandPrefix()
|
||||
{
|
||||
Tell = "tell {0} {1}",
|
||||
Say = "say {0}",
|
||||
Kick = "clientkick {0} \"{1}\"",
|
||||
Ban = "clientkick {0} \"{1}\"",
|
||||
TempBan = "tempbanclient {0} \"{1}\""
|
||||
};
|
||||
|
||||
public override CommandPrefix GetCommandPrefixes() => Prefixes;
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ namespace Application.RconParsers
|
||||
TempBan = "tempbanclient {0} \"{1}\""
|
||||
};
|
||||
|
||||
private static string StatusRegex = @"^( *[0-9]+) +-*([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){16}|bot[0-9]+|(?:[0-9]+)) +(.{0,20}) +([0-9]+) +(\d+\.\d+\.\d+.\d+\:-*\d{1,5}|0+.0+:-*\d{1,5}) +(-*[0-9]+) +([0-9]+) *$";
|
||||
private static string StatusRegex = @"^( *[0-9]+) +-*([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){16}|bot[0-9]+|(?:[0-9]+)) +(.{0,20}) +([0-9]+) +(\d+\.\d+\.\d+.\d+\:-*\d{1,5}|0+.0+:-*\d{1,5}|loopback) +(-*[0-9]+) +([0-9]+) *$";
|
||||
|
||||
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
|
||||
{
|
||||
@ -72,7 +72,7 @@ namespace Application.RconParsers
|
||||
return (await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, $"set {dvarName} {dvarValue}")).Length > 0;
|
||||
}
|
||||
|
||||
public CommandPrefix GetCommandPrefixes() => Prefixes;
|
||||
public virtual CommandPrefix GetCommandPrefixes() => Prefixes;
|
||||
|
||||
private List<Player> ClientsFromStatus(string[] Status)
|
||||
{
|
||||
|
@ -723,7 +723,7 @@ namespace IW4MAdmin
|
||||
|
||||
public async Task Initialize()
|
||||
{
|
||||
RconParser = ServerConfig.UseT6MParser ? (IRConParser)new T6MRConParser() : new IW4RConParser();
|
||||
RconParser = ServerConfig.UseT6MParser ? (IRConParser)new T6MRConParser() : new IW3RConParser();
|
||||
if (ServerConfig.UseIW5MParser)
|
||||
RconParser = new IW5MRConParser();
|
||||
|
||||
|
@ -6,17 +6,23 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
{
|
||||
class Detection
|
||||
{
|
||||
public enum DetectionType
|
||||
{
|
||||
Bone,
|
||||
Chest,
|
||||
Offset,
|
||||
Strain
|
||||
};
|
||||
|
||||
int Kills;
|
||||
int HitCount;
|
||||
int AboveThresholdCount;
|
||||
double AverageKillTime;
|
||||
Dictionary<IW4Info.HitLocation, int> HitLocationCount;
|
||||
ChangeTracking Tracker;
|
||||
double AngleDifferenceAverage;
|
||||
EFClientStatistics ClientStats;
|
||||
DateTime LastHit;
|
||||
@ -32,31 +38,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
HitLocationCount.Add((IW4Info.HitLocation)loc, 0);
|
||||
ClientStats = clientStats;
|
||||
Strain = new Strain();
|
||||
}
|
||||
|
||||
public void ProcessScriptDamage(string damageLine)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void ProcessDamage(string damageLine)
|
||||
{
|
||||
string regex = @"^(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]|_)+)$";
|
||||
|
||||
var match = Regex.Match(damageLine, regex, RegexOptions.IgnoreCase);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
var meansOfDeath = ParseEnum<IW4Info.MeansOfDeath>.Get(match.Groups[12].Value, typeof(IW4Info.MeansOfDeath));
|
||||
var hitLocation = ParseEnum<IW4Info.HitLocation>.Get(match.Groups[13].Value, typeof(IW4Info.HitLocation));
|
||||
|
||||
if (meansOfDeath == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET ||
|
||||
meansOfDeath == IW4Info.MeansOfDeath.MOD_RIFLE_BULLET ||
|
||||
meansOfDeath == IW4Info.MeansOfDeath.MOD_HEAD_SHOT)
|
||||
{
|
||||
ClientStats.HitLocations.First(hl => hl.Location == hitLocation).HitCount += 1;
|
||||
}
|
||||
}
|
||||
Tracker = new ChangeTracking();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -111,8 +93,8 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = Penalty.PenaltyType.Flag,
|
||||
RatioAmount = hitLoc.HitOffsetAverage,
|
||||
KillCount = hitLoc.HitCount,
|
||||
Value = hitLoc.HitOffsetAverage,
|
||||
HitCount = hitLoc.HitCount,
|
||||
};
|
||||
}
|
||||
|
||||
@ -124,15 +106,16 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
{
|
||||
Log.WriteDebug("*** Reached Max Session Average for Angle Difference ***");
|
||||
Log.WriteDebug($"Session Average = {sessAverage}");
|
||||
// Log.WriteDebug($"Bone = {hitLoc.Location}");
|
||||
Log.WriteDebug($"HitCount = {HitCount}");
|
||||
Log.WriteDebug($"ID = {kill.AttackerId}");
|
||||
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = Penalty.PenaltyType.Flag,
|
||||
RatioAmount = sessAverage,
|
||||
KillCount = HitCount,
|
||||
ClientPenalty = Penalty.PenaltyType.Ban,
|
||||
Value = sessAverage,
|
||||
HitCount = HitCount,
|
||||
Type = DetectionType.Offset,
|
||||
Location = hitLoc.Location
|
||||
};
|
||||
}
|
||||
|
||||
@ -140,10 +123,8 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
Log.WriteDebug($"PredictVsReal={realAgainstPredict}");
|
||||
#endif
|
||||
}
|
||||
var currentStrain = Strain.GetStrain(kill.ViewAngles, Math.Max(50, kill.TimeOffset - LastOffset));
|
||||
|
||||
double diff = Math.Max(50, kill.TimeOffset - LastOffset);
|
||||
var currentStrain = Strain.GetStrain(kill.ViewAngles, diff);
|
||||
//LastHit = kill.When;
|
||||
LastOffset = kill.TimeOffset;
|
||||
|
||||
if (currentStrain > ClientStats.MaxStrain)
|
||||
@ -151,14 +132,20 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
ClientStats.MaxStrain = currentStrain;
|
||||
}
|
||||
|
||||
if (currentStrain > Thresholds.MaxStrain)
|
||||
if (currentStrain > Thresholds.MaxStrainFlag)
|
||||
{
|
||||
Log.WriteDebug("*** Reached Max Strain ***");
|
||||
Log.WriteDebug($"Strain = {currentStrain}");
|
||||
Log.WriteDebug($"Angles = {kill.ViewAngles} {kill.AnglesList[0]} {kill.AnglesList[1]}");
|
||||
Log.WriteDebug($"Time = {diff}");
|
||||
Log.WriteDebug($"HitCount = {HitCount}");
|
||||
Log.WriteDebug($"ID = {kill.AttackerId}");
|
||||
Tracker.OnChange(Strain);
|
||||
|
||||
foreach (string change in Tracker.GetChanges())
|
||||
{
|
||||
Log.WriteDebug(change);
|
||||
}
|
||||
Log.WriteDebug(ClientStats.RoundScore.ToString());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Tracker.ClearChanges();
|
||||
}
|
||||
|
||||
if (Strain.TimesReachedMaxStrain >= 3)
|
||||
@ -166,8 +153,9 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = Penalty.PenaltyType.Flag,
|
||||
RatioAmount = ClientStats.MaxStrain,
|
||||
KillCount = HitCount,
|
||||
Value = ClientStats.MaxStrain,
|
||||
HitCount = HitCount,
|
||||
Type = DetectionType.Strain
|
||||
};
|
||||
}
|
||||
|
||||
@ -203,46 +191,44 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
// 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($"**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());
|
||||
Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
|
||||
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = Penalty.PenaltyType.Ban,
|
||||
RatioAmount = currentHeadshotRatio,
|
||||
Bone = IW4Info.HitLocation.head,
|
||||
KillCount = Kills
|
||||
Value = currentHeadshotRatio,
|
||||
Location = IW4Info.HitLocation.head,
|
||||
HitCount = HitCount,
|
||||
Type = DetectionType.Bone
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
AboveThresholdCount++;
|
||||
Log.WriteDebug("**Maximum Headshot Ratio Reached For Flag**");
|
||||
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
||||
Log.WriteDebug($"**Kills: {Kills}");
|
||||
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());
|
||||
Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
|
||||
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = Penalty.PenaltyType.Flag,
|
||||
RatioAmount = currentHeadshotRatio,
|
||||
Bone = IW4Info.HitLocation.head,
|
||||
KillCount = Kills
|
||||
Value = currentHeadshotRatio,
|
||||
Location = IW4Info.HitLocation.head,
|
||||
HitCount = HitCount,
|
||||
Type = DetectionType.Bone
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -257,7 +243,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
{
|
||||
Log.WriteDebug("**Maximum Bone Ratio Reached For Ban**");
|
||||
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
||||
Log.WriteDebug($"**Kills: {Kills}");
|
||||
Log.WriteDebug($"**HitCount: {HitCount}");
|
||||
Log.WriteDebug($"**Ratio {currentMaxBoneRatio}");
|
||||
Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValueForBan}");
|
||||
var sb = new StringBuilder();
|
||||
@ -268,16 +254,17 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = Penalty.PenaltyType.Ban,
|
||||
RatioAmount = currentMaxBoneRatio,
|
||||
Bone = bone,
|
||||
KillCount = Kills
|
||||
Value = currentMaxBoneRatio,
|
||||
Location = bone,
|
||||
HitCount = HitCount,
|
||||
Type = DetectionType.Bone
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.WriteDebug("**Maximum Bone Ratio Reached For Flag**");
|
||||
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
||||
Log.WriteDebug($"**Kills: {Kills}");
|
||||
Log.WriteDebug($"**HitCount: {HitCount}");
|
||||
Log.WriteDebug($"**Ratio {currentMaxBoneRatio}");
|
||||
Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValueForFlag}");
|
||||
var sb = new StringBuilder();
|
||||
@ -288,9 +275,10 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = Penalty.PenaltyType.Flag,
|
||||
RatioAmount = currentMaxBoneRatio,
|
||||
Bone = bone,
|
||||
KillCount = Kills
|
||||
Value = currentMaxBoneRatio,
|
||||
Location = bone,
|
||||
HitCount = HitCount,
|
||||
Type = DetectionType.Bone
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -298,12 +286,12 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
}
|
||||
|
||||
#region CHEST_ABDOMEN_RATIO_SESSION
|
||||
int chestKills = HitLocationCount[IW4Info.HitLocation.torso_upper];
|
||||
int chestHits = HitLocationCount[IW4Info.HitLocation.torso_upper];
|
||||
|
||||
if (chestKills >= Thresholds.MediumSampleMinKills)
|
||||
if (chestHits >= Thresholds.MediumSampleMinKills)
|
||||
{
|
||||
double marginOfError = Thresholds.GetMarginOfError(chestKills);
|
||||
double lerpAmount = Math.Min(1.0, (chestKills - Thresholds.MediumSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills));
|
||||
double marginOfError = Thresholds.GetMarginOfError(chestHits);
|
||||
double lerpAmount = Math.Min(1.0, (chestHits - Thresholds.MediumSampleMinKills) / (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;
|
||||
@ -313,32 +301,32 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag)
|
||||
{
|
||||
|
||||
if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan && chestKills >= Thresholds.MediumSampleMinKills + 30)
|
||||
if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan && chestHits >= Thresholds.MediumSampleMinKills + 30)
|
||||
{
|
||||
Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Ban**");
|
||||
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
||||
Log.WriteDebug($"**Chest Kills: {chestKills}");
|
||||
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());
|
||||
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
|
||||
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = Penalty.PenaltyType.Ban,
|
||||
RatioAmount = currentChestAbdomenRatio,
|
||||
Bone = 0,
|
||||
KillCount = chestKills
|
||||
Value = currentChestAbdomenRatio,
|
||||
Location = IW4Info.HitLocation.torso_upper,
|
||||
Type = DetectionType.Chest,
|
||||
HitCount = chestHits
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Flag**");
|
||||
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
||||
Log.WriteDebug($"**Chest Kills: {chestKills}");
|
||||
Log.WriteDebug($"**Chest Hits: {chestHits}");
|
||||
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
|
||||
Log.WriteDebug($"**MaxRatio {chestAbdomenRatioLerpValueForFlag}");
|
||||
var sb = new StringBuilder();
|
||||
@ -350,9 +338,10 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = Penalty.PenaltyType.Flag,
|
||||
RatioAmount = currentChestAbdomenRatio,
|
||||
Bone = 0,
|
||||
KillCount = chestKills
|
||||
Value = currentChestAbdomenRatio,
|
||||
Location = IW4Info.HitLocation.torso_upper,
|
||||
Type = DetectionType.Chest,
|
||||
HitCount = chestHits
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -362,23 +351,22 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = Penalty.PenaltyType.Any,
|
||||
RatioAmount = 0
|
||||
};
|
||||
}
|
||||
|
||||
public DetectionPenaltyResult ProcessTotalRatio(EFClientStatistics stats)
|
||||
{
|
||||
int totalChestKills = stats.HitLocations.Single(c => c.Location == IW4Info.HitLocation.torso_upper).HitCount;
|
||||
int totalChestHits = stats.HitLocations.Single(c => c.Location == IW4Info.HitLocation.torso_upper).HitCount;
|
||||
|
||||
if (totalChestKills >= 60)
|
||||
if (totalChestHits >= 60)
|
||||
{
|
||||
double marginOfError = Thresholds.GetMarginOfError(totalChestKills);
|
||||
double lerpAmount = Math.Min(1.0, (totalChestKills - 60) / 250.0);
|
||||
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 = totalChestKills /
|
||||
double currentChestAbdomenRatio = totalChestHits /
|
||||
stats.HitLocations.Single(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount;
|
||||
|
||||
if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag)
|
||||
@ -388,42 +376,42 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
{
|
||||
Log.WriteDebug("**Maximum Lifetime Chest/Abdomen Ratio Reached For Ban**");
|
||||
Log.WriteDebug($"ClientId: {stats.ClientId}");
|
||||
Log.WriteDebug($"**Total Chest Kills: {totalChestKills}");
|
||||
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());
|
||||
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
|
||||
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = Penalty.PenaltyType.Ban,
|
||||
RatioAmount = currentChestAbdomenRatio,
|
||||
Bone = IW4Info.HitLocation.torso_upper,
|
||||
KillCount = totalChestKills
|
||||
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 Kills: {totalChestKills}");
|
||||
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());
|
||||
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
|
||||
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
ClientPenalty = Penalty.PenaltyType.Flag,
|
||||
RatioAmount = currentChestAbdomenRatio,
|
||||
Bone = IW4Info.HitLocation.torso_upper,
|
||||
KillCount = totalChestKills
|
||||
Value = currentChestAbdomenRatio,
|
||||
Location = IW4Info.HitLocation.torso_upper,
|
||||
HitCount = totalChestHits,
|
||||
Type = DetectionType.Chest
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -431,7 +419,6 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
|
||||
return new DetectionPenaltyResult()
|
||||
{
|
||||
Bone = IW4Info.HitLocation.none,
|
||||
ClientPenalty = Penalty.PenaltyType.Any
|
||||
};
|
||||
}
|
||||
|
@ -9,9 +9,10 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
{
|
||||
class DetectionPenaltyResult
|
||||
{
|
||||
public Detection.DetectionType Type { get; set; }
|
||||
public Penalty.PenaltyType ClientPenalty { get; set; }
|
||||
public double RatioAmount { get; set; }
|
||||
public IW4Info.HitLocation Bone { get; set; }
|
||||
public int KillCount { get; set; }
|
||||
public double Value { get; set; }
|
||||
public IW4Info.HitLocation Location { get; set; }
|
||||
public int HitCount { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,18 @@
|
||||
using SharedLibraryCore.Helpers;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
{
|
||||
class Strain
|
||||
class Strain : ITrackable
|
||||
{
|
||||
private static double StrainDecayBase = 0.15;
|
||||
private double CurrentStrain;
|
||||
private Vector3 LastAngle;
|
||||
private double LastDeltaTime;
|
||||
private double LastDistance;
|
||||
|
||||
public int TimesReachedMaxStrain { get; private set; }
|
||||
|
||||
@ -18,10 +21,13 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
if (LastAngle == null)
|
||||
LastAngle = newAngle;
|
||||
|
||||
LastDeltaTime = deltaTime;
|
||||
|
||||
double decayFactor = GetDecay(deltaTime);
|
||||
CurrentStrain *= decayFactor;
|
||||
|
||||
double[] distance = Helpers.Extensions.AngleStuff(newAngle, LastAngle);
|
||||
LastDistance = distance[0] + distance[1];
|
||||
|
||||
// this happens on first kill
|
||||
if ((distance[0] == 0 && distance[1] == 0) ||
|
||||
@ -34,13 +40,18 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
double newStrain = Math.Pow(distance[0] + distance[1], 0.99) / deltaTime;
|
||||
CurrentStrain += newStrain;
|
||||
|
||||
if (CurrentStrain > Thresholds.MaxStrain)
|
||||
if (CurrentStrain > Thresholds.MaxStrainFlag)
|
||||
TimesReachedMaxStrain++;
|
||||
|
||||
LastAngle = newAngle;
|
||||
return CurrentStrain;
|
||||
}
|
||||
|
||||
|
||||
public string GetTrackableValue()
|
||||
{
|
||||
return $"Strain - {CurrentStrain}, Angle - {LastAngle}, Delta Time - {LastDeltaTime}, Distance - {LastDistance}";
|
||||
}
|
||||
|
||||
private double GetDecay(double deltaTime) => Math.Pow(StrainDecayBase, deltaTime / 1000.0);
|
||||
}
|
||||
}
|
@ -27,8 +27,9 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
public const int HighSampleMinKills = 100;
|
||||
public const double KillTimeThreshold = 0.2;
|
||||
|
||||
public const double MaxStrain = 0.4399;
|
||||
public const double MaxStrainBan = 0.4399;
|
||||
public const double MaxOffset = 4.789;
|
||||
public const double MaxStrainFlag = 0.2;
|
||||
|
||||
public static double GetMarginOfError(int numKills) => 1.6455 / Math.Sqrt(numKills);
|
||||
|
||||
|
@ -126,13 +126,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
.ToList()
|
||||
};
|
||||
|
||||
clientStats = statsSvc.ClientStatSvc.Insert(clientStats);
|
||||
await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
statsSvc.ClientStatSvc.Update(clientStats);
|
||||
// insert if they've not been added
|
||||
var clientStatsSvc = statsSvc.ClientStatSvc;
|
||||
clientStats = clientStatsSvc.Insert(clientStats);
|
||||
await clientStatsSvc.SaveChangesAsync();
|
||||
}
|
||||
|
||||
// migration for previous existing stats
|
||||
@ -161,9 +158,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
if (!detectionStats.TryAdd(pl.ClientId, new Cheat.Detection(Log, clientStats)))
|
||||
Log.WriteDebug("Could not add client to detection");
|
||||
|
||||
/*
|
||||
await statsSvc.ClientStatSvc.SaveChangesAsync();*/
|
||||
|
||||
return clientStats;
|
||||
}
|
||||
|
||||
@ -193,30 +187,39 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
|
||||
// get individual client's stats
|
||||
var clientStats = playerStats[pl.ClientId];
|
||||
/*// sync their score
|
||||
clientStats.SessionScore += pl.Score;*/
|
||||
|
||||
// remove the client from the stats dictionary as they're leaving
|
||||
playerStats.TryRemove(pl.ClientId, out EFClientStatistics removedValue3);
|
||||
detectionStats.TryRemove(pl.ClientId, out Cheat.Detection removedValue4);
|
||||
|
||||
// sync their stats before they leave
|
||||
//clientStats = UpdateStats(clientStats);
|
||||
// clientStats = UpdateStats(clientStats);
|
||||
// var clientStatsSvc = statsSvc.ClientStatSvc;
|
||||
// clientStatsSvc.Update(clientStats);
|
||||
// await clientStatsSvc.SaveChangesAsync();
|
||||
|
||||
statsSvc.ClientStatSvc.Update(clientStats);
|
||||
await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
// increment the total play time
|
||||
serverStats.TotalPlayTime += (int)(DateTime.UtcNow - pl.LastConnection).TotalSeconds;
|
||||
//await statsSvc.ServerStatsSvc.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public void AddDamageEvent(string eventLine, int clientId, int serverId)
|
||||
{
|
||||
if (Plugin.Config.Configuration().EnableAntiCheat)
|
||||
{
|
||||
var clientDetection = Servers[serverId].PlayerDetections[clientId];
|
||||
clientDetection.ProcessScriptDamage(eventLine);
|
||||
}
|
||||
/* string regex = @"^(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]|_)+)$";
|
||||
|
||||
var match = Regex.Match(damageLine, regex, RegexOptions.IgnoreCase);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
var meansOfDeath = ParseEnum<IW4Info.MeansOfDeath>.Get(match.Groups[12].Value, typeof(IW4Info.MeansOfDeath));
|
||||
var hitLocation = ParseEnum<IW4Info.HitLocation>.Get(match.Groups[13].Value, typeof(IW4Info.HitLocation));
|
||||
|
||||
if (meansOfDeath == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET ||
|
||||
meansOfDeath == IW4Info.MeansOfDeath.MOD_RIFLE_BULLET ||
|
||||
meansOfDeath == IW4Info.MeansOfDeath.MOD_HEAD_SHOT)
|
||||
{
|
||||
ClientStats.HitLocations.First(hl => hl.Location == hitLocation).HitCount += 1;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -310,7 +313,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
{
|
||||
clientStats.HitLocations.Single(hl => hl.Location == kill.HitLoc).HitCount += 1;
|
||||
|
||||
//statsSvc.ClientStatSvc.Update(clientStats);
|
||||
statsSvc.ClientStatSvc.Update(clientStats);
|
||||
// await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@ -330,19 +333,31 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
switch (penalty.ClientPenalty)
|
||||
{
|
||||
case Penalty.PenaltyType.Ban:
|
||||
await attacker.Ban(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_CHEAT_DETECTED"], new Player() { ClientId = 1 });
|
||||
await attacker.Ban(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_CHEAT_DETECTED"], new Player()
|
||||
{
|
||||
ClientId = 1
|
||||
});
|
||||
break;
|
||||
case Penalty.PenaltyType.Flag:
|
||||
if (attacker.Level != Player.Permission.User)
|
||||
break;
|
||||
var flagCmd = new CFlag();
|
||||
await flagCmd.ExecuteAsync(new GameEvent(GameEvent.EventType.Flag, $"{(int)penalty.Bone}-{Math.Round(penalty.RatioAmount, 2).ToString()}@{penalty.KillCount}", new Player()
|
||||
var e = new GameEvent()
|
||||
{
|
||||
ClientId = 1,
|
||||
Level = Player.Permission.Console,
|
||||
ClientNumber = -1,
|
||||
CurrentServer = attacker.CurrentServer
|
||||
}, attacker, attacker.CurrentServer));
|
||||
Data = penalty.Type == Cheat.Detection.DetectionType.Bone ?
|
||||
$"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" :
|
||||
$"{penalty.Type} -{Math.Round(penalty.Value, 2)}@{penalty.HitCount}",
|
||||
Origin = new Player()
|
||||
{
|
||||
ClientId = 1,
|
||||
Level = Player.Permission.Console,
|
||||
ClientNumber = -1,
|
||||
CurrentServer = attacker.CurrentServer
|
||||
},
|
||||
Target = attacker,
|
||||
Owner = attacker.CurrentServer,
|
||||
Type = GameEvent.EventType.Flag
|
||||
};
|
||||
await new CFlag().ExecuteAsync(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -433,10 +448,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
}
|
||||
|
||||
// todo: do we want to save this immediately?
|
||||
var statsSvc = ContextThreads[serverId];
|
||||
statsSvc.ClientStatSvc.Update(attackerStats);
|
||||
statsSvc.ClientStatSvc.Update(victimStats);
|
||||
//await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
var statsSvc = ContextThreads[serverId].ClientStatSvc;
|
||||
statsSvc.Update(attackerStats);
|
||||
statsSvc.Update(victimStats);
|
||||
await statsSvc.SaveChangesAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -463,7 +478,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
victimStats.KillStreak = 0;
|
||||
|
||||
// process the attacker's stats after the kills
|
||||
attackerStats = UpdateStats(attackerStats);
|
||||
//attackerStats = UpdateStats(attackerStats);
|
||||
|
||||
// update after calculation
|
||||
attackerStats.TimePlayed += (int)(DateTime.UtcNow - attackerStats.LastActive).TotalSeconds;
|
||||
|
@ -10,7 +10,13 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
{
|
||||
public class ThreadSafeStatsService
|
||||
{
|
||||
public GenericRepository<EFClientStatistics> ClientStatSvc { get; private set; }
|
||||
public GenericRepository<EFClientStatistics> ClientStatSvc
|
||||
{
|
||||
get
|
||||
{
|
||||
return new GenericRepository<EFClientStatistics>();
|
||||
}
|
||||
}
|
||||
public GenericRepository<EFServer> ServerSvc { get; private set; }
|
||||
public GenericRepository<EFClientKill> KillStatsSvc { get; private set; }
|
||||
public GenericRepository<EFServerStatistics> ServerStatsSvc { get; private set; }
|
||||
@ -18,7 +24,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
|
||||
public ThreadSafeStatsService()
|
||||
{
|
||||
ClientStatSvc = new GenericRepository<EFClientStatistics>();
|
||||
//ClientStatSvc = new GenericRepository<EFClientStatistics>();
|
||||
ServerSvc = new GenericRepository<EFServer>();
|
||||
KillStatsSvc = new GenericRepository<EFClientKill>();
|
||||
ServerStatsSvc = new GenericRepository<EFServerStatistics>();
|
||||
|
41
SharedLibraryCore/Helpers/ChangeTracking.cs
Normal file
41
SharedLibraryCore/Helpers/ChangeTracking.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SharedLibraryCore.Helpers
|
||||
{
|
||||
public class ChangeTracking
|
||||
{
|
||||
List<string> Values;
|
||||
|
||||
public ChangeTracking()
|
||||
{
|
||||
Values = new List<string>();
|
||||
}
|
||||
|
||||
public void OnChange(ITrackable value)
|
||||
{
|
||||
Values.Add(value.GetTrackableValue());
|
||||
}
|
||||
|
||||
public void ClearChanges()
|
||||
{
|
||||
Values.Clear();
|
||||
}
|
||||
|
||||
public string[] GetChanges()
|
||||
{
|
||||
List<string> values = new List<string>();
|
||||
|
||||
int number = 1;
|
||||
foreach (string change in Values)
|
||||
{
|
||||
values.Add($"{number} {change}");
|
||||
number++;
|
||||
}
|
||||
|
||||
return values.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
11
SharedLibraryCore/Interfaces/ITrackable.cs
Normal file
11
SharedLibraryCore/Interfaces/ITrackable.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
{
|
||||
public interface ITrackable
|
||||
{
|
||||
string GetTrackableValue();
|
||||
}
|
||||
}
|
@ -242,7 +242,7 @@ namespace SharedLibraryCore
|
||||
return Game.IW4;
|
||||
if (gameName.Contains("CoD4"))
|
||||
return Game.IW3;
|
||||
if (gameName.Contains("WaW"))
|
||||
if (gameName.Contains("COD_WaW"))
|
||||
return Game.T4;
|
||||
if (gameName.Contains("COD_T5_S"))
|
||||
return Game.T5;
|
||||
|
Loading…
Reference in New Issue
Block a user