fix T6 reading

add WaW support
fix stats threading
This commit is contained in:
RaidMax 2018-05-10 23:52:20 -05:00
parent e964013700
commit 6e5501b32d
15 changed files with 246 additions and 151 deletions

View File

@ -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')
{

View File

@ -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";
}
}

View File

@ -139,7 +139,7 @@ namespace IW4MAdmin.Application
sensitiveEvent.OnProcessed.Set();
}
await Task.Delay(5000);
await Task.Delay(1000);
}
}

View 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;
}
}

View File

@ -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)
{

View File

@ -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();

View File

@ -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
};
}

View File

@ -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; }
}
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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>();

View 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();
}
}
}

View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.Interfaces
{
public interface ITrackable
{
string GetTrackableValue();
}
}

View File

@ -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;