update anti-cheat offset calculation
This commit is contained in:
parent
e86904b11e
commit
10829b32ad
@ -25,7 +25,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
public List<EFClientKill> QueuedHits { get; set; }
|
public List<EFClientKill> QueuedHits { get; set; }
|
||||||
int Kills;
|
int Kills;
|
||||||
int HitCount;
|
int HitCount;
|
||||||
Dictionary<IW4Info.HitLocation, int> HitLocationCount;
|
Dictionary<IW4Info.HitLocation, HitInfo> HitLocationCount;
|
||||||
double AngleDifferenceAverage;
|
double AngleDifferenceAverage;
|
||||||
EFClientStatistics ClientStats;
|
EFClientStatistics ClientStats;
|
||||||
long LastOffset;
|
long LastOffset;
|
||||||
@ -34,13 +34,19 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
Strain Strain;
|
Strain Strain;
|
||||||
readonly DateTime ConnectionTime = DateTime.UtcNow;
|
readonly DateTime ConnectionTime = DateTime.UtcNow;
|
||||||
|
|
||||||
|
private class HitInfo
|
||||||
|
{
|
||||||
|
public int Count { get; set; }
|
||||||
|
public double Offset { get; set; }
|
||||||
|
};
|
||||||
|
|
||||||
public Detection(ILogger log, EFClientStatistics clientStats)
|
public Detection(ILogger log, EFClientStatistics clientStats)
|
||||||
{
|
{
|
||||||
Log = log;
|
Log = log;
|
||||||
HitLocationCount = new Dictionary<IW4Info.HitLocation, int>();
|
HitLocationCount = new Dictionary<IW4Info.HitLocation, HitInfo>();
|
||||||
foreach (var loc in Enum.GetValues(typeof(IW4Info.HitLocation)))
|
foreach (var loc in Enum.GetValues(typeof(IW4Info.HitLocation)))
|
||||||
{
|
{
|
||||||
HitLocationCount.Add((IW4Info.HitLocation)loc, 0);
|
HitLocationCount.Add((IW4Info.HitLocation)loc, new HitInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientStats = clientStats;
|
ClientStats = clientStats;
|
||||||
@ -72,7 +78,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
DetectionPenaltyResult result = null;
|
DetectionPenaltyResult result = null;
|
||||||
LastWeapon = hit.Weapon;
|
LastWeapon = hit.Weapon;
|
||||||
|
|
||||||
HitLocationCount[hit.HitLoc]++;
|
HitLocationCount[hit.HitLoc].Count++;
|
||||||
HitCount++;
|
HitCount++;
|
||||||
|
|
||||||
if (!isDamage)
|
if (!isDamage)
|
||||||
@ -93,14 +99,18 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
double newAverage = (previousAverage * (hitLoc.HitCount - 1) + realAgainstPredict) / hitLoc.HitCount;
|
double newAverage = (previousAverage * (hitLoc.HitCount - 1) + realAgainstPredict) / hitLoc.HitCount;
|
||||||
hitLoc.HitOffsetAverage = (float)newAverage;
|
hitLoc.HitOffsetAverage = (float)newAverage;
|
||||||
|
|
||||||
if (hitLoc.HitOffsetAverage > Thresholds.MaxOffset(hitLoc.HitCount) &&
|
int totalHits = ClientStats.HitLocations.Sum(_hit => _hit.HitCount);
|
||||||
|
var weightedLifetimeAverage = ClientStats.HitLocations.Where(_hit => _hit.HitCount > 0)
|
||||||
|
.Sum(_hit => _hit.HitOffsetAverage * _hit.HitCount) / totalHits;
|
||||||
|
|
||||||
|
if (weightedLifetimeAverage > Thresholds.MaxOffset(totalHits) &&
|
||||||
hitLoc.HitCount > 100)
|
hitLoc.HitCount > 100)
|
||||||
{
|
{
|
||||||
//Log.WriteDebug("*** Reached Max Lifetime Average for Angle Difference ***");
|
Log.WriteDebug("*** Reached Max Lifetime Average for Angle Difference ***");
|
||||||
//Log.WriteDebug($"Lifetime Average = {newAverage}");
|
Log.WriteDebug($"Lifetime Average = {newAverage}");
|
||||||
//Log.WriteDebug($"Bone = {hitLoc.Location}");
|
Log.WriteDebug($"Bone = {hitLoc.Location}");
|
||||||
//Log.WriteDebug($"HitCount = {hitLoc.HitCount}");
|
Log.WriteDebug($"HitCount = {hitLoc.HitCount}");
|
||||||
//Log.WriteDebug($"ID = {hit.AttackerId}");
|
Log.WriteDebug($"ID = {hit.AttackerId}");
|
||||||
|
|
||||||
result = new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
@ -112,21 +122,25 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SESSION
|
// SESSION
|
||||||
double sessAverage = (AngleDifferenceAverage * (HitCount - 1) + realAgainstPredict) / HitCount;
|
var sessionHitLoc = HitLocationCount[hit.HitLoc];
|
||||||
AngleDifferenceAverage = sessAverage;
|
sessionHitLoc.Offset = (sessionHitLoc.Offset * (sessionHitLoc.Count - 1) + realAgainstPredict) / sessionHitLoc.Count;
|
||||||
|
|
||||||
if (sessAverage > Thresholds.MaxOffset(HitCount) &&
|
int totalSessionHits = HitLocationCount.Sum(_hit => _hit.Value.Count);
|
||||||
HitCount > 30)
|
var weightedSessionAverage = HitLocationCount.Where(_hit => _hit.Value.Count > 0)
|
||||||
|
.Sum(_hit => _hit.Value.Offset * _hit.Value.Count) / totalHits;
|
||||||
|
|
||||||
|
if (weightedSessionAverage > Thresholds.MaxOffset(totalSessionHits) &&
|
||||||
|
totalSessionHits > 40)
|
||||||
{
|
{
|
||||||
//Log.WriteDebug("*** Reached Max Session Average for Angle Difference ***");
|
Log.WriteDebug("*** Reached Max Session Average for Angle Difference ***");
|
||||||
//Log.WriteDebug($"Session Average = {sessAverage}");
|
Log.WriteDebug($"Session Average = {weightedSessionAverage}");
|
||||||
//Log.WriteDebug($"HitCount = {HitCount}");
|
Log.WriteDebug($"HitCount = {HitCount}");
|
||||||
//Log.WriteDebug($"ID = {hit.AttackerId}");
|
Log.WriteDebug($"ID = {hit.AttackerId}");
|
||||||
|
|
||||||
result = new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = EFPenalty.PenaltyType.Ban,
|
ClientPenalty = EFPenalty.PenaltyType.Ban,
|
||||||
Value = sessAverage,
|
Value = weightedSessionAverage,
|
||||||
HitCount = HitCount,
|
HitCount = HitCount,
|
||||||
Type = DetectionType.Offset,
|
Type = DetectionType.Offset,
|
||||||
Location = hitLoc.Location
|
Location = hitLoc.Location
|
||||||
@ -188,10 +202,10 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
double maxBoneRatioLerpValueForBan = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample(3.25), Thresholds.BoneRatioThresholdHighSample(3.25), lerpAmount) + marginOfError;
|
double maxBoneRatioLerpValueForBan = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample(3.25), Thresholds.BoneRatioThresholdHighSample(3.25), lerpAmount) + marginOfError;
|
||||||
|
|
||||||
// calculate headshot ratio
|
// calculate headshot ratio
|
||||||
double currentHeadshotRatio = ((HitLocationCount[IW4Info.HitLocation.head] + HitLocationCount[IW4Info.HitLocation.helmet] + HitLocationCount[IW4Info.HitLocation.neck]) / (double)HitCount);
|
double currentHeadshotRatio = ((HitLocationCount[IW4Info.HitLocation.head].Count + HitLocationCount[IW4Info.HitLocation.helmet].Count + HitLocationCount[IW4Info.HitLocation.neck].Count) / (double)HitCount);
|
||||||
|
|
||||||
// calculate maximum bone
|
// calculate maximum bone
|
||||||
double currentMaxBoneRatio = (HitLocationCount.Values.Select(v => v / (double)HitCount).Max());
|
double currentMaxBoneRatio = (HitLocationCount.Values.Select(v => v.Count / (double)HitCount).Max());
|
||||||
var bone = HitLocationCount.FirstOrDefault(b => b.Value == HitLocationCount.Values.Max()).Key;
|
var bone = HitLocationCount.FirstOrDefault(b => b.Value == HitLocationCount.Values.Max()).Key;
|
||||||
|
|
||||||
#region HEADSHOT_RATIO
|
#region HEADSHOT_RATIO
|
||||||
@ -308,7 +322,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region CHEST_ABDOMEN_RATIO_SESSION
|
#region CHEST_ABDOMEN_RATIO_SESSION
|
||||||
int chestHits = HitLocationCount[IW4Info.HitLocation.torso_upper];
|
int chestHits = HitLocationCount[IW4Info.HitLocation.torso_upper].Count;
|
||||||
|
|
||||||
if (chestHits >= Thresholds.MediumSampleMinKills)
|
if (chestHits >= Thresholds.MediumSampleMinKills)
|
||||||
{
|
{
|
||||||
@ -318,7 +332,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(3), Thresholds.ChestAbdomenRatioThresholdHighSample(3), lerpAmount) + marginOfError;
|
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 chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(4), Thresholds.ChestAbdomenRatioThresholdHighSample(4), lerpAmount) + marginOfError;
|
||||||
|
|
||||||
double currentChestAbdomenRatio = HitLocationCount[IW4Info.HitLocation.torso_upper] / (double)HitLocationCount[IW4Info.HitLocation.torso_lower];
|
double currentChestAbdomenRatio = HitLocationCount[IW4Info.HitLocation.torso_upper].Count / (double)HitLocationCount[IW4Info.HitLocation.torso_lower].Count;
|
||||||
|
|
||||||
if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag)
|
if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag)
|
||||||
{
|
{
|
||||||
|
@ -29,7 +29,10 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
|
|
||||||
public const double MaxStrainBan = 0.9;
|
public const double MaxStrainBan = 0.9;
|
||||||
|
|
||||||
public static double MaxOffset(int sampleSize) => Math.Exp(Math.Max(-3.07 + (-3.07 / Math.Sqrt(sampleSize)), -3.07 - (-3.07 / Math.Sqrt(sampleSize))) + 4 * (0.869));
|
private const double _offsetMeanLog = -2.727273;
|
||||||
|
private const double _offsetSdLog = 0.458325;
|
||||||
|
|
||||||
|
public static double MaxOffset(int sampleSize) => Math.Exp(Math.Max(_offsetMeanLog + (_offsetMeanLog / Math.Sqrt(sampleSize)), _offsetMeanLog - (_offsetMeanLog / Math.Sqrt(sampleSize))) + 4 * (_offsetSdLog));
|
||||||
public const double MaxStrainFlag = 0.36;
|
public const double MaxStrainFlag = 0.36;
|
||||||
|
|
||||||
public static double GetMarginOfError(int numKills) => 1.6455 / Math.Sqrt(numKills);
|
public static double GetMarginOfError(int numKills) => 1.6455 / Math.Sqrt(numKills);
|
||||||
|
@ -360,7 +360,7 @@ namespace SharedLibraryCore.Services
|
|||||||
{
|
{
|
||||||
using (var context = new DatabaseContext())
|
using (var context = new DatabaseContext())
|
||||||
{
|
{
|
||||||
if (temporalClient.LastConnection == DateTime.MinValue || temporalClient.Connections == 0 || temporalClient.TotalConnectionTime == 0)
|
if (temporalClient.LastConnection == DateTime.MinValue || temporalClient.FirstConnection == DateTime.MinValue)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"client {temporalClient} trying to update but parameters are invalid");
|
throw new InvalidOperationException($"client {temporalClient} trying to update but parameters are invalid");
|
||||||
}
|
}
|
||||||
@ -369,6 +369,12 @@ namespace SharedLibraryCore.Services
|
|||||||
var entity = context.Clients
|
var entity = context.Clients
|
||||||
.First(client => client.ClientId == temporalClient.ClientId);
|
.First(client => client.ClientId == temporalClient.ClientId);
|
||||||
|
|
||||||
|
if (entity.TotalConnectionTime > temporalClient.TotalConnectionTime || entity.Connections > temporalClient.Connections ||
|
||||||
|
entity.LastConnection > temporalClient.LastConnection || entity.FirstConnection > temporalClient.FirstConnection)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"client {temporalClient} trying to update but new parameters don't match saved parameters");
|
||||||
|
}
|
||||||
|
|
||||||
entity.LastConnection = temporalClient.LastConnection;
|
entity.LastConnection = temporalClient.LastConnection;
|
||||||
entity.Connections = temporalClient.Connections;
|
entity.Connections = temporalClient.Connections;
|
||||||
entity.FirstConnection = temporalClient.FirstConnection;
|
entity.FirstConnection = temporalClient.FirstConnection;
|
||||||
@ -462,7 +468,6 @@ namespace SharedLibraryCore.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
// want to find them by name (wildcard)
|
// want to find them by name (wildcard)
|
||||||
// todo maybe not make it start with wildcard?
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iqLinkIds = iqLinkIds.Where(_alias => EF.Functions.Like(_alias.Name.ToLower(), $"%{identifier.ToLower()}%"));
|
iqLinkIds = iqLinkIds.Where(_alias => EF.Functions.Like(_alias.Name.ToLower(), $"%{identifier.ToLower()}%"));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user