auth cookie expires after 30 days

only check hit offset when distance > 3 meters
fix null reference on unauthorized user
fixed stats not showing on profile if anticheat disabled
server client history turns red server is unresponsive
This commit is contained in:
RaidMax 2018-04-04 23:38:45 -05:00
parent c0865b82a0
commit 6d8d021b16
29 changed files with 455 additions and 352 deletions

View File

@ -60,7 +60,7 @@ namespace StatsPlugin.Cheat
var calculatedVector = Vector3.Subtract(kill.KillOrigin, new Vector3((float)x, (float)y, (float)z));
double angle = trueVector.AngleBetween(calculatedVector);
if (kill.AdsPercent > 0.5)
if (kill.AdsPercent > 0.5 && kill.Distance > 3)
{
var hitLoc = ClientStats.HitLocations
.First(hl => hl.Location == kill.HitLoc);
@ -69,264 +69,264 @@ namespace StatsPlugin.Cheat
hitLoc.HitOffsetAverage = (float)newAverage;
}
#endregion
#endregion
#region SESSION_RATIOS
if (Kills >= Thresholds.LowSampleMinKills)
{
double marginOfError = Thresholds.GetMarginOfError(Kills);
// determine what the max headshot percentage can be for current number of kills
double lerpAmount = Math.Min(1.0, (Kills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills));
double maxHeadshotLerpValueForFlag = Thresholds.Lerp(Thresholds.HeadshotRatioThresholdLowSample(2.0), Thresholds.HeadshotRatioThresholdHighSample(2.0), lerpAmount) + marginOfError;
double maxHeadshotLerpValueForBan = Thresholds.Lerp(Thresholds.HeadshotRatioThresholdLowSample(3.0), Thresholds.HeadshotRatioThresholdHighSample(3.0), lerpAmount) + marginOfError;
// determine what the max bone percentage can be for current number of kills
double maxBoneRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample(2.25), Thresholds.BoneRatioThresholdHighSample(2.25), lerpAmount) + marginOfError;
double maxBoneRatioLerpValueForBan = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample(3.25), Thresholds.BoneRatioThresholdHighSample(3.25), lerpAmount) + marginOfError;
#region SESSION_RATIOS
if (Kills >= Thresholds.LowSampleMinKills)
{
double marginOfError = Thresholds.GetMarginOfError(Kills);
// determine what the max headshot percentage can be for current number of kills
double lerpAmount = Math.Min(1.0, (Kills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills));
double maxHeadshotLerpValueForFlag = Thresholds.Lerp(Thresholds.HeadshotRatioThresholdLowSample(2.0), Thresholds.HeadshotRatioThresholdHighSample(2.0), lerpAmount) + marginOfError;
double maxHeadshotLerpValueForBan = Thresholds.Lerp(Thresholds.HeadshotRatioThresholdLowSample(3.0), Thresholds.HeadshotRatioThresholdHighSample(3.0), lerpAmount) + marginOfError;
// determine what the max bone percentage can be for current number of kills
double maxBoneRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample(2.25), Thresholds.BoneRatioThresholdHighSample(2.25), lerpAmount) + marginOfError;
double maxBoneRatioLerpValueForBan = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample(3.25), Thresholds.BoneRatioThresholdHighSample(3.25), lerpAmount) + marginOfError;
// calculate headshot ratio
double currentHeadshotRatio = ((HitLocationCount[IW4Info.HitLocation.head] + HitLocationCount[IW4Info.HitLocation.helmet]) / (double)Kills);
// calculate maximum bone
double currentMaxBoneRatio = (HitLocationCount.Values.Select(v => v / (double)Kills).Max());
// calculate headshot ratio
double currentHeadshotRatio = ((HitLocationCount[IW4Info.HitLocation.head] + HitLocationCount[IW4Info.HitLocation.helmet]) / (double)Kills);
// calculate maximum bone
double currentMaxBoneRatio = (HitLocationCount.Values.Select(v => v / (double)Kills).Max());
var bone = HitLocationCount.FirstOrDefault(b => b.Value == HitLocationCount.Values.Max()).Key;
#region HEADSHOT_RATIO
// flag on headshot
if (currentHeadshotRatio > maxHeadshotLerpValueForFlag)
{
// ban on headshot
if (currentHeadshotRatio > maxHeadshotLerpValueForFlag)
{
AboveThresholdCount++;
Log.WriteDebug("**Maximum Headshot Ratio Reached For Ban**");
Log.WriteDebug($"ClientId: {kill.AttackerId}");
Log.WriteDebug($"**Kills: {Kills}");
Log.WriteDebug($"**Ratio {currentHeadshotRatio}");
Log.WriteDebug($"**MaxRatio {maxHeadshotLerpValueForFlag}");
var sb = new StringBuilder();
foreach (var kvp in HitLocationCount)
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
Log.WriteDebug(sb.ToString());
Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
var bone = HitLocationCount.FirstOrDefault(b => b.Value == HitLocationCount.Values.Max()).Key;
#region HEADSHOT_RATIO
// flag on headshot
if (currentHeadshotRatio > maxHeadshotLerpValueForFlag)
{
// ban on headshot
if (currentHeadshotRatio > maxHeadshotLerpValueForFlag)
{
AboveThresholdCount++;
Log.WriteDebug("**Maximum Headshot Ratio Reached For Ban**");
Log.WriteDebug($"ClientId: {kill.AttackerId}");
Log.WriteDebug($"**Kills: {Kills}");
Log.WriteDebug($"**Ratio {currentHeadshotRatio}");
Log.WriteDebug($"**MaxRatio {maxHeadshotLerpValueForFlag}");
var sb = new StringBuilder();
foreach (var kvp in HitLocationCount)
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
Log.WriteDebug(sb.ToString());
Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Ban,
RatioAmount = currentHeadshotRatio,
Bone = IW4Info.HitLocation.head,
KillCount = Kills
};
}
else
{
AboveThresholdCount++;
Log.WriteDebug("**Maximum Headshot Ratio Reached For Flag**");
Log.WriteDebug($"ClientId: {kill.AttackerId}");
Log.WriteDebug($"**Kills: {Kills}");
Log.WriteDebug($"**Ratio {currentHeadshotRatio}");
Log.WriteDebug($"**MaxRatio {maxHeadshotLerpValueForFlag}");
var sb = new StringBuilder();
foreach (var kvp in HitLocationCount)
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
Log.WriteDebug(sb.ToString());
Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Flag,
RatioAmount = currentHeadshotRatio,
Bone = IW4Info.HitLocation.head,
KillCount = Kills
};
}
}
#endregion
#region BONE_RATIO
// flag on bone ratio
else if (currentMaxBoneRatio > maxBoneRatioLerpValueForFlag)
{
// ban on bone ratio
if (currentMaxBoneRatio > maxBoneRatioLerpValueForBan)
{
Log.WriteDebug("**Maximum Bone Ratio Reached For Ban**");
Log.WriteDebug($"ClientId: {kill.AttackerId}");
Log.WriteDebug($"**Kills: {Kills}");
Log.WriteDebug($"**Ratio {currentMaxBoneRatio}");
Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValueForBan}");
var sb = new StringBuilder();
foreach (var kvp in HitLocationCount)
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
Log.WriteDebug(sb.ToString());
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Ban,
RatioAmount = currentMaxBoneRatio,
Bone = bone,
KillCount = Kills
};
}
else
{
Log.WriteDebug("**Maximum Bone Ratio Reached For Flag**");
Log.WriteDebug($"ClientId: {kill.AttackerId}");
Log.WriteDebug($"**Kills: {Kills}");
Log.WriteDebug($"**Ratio {currentMaxBoneRatio}");
Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValueForFlag}");
var sb = new StringBuilder();
foreach (var kvp in HitLocationCount)
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
Log.WriteDebug(sb.ToString());
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Flag,
RatioAmount = currentMaxBoneRatio,
Bone = bone,
KillCount = Kills
};
}
}
#endregion
}
#region CHEST_ABDOMEN_RATIO_SESSION
int chestKills = HitLocationCount[IW4Info.HitLocation.torso_upper];
if (chestKills >= Thresholds.MediumSampleMinKills)
{
double marginOfError = Thresholds.GetMarginOfError(chestKills);
double lerpAmount = Math.Min(1.0, (chestKills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills));
// determine max acceptable ratio of chest to abdomen kills
double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(3), Thresholds.ChestAbdomenRatioThresholdHighSample(3), lerpAmount) + marginOfError;
double chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(4), Thresholds.ChestAbdomenRatioThresholdHighSample(4), lerpAmount) + marginOfError;
double currentChestAbdomenRatio = HitLocationCount[IW4Info.HitLocation.torso_upper] / (double)HitLocationCount[IW4Info.HitLocation.torso_lower];
if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag)
{
if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan && chestKills >= Thresholds.MediumSampleMinKills + 30)
{
Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Ban**");
Log.WriteDebug($"ClientId: {kill.AttackerId}");
Log.WriteDebug($"**Chest Kills: {chestKills}");
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
Log.WriteDebug($"**MaxRatio {chestAbdomenLerpValueForBan}");
var sb = new StringBuilder();
foreach (var kvp in HitLocationCount)
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
Log.WriteDebug(sb.ToString());
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Ban,
RatioAmount = currentChestAbdomenRatio,
Bone = 0,
KillCount = chestKills
};
}
else
{
Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Flag**");
Log.WriteDebug($"ClientId: {kill.AttackerId}");
Log.WriteDebug($"**Chest Kills: {chestKills}");
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
Log.WriteDebug($"**MaxRatio {chestAbdomenRatioLerpValueForFlag}");
var sb = new StringBuilder();
foreach (var kvp in HitLocationCount)
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
Log.WriteDebug(sb.ToString());
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Flag,
RatioAmount = currentChestAbdomenRatio,
Bone = 0,
KillCount = chestKills
};
}
}
}
#endregion
#endregion
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Ban,
RatioAmount = currentHeadshotRatio,
Bone = IW4Info.HitLocation.head,
KillCount = Kills
ClientPenalty = Penalty.PenaltyType.Any,
RatioAmount = 0
};
}
else
public DetectionPenaltyResult ProcessTotalRatio(EFClientStatistics stats)
{
AboveThresholdCount++;
Log.WriteDebug("**Maximum Headshot Ratio Reached For Flag**");
Log.WriteDebug($"ClientId: {kill.AttackerId}");
Log.WriteDebug($"**Kills: {Kills}");
Log.WriteDebug($"**Ratio {currentHeadshotRatio}");
Log.WriteDebug($"**MaxRatio {maxHeadshotLerpValueForFlag}");
var sb = new StringBuilder();
foreach (var kvp in HitLocationCount)
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
Log.WriteDebug(sb.ToString());
Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
int totalChestKills = stats.HitLocations.Single(c => c.Location == IW4Info.HitLocation.left_arm_upper).HitCount;
return new DetectionPenaltyResult()
if (totalChestKills >= 250)
{
ClientPenalty = Penalty.PenaltyType.Flag,
RatioAmount = currentHeadshotRatio,
Bone = IW4Info.HitLocation.head,
KillCount = Kills
};
}
}
#endregion
#region BONE_RATIO
// flag on bone ratio
else if (currentMaxBoneRatio > maxBoneRatioLerpValueForFlag)
{
// ban on bone ratio
if (currentMaxBoneRatio > maxBoneRatioLerpValueForBan)
{
Log.WriteDebug("**Maximum Bone Ratio Reached For Ban**");
Log.WriteDebug($"ClientId: {kill.AttackerId}");
Log.WriteDebug($"**Kills: {Kills}");
Log.WriteDebug($"**Ratio {currentMaxBoneRatio}");
Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValueForBan}");
var sb = new StringBuilder();
foreach (var kvp in HitLocationCount)
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
Log.WriteDebug(sb.ToString());
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Ban,
RatioAmount = currentMaxBoneRatio,
Bone = bone,
KillCount = Kills
};
}
else
{
Log.WriteDebug("**Maximum Bone Ratio Reached For Flag**");
Log.WriteDebug($"ClientId: {kill.AttackerId}");
Log.WriteDebug($"**Kills: {Kills}");
Log.WriteDebug($"**Ratio {currentMaxBoneRatio}");
Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValueForFlag}");
var sb = new StringBuilder();
foreach (var kvp in HitLocationCount)
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
Log.WriteDebug(sb.ToString());
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Flag,
RatioAmount = currentMaxBoneRatio,
Bone = bone,
KillCount = Kills
};
}
}
#endregion
}
#region CHEST_ABDOMEN_RATIO_SESSION
int chestKills = HitLocationCount[IW4Info.HitLocation.torso_upper];
if (chestKills >= Thresholds.MediumSampleMinKills)
{
double marginOfError = Thresholds.GetMarginOfError(chestKills);
double lerpAmount = Math.Min(1.0, (chestKills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills));
// determine max acceptable ratio of chest to abdomen kills
double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(3), Thresholds.ChestAbdomenRatioThresholdHighSample(3), lerpAmount) + marginOfError;
double chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(4), Thresholds.ChestAbdomenRatioThresholdHighSample(4), lerpAmount) + marginOfError;
double currentChestAbdomenRatio = HitLocationCount[IW4Info.HitLocation.torso_upper] / (double)HitLocationCount[IW4Info.HitLocation.torso_lower];
if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag)
{
if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan && chestKills >= Thresholds.MediumSampleMinKills + 30)
{
Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Ban**");
Log.WriteDebug($"ClientId: {kill.AttackerId}");
Log.WriteDebug($"**Chest Kills: {chestKills}");
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
Log.WriteDebug($"**MaxRatio {chestAbdomenLerpValueForBan}");
var sb = new StringBuilder();
foreach (var kvp in HitLocationCount)
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
Log.WriteDebug(sb.ToString());
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Ban,
RatioAmount = currentChestAbdomenRatio,
Bone = 0,
KillCount = chestKills
};
}
else
{
Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Flag**");
Log.WriteDebug($"ClientId: {kill.AttackerId}");
Log.WriteDebug($"**Chest Kills: {chestKills}");
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
Log.WriteDebug($"**MaxRatio {chestAbdomenRatioLerpValueForFlag}");
var sb = new StringBuilder();
foreach (var kvp in HitLocationCount)
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
Log.WriteDebug(sb.ToString());
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Flag,
RatioAmount = currentChestAbdomenRatio,
Bone = 0,
KillCount = chestKills
};
}
}
}
#endregion
#endregion
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Any,
RatioAmount = 0
};
}
public DetectionPenaltyResult ProcessTotalRatio(EFClientStatistics stats)
{
int totalChestKills = stats.HitLocations.Single(c => c.Location == IW4Info.HitLocation.left_arm_upper).HitCount;
if (totalChestKills >= 250)
{
double marginOfError = Thresholds.GetMarginOfError(totalChestKills);
double lerpAmount = Math.Min(1.0, (totalChestKills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills));
// determine max acceptable ratio of chest to abdomen kills
double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(2.25), Thresholds.ChestAbdomenRatioThresholdHighSample(2.25), lerpAmount) + marginOfError;
double chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(3.0), Thresholds.ChestAbdomenRatioThresholdHighSample(3.0), lerpAmount) + marginOfError;
double marginOfError = Thresholds.GetMarginOfError(totalChestKills);
double lerpAmount = Math.Min(1.0, (totalChestKills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills));
// determine max acceptable ratio of chest to abdomen kills
double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(2.25), Thresholds.ChestAbdomenRatioThresholdHighSample(2.25), lerpAmount) + marginOfError;
double chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(3.0), Thresholds.ChestAbdomenRatioThresholdHighSample(3.0), lerpAmount) + marginOfError;
double currentChestAbdomenRatio = stats.HitLocations.Single(hl => hl.Location == IW4Info.HitLocation.torso_upper).HitCount /
stats.HitLocations.Single(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount;
if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag)
{
if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag)
{
if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan)
{
Log.WriteDebug("**Maximum Lifetime Chest/Abdomen Ratio Reached For Ban**");
Log.WriteDebug($"ClientId: {stats.ClientId}");
Log.WriteDebug($"**Total Chest Kills: {totalChestKills}");
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
Log.WriteDebug($"**MaxRatio {chestAbdomenLerpValueForBan}");
var sb = new StringBuilder();
foreach (var location in stats.HitLocations)
sb.Append($"HitLocation: {location.Location} -> {location.HitCount}\r\n");
Log.WriteDebug(sb.ToString());
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan)
{
Log.WriteDebug("**Maximum Lifetime Chest/Abdomen Ratio Reached For Ban**");
Log.WriteDebug($"ClientId: {stats.ClientId}");
Log.WriteDebug($"**Total Chest Kills: {totalChestKills}");
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
Log.WriteDebug($"**MaxRatio {chestAbdomenLerpValueForBan}");
var sb = new StringBuilder();
foreach (var location in stats.HitLocations)
sb.Append($"HitLocation: {location.Location} -> {location.HitCount}\r\n");
Log.WriteDebug(sb.ToString());
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Ban,
RatioAmount = currentChestAbdomenRatio,
Bone = IW4Info.HitLocation.torso_upper,
KillCount = totalChestKills
};
}
else
{
Log.WriteDebug("**Maximum Lifetime Chest/Abdomen Ratio Reached For Flag**");
Log.WriteDebug($"ClientId: {stats.ClientId}");
Log.WriteDebug($"**Total Chest Kills: {totalChestKills}");
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
Log.WriteDebug($"**MaxRatio {chestAbdomenRatioLerpValueForFlag}");
var sb = new StringBuilder();
foreach (var location in stats.HitLocations)
sb.Append($"HitLocation: {location.Location} -> {location.HitCount}\r\n");
Log.WriteDebug(sb.ToString());
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Flag,
RatioAmount = currentChestAbdomenRatio,
Bone = IW4Info.HitLocation.torso_upper,
KillCount = totalChestKills
};
}
}
}
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Ban,
RatioAmount = currentChestAbdomenRatio,
Bone = IW4Info.HitLocation.torso_upper,
KillCount = totalChestKills
};
}
else
{
Log.WriteDebug("**Maximum Lifetime Chest/Abdomen Ratio Reached For Flag**");
Log.WriteDebug($"ClientId: {stats.ClientId}");
Log.WriteDebug($"**Total Chest Kills: {totalChestKills}");
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
Log.WriteDebug($"**MaxRatio {chestAbdomenRatioLerpValueForFlag}");
var sb = new StringBuilder();
foreach (var location in stats.HitLocations)
sb.Append($"HitLocation: {location.Location} -> {location.HitCount}\r\n");
Log.WriteDebug(sb.ToString());
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
return new DetectionPenaltyResult()
{
ClientPenalty = Penalty.PenaltyType.Flag,
RatioAmount = currentChestAbdomenRatio,
Bone = IW4Info.HitLocation.torso_upper,
KillCount = totalChestKills
Bone = IW4Info.HitLocation.none,
ClientPenalty = Penalty.PenaltyType.Any
};
}
}
}
return new DetectionPenaltyResult()
{
Bone = IW4Info.HitLocation.none,
ClientPenalty = Penalty.PenaltyType.Any
};
}
}
}

View File

@ -380,7 +380,7 @@ namespace StatsPlugin.Helpers
double timeSinceLastActive = (DateTime.UtcNow - clientStats.LastActive).TotalSeconds / 60.0;
// prevent NaN or inactive time lowering SPM
if (timeSinceLastCalc == 0 || timeSinceLastActive > 3)
if (timeSinceLastCalc == 0 || timeSinceLastActive > 3 || clientStats.SPM < 1)
return clientStats;
// calculate the players Score Per Minute for the current session
@ -403,6 +403,9 @@ namespace StatsPlugin.Helpers
// calculate the new weight against average times the weight against play time
clientStats.SPM = (killSPM * SPMAgainstPlayWeight) + (clientStats.SPM * (1 - SPMAgainstPlayWeight));
// fixme: how does this happen?
if (clientStats.SPM == double.NaN)
clientStats.SPM = 0;
clientStats.SPM = Math.Round(clientStats.SPM, 3);
clientStats.Skill = Math.Round((clientStats.SPM * KDRWeight), 3);

View File

@ -105,6 +105,41 @@ namespace StatsPlugin
double skill = Math.Round(clientStats.Sum(c => c.Skill) / clientStats.Count, 2);
double spm = Math.Round(clientStats.Sum(c => c.SPM), 1);
return new List<ProfileMeta>()
{
new ProfileMeta()
{
Key = "Kills",
Value = kills
},
new ProfileMeta()
{
Key = "Deaths",
Value = deaths
},
new ProfileMeta()
{
Key = "KDR",
Value = kdr
},
new ProfileMeta()
{
Key = "Skill",
Value = skill
},
new ProfileMeta()
{
Key = "Score Per Minute",
Value = spm
}
};
}
async Task<List<ProfileMeta>> getAnticheatInfo(int clientId)
{
var statsSvc = new GenericRepository<EFClientStatistics>();
var clientStats = await statsSvc.FindAsync(c => c.ClientId == clientId);
double headRatio = 0;
double chestRatio = 0;
double abdomenRatio = 0;
@ -134,61 +169,36 @@ namespace StatsPlugin
return new List<ProfileMeta>()
{
new ProfileMeta()
{
Key = "Kills",
Value = kills
},
new ProfileMeta()
{
Key = "Deaths",
Value = deaths
},
new ProfileMeta()
{
Key = "KDR",
Value = kdr
},
new ProfileMeta()
{
Key = "Skill",
Value = skill
},
new ProfileMeta()
{
Key = "Score Per Minute",
Value = spm
},
new ProfileMeta()
{
Key = "Chest Ratio",
Value = chestRatio,
Sensitive = true
},
new ProfileMeta()
{
Key = "Abdomen Ratio",
Value = abdomenRatio,
Sensitive = true
},
new ProfileMeta()
{
Key = "Chest To Abdomen Ratio",
Value = chestAbdomenRatio,
Sensitive = true
},
new ProfileMeta()
{
Key = "Headshot Ratio",
Value = headRatio,
Sensitive = true
},
new ProfileMeta()
{
Key = "Hit Offset Average",
Value = $"{Math.Round(((float)hitOffsetAverage).ToDegrees(), 4)}°",
Sensitive = true
}
new ProfileMeta()
{
Key = "Chest Ratio",
Value = chestRatio,
Sensitive = true
},
new ProfileMeta()
{
Key = "Abdomen Ratio",
Value = abdomenRatio,
Sensitive = true
},
new ProfileMeta()
{
Key = "Chest To Abdomen Ratio",
Value = chestAbdomenRatio,
Sensitive = true
},
new ProfileMeta()
{
Key = "Headshot Ratio",
Value = headRatio,
Sensitive = true
},
new ProfileMeta()
{
Key = "Hit Offset Average",
Value = $"{Math.Round(((float)hitOffsetAverage).ToDegrees(), 4)}°",
Sensitive = true
}
};
}
@ -211,10 +221,13 @@ namespace StatsPlugin
return messageMeta;
}
MetaService.AddMeta(getStats);
if (Config.Configuration().EnableAntiCheat)
{
MetaService.AddMeta(getStats);
MetaService.AddMeta(getAnticheatInfo);
}
MetaService.AddMeta(getMessages);
// todo: is this fast? make async?
@ -240,10 +253,7 @@ namespace StatsPlugin
Manager = new StatManager(manager);
}
public async Task OnTickAsync(Server S)
{
}
public Task OnTickAsync(Server S) => Utilities.CompletedTask;
public async Task OnUnloadAsync()
{

View File

@ -75,13 +75,9 @@ namespace Welcome_Plugin
}
}
public async Task OnUnloadAsync()
{
}
public Task OnUnloadAsync() => Utilities.CompletedTask;
public async Task OnTickAsync(Server S)
{
}
public Task OnTickAsync(Server S) => Utilities.CompletedTask;
public async Task OnEventAsync(Event E, Server S)
{

View File

@ -457,6 +457,16 @@ namespace SharedLibrary.Commands
await E.Owner.Manager.GetClientService().Update(E.Target);
}
try
{
E.Owner.Manager.GetPrivilegedClients().Add(E.Target.ClientId, E.Target);
}
catch (Exception)
{
E.Owner.Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target;
}
await E.Origin.Tell($"{E.Target.Name} was successfully promoted");
}
@ -989,12 +999,22 @@ namespace SharedLibrary.Commands
public override async Task ExecuteAsync(Event E)
{
if (E.Data.Length < 5)
{
await E.Origin.Tell("Your password must be atleast 5 characters long");
return;
}
string[] hashedPassword = Helpers.Hashing.Hash(E.Data);
E.Origin.Password = hashedPassword[0];
E.Origin.PasswordSalt = hashedPassword[1];
// update the password for the client in privileged
E.Owner.Manager.GetPrivilegedClients()[E.Origin.ClientId] = E.Origin;
await E.Owner.Manager.GetClientService().Update(E.Origin);
await E.Origin.Tell("Your password has been set successfully");
}
}

View File

@ -56,7 +56,18 @@ namespace SharedLibrary.Database
#if !DEBUG
foreach (string dllPath in System.IO.Directory.GetFiles($"{Utilities.OperatingDirectory}Plugins"))
#else
foreach (string dllPath in System.IO.Directory.GetFiles(/*C:\Projects\IW4M - Admin\WebfrontCore */ $@"{Environment.CurrentDirectory}\bin\x86\Debug\Plugins").Where(f => f.Contains(".dll")))
IEnumerable<string> directoryFiles;
try
{
directoryFiles = Directory.GetFiles($@"{Environment.CurrentDirectory}\bin\x86\Debug\Plugins").Where(f => f.Contains(".dll"));
}
catch(Exception)
{
directoryFiles = Directory.GetFiles($@"{Environment.CurrentDirectory}\Plugins").Where(f => f.Contains(".dll"));
}
foreach (string dllPath in directoryFiles)
#endif
{
Assembly library;

View File

@ -2,9 +2,6 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SharedLibrary.Database.Models
{

View File

@ -18,5 +18,6 @@ namespace SharedLibrary.Dtos
public List<PlayerInfo> Players { get; set; }
public Helpers.PlayerHistory[] PlayerHistory { get; set; }
public int ID { get; set; }
public bool Online { get; set; }
}
}

View File

@ -22,5 +22,6 @@ namespace SharedLibrary.Interfaces
ClientService GetClientService();
AliasService GetAliasService();
PenaltyService GetPenaltyService();
IDictionary<int, Player> GetPrivilegedClients();
}
}

View File

@ -19,6 +19,6 @@ namespace SharedLibrary.RCon
}
public static char SeperatorChar = (char)int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
public static readonly TimeSpan SocketTimeout = new TimeSpan(0, 0, 1);
public static readonly TimeSpan SocketTimeout = new TimeSpan(0, 0, 10);
}
}

View File

@ -142,6 +142,7 @@ namespace SharedLibrary
await this.ExecuteCommandAsync($"{sayCommand} {(CustomSayEnabled ? CustomSayName : "")} {Message}");
#else
Logger.WriteVerbose(Message.StripColors());
await Utilities.CompletedTask;
#endif
}
@ -159,6 +160,7 @@ namespace SharedLibrary
await this.ExecuteCommandAsync($"{tellCommand} {Target.ClientNumber} {(CustomSayEnabled ? CustomSayName : "")} {Message}^7");
#else
Logger.WriteVerbose($"{Target.ClientNumber}->{Message.StripColors()}");
await Utilities.CompletedTask;
#endif
if (Target.Level == Player.Permission.Console)

View File

@ -16,8 +16,8 @@ namespace SharedLibrary.Services
{
public async Task<EFAlias> Create(EFAlias entity)
{
throw new Exception();
using (var context = new DatabaseContext())
throw await Task.FromResult(new Exception());
/*using (var context = new DatabaseContext())
{
var alias = new EFAlias()
{
@ -32,7 +32,7 @@ namespace SharedLibrary.Services
context.Aliases.Add(entity);
await context.SaveChangesAsync();
return entity;
}
}*/
}
public Task<EFAlias> CreateProxy()
@ -80,14 +80,14 @@ namespace SharedLibrary.Services
public async Task<EFAlias> Update(EFAlias entity)
{
throw new Exception();
using (var context = new DatabaseContext())
throw await Task.FromResult(new Exception());
/*using (var context = new DatabaseContext())
{
entity = context.Aliases.Attach(entity);
context.Entry(entity).State = EntityState.Modified;
await context.SaveChangesAsync();
return entity;
}
}*/
}
public async Task<EFAliasLink> CreateLink(EFAliasLink link)

View File

@ -59,6 +59,8 @@ namespace SharedLibrary.Services
public async Task<IList<EFPenalty>> Find(Func<EFPenalty, bool> expression)
{
throw await Task.FromResult(new Exception());
/*
return await Task.FromResult(new List<EFPenalty>());
// fixme: this is so slow!
return await Task.Run(() =>
@ -70,7 +72,7 @@ namespace SharedLibrary.Services
.Where(expression)
.Where(p => p.Active)
.ToList();
});
});*/
}
public Task<EFPenalty> Get(int entityID)

View File

@ -20,6 +20,7 @@ namespace SharedLibrary
public static class Utilities
{
public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar;
public static readonly Task CompletedTask = Task.FromResult(false);
//Get string with specified number of spaces -- really only for visual output
public static String GetSpaces(int Num)
@ -52,7 +53,7 @@ namespace SharedLibrary
return newStr;
}
public static List<Player> PlayersFromStatus(String[] Status)
public static List<Player> PlayersFromStatus(string[] Status)
{
List<Player> StatusPlayers = new List<Player>();

View File

@ -40,7 +40,7 @@ namespace IW4MAdmin
if (type == LogType.Error || type == LogType.Verbose)
Console.WriteLine(LogLine);
//if (type != LogType.Debug)
File.AppendAllText(FileName, LogLine + Environment.NewLine);
File.AppendAllText(FileName, $"{LogLine}{Environment.NewLine}");
#endif
}
}

View File

@ -57,8 +57,15 @@ namespace IW4MAdmin
PrivilegedClients = new Dictionary<int, Player>();
ServerEventOccurred += EventAPI.OnServerEventOccurred;
ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings");
Console.CancelKeyPress += new ConsoleCancelEventHandler(OnCancelKey);
}
private void OnCancelKey(object sender, ConsoleCancelEventArgs args)
{
Stop();
}
public IList<Server> GetServers()
{
return Servers;
@ -305,5 +312,7 @@ namespace IW4MAdmin
public PenaltyService GetPenaltyService() => PenaltySvc;
public IConfigurationHandler<ApplicationConfiguration> GetApplicationSettings() => ConfigHandler;
public IDictionary<int, Player> GetPrivilegedClients() => PrivilegedClients;
}
}

View File

@ -788,7 +788,7 @@ namespace IW4MAdmin
CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname };
// todo: make this more efficient
((ApplicationManager)(Manager)).PrivilegedClients = new Dictionary<int, Player>();
/*((ApplicationManager)(Manager)).PrivilegedClients = new Dictionary<int, Player>();
var ClientSvc = new ClientService();
var ipList = (await ClientSvc.Find(c => c.Level > Player.Permission.Trusted))
.Select(c => new
@ -818,7 +818,7 @@ namespace IW4MAdmin
{
continue;
}
}
}*/
}
if (E.Type == Event.GType.MapEnd)

View File

@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Cookies;
using System.Security.Claims;
using System;
namespace WebfrontCore.Controllers
{
@ -15,23 +16,37 @@ namespace WebfrontCore.Controllers
return Unauthorized();
}
var client = IW4MAdmin.Program.ServerManager.PrivilegedClients[userId];
string[] hashedPassword = await Task.FromResult(SharedLibrary.Helpers.Hashing.Hash(password, client.PasswordSalt));
if (hashedPassword[0] == client.Password)
try
{
var claims = new[]
var client = IW4MAdmin.Program.ServerManager.PrivilegedClients[userId];
string[] hashedPassword = await Task.FromResult(SharedLibrary.Helpers.Hashing.Hash(password, client.PasswordSalt));
if (hashedPassword[0] == client.Password)
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, client.Name),
new Claim(ClaimTypes.Role, client.Level.ToString()),
new Claim(ClaimTypes.Sid, client.ClientId.ToString())
};
var claimsIdentity = new ClaimsIdentity(claims, "login");
var claimsPrinciple = new ClaimsPrincipal(claimsIdentity);
await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrinciple);
var claimsIdentity = new ClaimsIdentity(claims, "login");
var claimsPrinciple = new ClaimsPrincipal(claimsIdentity);
await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrinciple, new Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties()
{
AllowRefresh = true,
ExpiresUtc = DateTime.UtcNow.AddDays(30),
IsPersistent = true,
IssuedUtc = DateTime.UtcNow
});
return Ok();
return Ok();
}
}
catch (Exception)
{
return Unauthorized();
}
return Unauthorized();

View File

@ -82,7 +82,7 @@ namespace WebfrontCore.Controllers
{
new InputInfo()
{
Name = "UserID"
Name = "User ID"
},
new InputInfo()
{

View File

@ -30,8 +30,12 @@ namespace WebfrontCore.Controllers
{
var server = Manager.Servers.First(s => s.GetHashCode() == serverId);
var client = User.AsPlayer();
client.CurrentServer = server;
var client = new Player()
{
ClientId = User.ClientId,
Level = User.Level,
CurrentServer = server
};
var remoteEvent = new Event(Event.GType.Say, command, client, null, server);

View File

@ -35,7 +35,7 @@ namespace WebfrontCore.Controllers
LevelInt = (int)p.Level
}).ToList(),
ChatHistory = s.ChatHistory.OrderBy(c => c.Time).Take((int)Math.Ceiling(s.ClientNum / 2.0)).ToArray(),
PlayerHistory = s.PlayerHistory.ToArray()
PlayerHistory = s.PlayerHistory.ToArray(),
};
return PartialView("_ClientActivity", serverInfo);
}

View File

@ -55,7 +55,8 @@ namespace WebfrontCore
AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme,
AutomaticAuthenticate = true,
AutomaticChallenge = true,
LoginPath = "/Account/Login/"
LoginPath = "/Account/Login/",
ExpireTimeSpan = TimeSpan.FromDays(30),
});
app.UseMvc(routes =>
@ -65,7 +66,6 @@ namespace WebfrontCore
template: "{controller=Home}/{action=Index}/{id?}");
});
//app.UseBasicAuthentication(Authentication.Basic.Generate());
}
}
}

View File

@ -30,7 +30,8 @@ namespace WebfrontCore.ViewComponents
Level = p.Level.ToString(),
LevelInt = (int)p.Level
}).ToList(),
ChatHistory = s.ChatHistory.ToArray()
ChatHistory = s.ChatHistory.ToArray(),
Online = !s.Throttled
}).ToList();
return View("_List", serverInfo);
}

View File

@ -17,5 +17,5 @@
</div>
<div class="row server-history mb-4">
<div class="server-history-row col-md-12" id="server_history_@Model.ID" data-serverid="@Model.ID" data-clienthistory='@Html.Raw(Json.Serialize(Model.PlayerHistory))'></div>
<div class="server-history-row col-md-12" id="server_history_@Model.ID" data-serverid="@Model.ID" data-clienthistory='@Html.Raw(Json.Serialize(Model.PlayerHistory))' data-online="@Model.Online"></div>
</div>

View File

@ -44,7 +44,6 @@
}
else
{
<li class="nav-item text-center text-md-left"><a href="#" id="profile_action_login_btn" class="nav-link profile-action oi oi-key oi-fix-navbar w-100" title="Login" data-action="login" aria-hidden="true"></a></li>
}
</ul>
@ -82,6 +81,8 @@
</button>
</div>
<div class="modal-body">
<div class="modal-message text-danger mb-3"></div>
<div class="modal-body-content"></div>
</div>
<!--<div class="modal-footer">
<button type="button" class="btn btn-primary">Action</button>

View File

@ -3,58 +3,72 @@
}
.level-color-user, .level-color-guest {
color: #fff;
color: rgba(255, 255, 255, 0.7);
}
.level-bgcolor-user, .level-bgcolor-guest {
background-color: #fff;
background-color: rgba(255, 255, 255, 0.85);
}
.level-color-trusted {
color: #749363;
color: rgba(116,147,99,1);
}
.level-bgcolor-trusted, .level-bgcolor-user {
.level-bgcolor-trusted {
background-color: #749363;
background-color: rgba(116,147,99,1);
}
.level-color-flagged {
color: #fd9c38;
color: rgba(253, 139, 22, 0.85);
}
.level-bgcolor-flagged {
background-color: #fd9c38;
background-color: rgba(253, 139, 22, 0.85);
}
.level-color-banned, .level-color-console {
color: #ff6060;
color: rgba(255, 69, 69, 0.85);
}
.level-bgcolor-banned {
background-color: #ff6060;
background-color: rgba(255, 69, 69, 0.85);
}
.level-color-moderator {
color: #f0de8b;
color: rgba(235, 211, 101, 0.75);
}
.level-bgcolor-moderator {
background-color: #f0de8b;
background-color: rgba(235, 211, 101, 0.75);
}
.level-color-administrator {
color: #f1a8e8;
color: rgba(236, 130, 222, 0.69);
}
.level-bgcolor-administrator {
background-color: #f1a8e8;
background-color: rgba(236, 130, 222, 0.69);
}
.level-color-senioradmin {
color: #50bcc3;
color: rgba(50, 177, 185, 0.85);
}
.level-bgcolor-senioradmin {
background-color: #50bcc3;
background-color: rgba(50, 177, 185, 0.85);
}
@ -72,26 +86,32 @@
.penalties-color-kick,
.penalties-color-unban {
color: #749363;
color: rgba(116, 147, 99, 1);
}
.penalties-color-report {
color: #749363;
color: rgba(116, 147, 99, 1);
}
.penalties-color-warning {
color: #f0de8b;
color: rgba(235, 211, 101, 0.75);
}
.penalties-color-tempban {
color: #fd9c38;
color: rgba(253, 139, 22, 0.85);
}
.penalties-color-flag {
color: #fd9c38;
color: rgba(253, 139, 22, 0.85);
}
.penalties-color-ban {
color: #ff6060;
color: rgba(255, 69, 69, 0.85);
}
@ -122,6 +142,7 @@
}
#profile_level > span.level {
color: #f1a8e8;
color: rgba(236, 130, 222, 0.69);
font-weight: bold;
font-size: 1.5em;
@ -137,6 +158,7 @@
}
#profile_level > span.level {
color: #f1a8e8;
color: rgba(236, 130, 222, 0.69);
font-weight: bold;
}

Binary file not shown.

View File

@ -6,12 +6,14 @@
const actionType = $(this).data('action');
$.get('/Action/' + actionType + 'Form')
.done(function (response) {
$('#actionModal .modal-body').html(response);
$('#actionModal .modal-message').fadeOut('fast');
$('#actionModal .modal-body-content').html(response);
$('#actionModal').modal();
})
.fail(function (jqxhr, textStatus, error) {
$('#actionModal .modal-body').html('<span class="text-danger">' + error + '</span>');
$('#actionModal .modal-message').text('Error &mdash ' + error);
$('#actionModal').modal();
$('#actionModal .modal-message').fadeIn('fast');
});
});
@ -29,18 +31,22 @@
location.reload();
}
else {
$('#actionModal .modal-body').html(response);
$('#actionModal .modal-message').fadeOut('fast');
$('#actionModal .modal-body-content').html(response);
$('#actionModal').modal();
}
})
.fail(function (jqxhr, textStatus, error) {
if (jqxhr.status == 401) {
$('#actionModal .modal-body').removeClass('text-danger');
$('#actionModal .modal-body').prepend('<div class="text-danger mb-3">Invalid login credentials</div>');
if ($('#actionModal .modal-message').text.length > 0) {
$('#actionModal .modal-message').fadeOut('fast');
}
if (jqxhr.status === 401) {
$('#actionModal .modal-message').text('Invalid login credentials');
}
else {
$('#actionModal .modal-body').html('<span class="text-danger">Error &mdash; ' + error + '</span>');
$('#actionModal .modal-message').text('Error &mdash; ' + error);
}
$('#actionModal .modal-message').fadeIn('fast');
});
});
});

View File

@ -1,4 +1,4 @@
function getPlayerHistoryChart(playerHistory, i, width) {
function getPlayerHistoryChart(playerHistory, i, width, color) {
///////////////////////////////////////
// thanks to canvasjs :(
playerHistory.forEach(function (item, i) {
@ -6,7 +6,7 @@
});
return new CanvasJS.Chart(`server_history_${i}`, {
backgroundColor: "#191919",
backgroundColor: '#191919',
height: 100,
width: width,
animationEnabled: true,
@ -41,7 +41,7 @@
data: [{
showInLegend: false,
type: "splineArea",
color: "rgba(0, 122, 204, 0.432)",
color: color,
markerSize: 0,
dataPoints: playerHistory
}]
@ -53,8 +53,9 @@ var charts = {};
$('.server-history-row').each(function (index, element) {
let clientHistory = $(this).data('clienthistory');
let serverId = $(this).data('serverid');
let color = $(this).data('online') === 'True' ? '#007acc' : '#ff6060'
let width = $('.server-header').first().width();
let historyChart = getPlayerHistoryChart(clientHistory, serverId, width);
let historyChart = getPlayerHistoryChart(clientHistory, serverId, width, color);
historyChart.render();
charts[serverId] = historyChart;
});