Small anti-cheat update
This commit is contained in:
parent
1779bf821d
commit
d9d548ea18
@ -46,40 +46,40 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Analyze kill and see if performed by a cheater
|
/// Analyze kill and see if performed by a cheater
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="kill">kill performed by the player</param>
|
/// <param name="hit">kill performed by the player</param>
|
||||||
/// <returns>true if detection reached thresholds, false otherwise</returns>
|
/// <returns>true if detection reached thresholds, false otherwise</returns>
|
||||||
public DetectionPenaltyResult ProcessKill(EFClientKill kill, bool isDamage)
|
public DetectionPenaltyResult ProcessHit(EFClientKill hit, bool isDamage)
|
||||||
{
|
{
|
||||||
if ((kill.DeathType != IW4Info.MeansOfDeath.MOD_PISTOL_BULLET &&
|
if ((hit.DeathType != IW4Info.MeansOfDeath.MOD_PISTOL_BULLET &&
|
||||||
kill.DeathType != IW4Info.MeansOfDeath.MOD_RIFLE_BULLET &&
|
hit.DeathType != IW4Info.MeansOfDeath.MOD_RIFLE_BULLET &&
|
||||||
kill.DeathType != IW4Info.MeansOfDeath.MOD_HEAD_SHOT) ||
|
hit.DeathType != IW4Info.MeansOfDeath.MOD_HEAD_SHOT) ||
|
||||||
kill.HitLoc == IW4Info.HitLocation.none || kill.TimeOffset - LastOffset < 0 ||
|
hit.HitLoc == IW4Info.HitLocation.none || hit.TimeOffset - LastOffset < 0 ||
|
||||||
// hack: prevents false positives
|
// hack: prevents false positives
|
||||||
(LastWeapon != kill.Weapon && (kill.TimeOffset - LastOffset) == 50))
|
(LastWeapon != hit.Weapon && (hit.TimeOffset - LastOffset) == 50))
|
||||||
return new DetectionPenaltyResult()
|
return new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Any,
|
ClientPenalty = Penalty.PenaltyType.Any,
|
||||||
};
|
};
|
||||||
|
|
||||||
DetectionPenaltyResult result = null;
|
DetectionPenaltyResult result = null;
|
||||||
LastWeapon = kill.Weapon;
|
LastWeapon = hit.Weapon;
|
||||||
|
|
||||||
|
HitLocationCount[hit.HitLoc]++;
|
||||||
|
HitCount++;
|
||||||
|
|
||||||
HitLocationCount[kill.HitLoc]++;
|
|
||||||
if (!isDamage)
|
if (!isDamage)
|
||||||
{
|
{
|
||||||
Kills++;
|
Kills++;
|
||||||
}
|
}
|
||||||
|
|
||||||
HitCount++;
|
|
||||||
|
|
||||||
#region VIEWANGLES
|
#region VIEWANGLES
|
||||||
if (kill.AnglesList.Count >= 2)
|
if (hit.AnglesList.Count >= 2)
|
||||||
{
|
{
|
||||||
double realAgainstPredict = Vector3.ViewAngleDistance(kill.AnglesList[0], kill.AnglesList[1], kill.ViewAngles);
|
double realAgainstPredict = Vector3.ViewAngleDistance(hit.AnglesList[0], hit.AnglesList[1], hit.ViewAngles);
|
||||||
|
|
||||||
// LIFETIME
|
// LIFETIME
|
||||||
var hitLoc = ClientStats.HitLocations
|
var hitLoc = ClientStats.HitLocations
|
||||||
.First(hl => hl.Location == kill.HitLoc);
|
.First(hl => hl.Location == hit.HitLoc);
|
||||||
|
|
||||||
float previousAverage = hitLoc.HitOffsetAverage;
|
float previousAverage = hitLoc.HitOffsetAverage;
|
||||||
double newAverage = (previousAverage * (hitLoc.HitCount - 1) + realAgainstPredict) / hitLoc.HitCount;
|
double newAverage = (previousAverage * (hitLoc.HitCount - 1) + realAgainstPredict) / hitLoc.HitCount;
|
||||||
@ -88,11 +88,11 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
if (hitLoc.HitOffsetAverage > Thresholds.MaxOffset(hitLoc.HitCount) &&
|
if (hitLoc.HitOffsetAverage > Thresholds.MaxOffset(hitLoc.HitCount) &&
|
||||||
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 = {kill.AttackerId}");
|
//Log.WriteDebug($"ID = {hit.AttackerId}");
|
||||||
|
|
||||||
result = new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
@ -110,10 +110,10 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
if (sessAverage > Thresholds.MaxOffset(HitCount) &&
|
if (sessAverage > Thresholds.MaxOffset(HitCount) &&
|
||||||
HitCount > 30)
|
HitCount > 30)
|
||||||
{
|
{
|
||||||
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 = {sessAverage}");
|
||||||
Log.WriteDebug($"HitCount = {HitCount}");
|
//Log.WriteDebug($"HitCount = {HitCount}");
|
||||||
Log.WriteDebug($"ID = {kill.AttackerId}");
|
//Log.WriteDebug($"ID = {hit.AttackerId}");
|
||||||
|
|
||||||
result = new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
@ -130,17 +130,20 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
double currentStrain = Strain.GetStrain(isDamage, kill.Damage, kill.Distance / 0.0254, kill.ViewAngles, Math.Max(50, kill.TimeOffset - LastOffset));
|
double currentStrain = Strain.GetStrain(isDamage, hit.Damage, hit.Distance / 0.0254, hit.ViewAngles, Math.Max(50, hit.TimeOffset - LastOffset));
|
||||||
LastOffset = kill.TimeOffset;
|
#if DEBUG == true
|
||||||
|
Log.WriteDebug($"Current Strain: {currentStrain}");
|
||||||
|
#endif
|
||||||
|
LastOffset = hit.TimeOffset;
|
||||||
|
|
||||||
if (currentStrain > ClientStats.MaxStrain)
|
if (currentStrain > ClientStats.MaxStrain)
|
||||||
{
|
{
|
||||||
ClientStats.MaxStrain = currentStrain;
|
ClientStats.MaxStrain = currentStrain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// flag
|
// flag
|
||||||
if (currentStrain > Thresholds.MaxStrainFlag &&
|
if (currentStrain > Thresholds.MaxStrainFlag)
|
||||||
HitCount >= 10)
|
|
||||||
{
|
{
|
||||||
result = new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
@ -153,7 +156,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
|
|
||||||
// ban
|
// ban
|
||||||
if (currentStrain > Thresholds.MaxStrainBan &&
|
if (currentStrain > Thresholds.MaxStrainBan &&
|
||||||
HitCount >= 15)
|
HitCount >= 5)
|
||||||
{
|
{
|
||||||
result = new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
@ -163,11 +166,6 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
Type = DetectionType.Strain
|
Type = DetectionType.Strain
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
Log.WriteDebug($"Current Strain: {currentStrain}");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region SESSION_RATIOS
|
#region SESSION_RATIOS
|
||||||
@ -197,7 +195,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
if (currentHeadshotRatio > maxHeadshotLerpValueForBan)
|
if (currentHeadshotRatio > maxHeadshotLerpValueForBan)
|
||||||
{
|
{
|
||||||
Log.WriteDebug("**Maximum Headshot Ratio Reached For Ban**");
|
Log.WriteDebug("**Maximum Headshot Ratio Reached For Ban**");
|
||||||
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
Log.WriteDebug($"ClientId: {hit.AttackerId}");
|
||||||
Log.WriteDebug($"**HitCount: {HitCount}");
|
Log.WriteDebug($"**HitCount: {HitCount}");
|
||||||
Log.WriteDebug($"**Ratio {currentHeadshotRatio}");
|
Log.WriteDebug($"**Ratio {currentHeadshotRatio}");
|
||||||
Log.WriteDebug($"**MaxRatio {maxHeadshotLerpValueForFlag}");
|
Log.WriteDebug($"**MaxRatio {maxHeadshotLerpValueForFlag}");
|
||||||
@ -218,7 +216,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.WriteDebug("**Maximum Headshot Ratio Reached For Flag**");
|
Log.WriteDebug("**Maximum Headshot Ratio Reached For Flag**");
|
||||||
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
Log.WriteDebug($"ClientId: {hit.AttackerId}");
|
||||||
Log.WriteDebug($"**HitCount: {HitCount}");
|
Log.WriteDebug($"**HitCount: {HitCount}");
|
||||||
Log.WriteDebug($"**Ratio {currentHeadshotRatio}");
|
Log.WriteDebug($"**Ratio {currentHeadshotRatio}");
|
||||||
Log.WriteDebug($"**MaxRatio {maxHeadshotLerpValueForFlag}");
|
Log.WriteDebug($"**MaxRatio {maxHeadshotLerpValueForFlag}");
|
||||||
@ -247,7 +245,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
if (currentMaxBoneRatio > maxBoneRatioLerpValueForBan)
|
if (currentMaxBoneRatio > maxBoneRatioLerpValueForBan)
|
||||||
{
|
{
|
||||||
Log.WriteDebug("**Maximum Bone Ratio Reached For Ban**");
|
Log.WriteDebug("**Maximum Bone Ratio Reached For Ban**");
|
||||||
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
Log.WriteDebug($"ClientId: {hit.AttackerId}");
|
||||||
Log.WriteDebug($"**HitCount: {HitCount}");
|
Log.WriteDebug($"**HitCount: {HitCount}");
|
||||||
Log.WriteDebug($"**Ratio {currentMaxBoneRatio}");
|
Log.WriteDebug($"**Ratio {currentMaxBoneRatio}");
|
||||||
Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValueForBan}");
|
Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValueForBan}");
|
||||||
@ -268,7 +266,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.WriteDebug("**Maximum Bone Ratio Reached For Flag**");
|
Log.WriteDebug("**Maximum Bone Ratio Reached For Flag**");
|
||||||
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
Log.WriteDebug($"ClientId: {hit.AttackerId}");
|
||||||
Log.WriteDebug($"**HitCount: {HitCount}");
|
Log.WriteDebug($"**HitCount: {HitCount}");
|
||||||
Log.WriteDebug($"**Ratio {currentMaxBoneRatio}");
|
Log.WriteDebug($"**Ratio {currentMaxBoneRatio}");
|
||||||
Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValueForFlag}");
|
Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValueForFlag}");
|
||||||
@ -309,7 +307,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan && chestHits >= Thresholds.MediumSampleMinKills + 30)
|
if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan && chestHits >= Thresholds.MediumSampleMinKills + 30)
|
||||||
{
|
{
|
||||||
Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Ban**");
|
Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Ban**");
|
||||||
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
Log.WriteDebug($"ClientId: {hit.AttackerId}");
|
||||||
Log.WriteDebug($"**Chest Hits: {chestHits}");
|
Log.WriteDebug($"**Chest Hits: {chestHits}");
|
||||||
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
|
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
|
||||||
Log.WriteDebug($"**MaxRatio {chestAbdomenLerpValueForBan}");
|
Log.WriteDebug($"**MaxRatio {chestAbdomenLerpValueForBan}");
|
||||||
@ -330,7 +328,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Flag**");
|
Log.WriteDebug("**Maximum Chest/Abdomen Ratio Reached For Flag**");
|
||||||
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
Log.WriteDebug($"ClientId: {hit.AttackerId}");
|
||||||
Log.WriteDebug($"**Chest Hits: {chestHits}");
|
Log.WriteDebug($"**Chest Hits: {chestHits}");
|
||||||
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
|
Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}");
|
||||||
Log.WriteDebug($"**MaxRatio {chestAbdomenRatioLerpValueForFlag}");
|
Log.WriteDebug($"**MaxRatio {chestAbdomenRatioLerpValueForFlag}");
|
||||||
@ -356,31 +354,31 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
|
|
||||||
Tracker.OnChange(new EFACSnapshot()
|
Tracker.OnChange(new EFACSnapshot()
|
||||||
{
|
{
|
||||||
When = kill.When,
|
When = hit.When,
|
||||||
ClientId = ClientStats.ClientId,
|
ClientId = ClientStats.ClientId,
|
||||||
SessionAngleOffset = AngleDifferenceAverage,
|
SessionAngleOffset = AngleDifferenceAverage,
|
||||||
CurrentSessionLength = (int)(DateTime.UtcNow - ConnectionTime).TotalSeconds,
|
CurrentSessionLength = (int)(DateTime.UtcNow - ConnectionTime).TotalSeconds,
|
||||||
CurrentStrain = currentStrain,
|
CurrentStrain = currentStrain,
|
||||||
CurrentViewAngle = kill.ViewAngles,
|
CurrentViewAngle = hit.ViewAngles,
|
||||||
Hits = HitCount,
|
Hits = HitCount,
|
||||||
Kills = Kills,
|
Kills = Kills,
|
||||||
Deaths = ClientStats.SessionDeaths,
|
Deaths = ClientStats.SessionDeaths,
|
||||||
HitDestinationId = kill.DeathOrigin.Vector3Id,
|
HitDestinationId = hit.DeathOrigin.Vector3Id,
|
||||||
HitDestination = kill.DeathOrigin,
|
HitDestination = hit.DeathOrigin,
|
||||||
HitOriginId = kill.KillOrigin.Vector3Id,
|
HitOriginId = hit.KillOrigin.Vector3Id,
|
||||||
HitOrigin = kill.KillOrigin,
|
HitOrigin = hit.KillOrigin,
|
||||||
EloRating = ClientStats.EloRating,
|
EloRating = ClientStats.EloRating,
|
||||||
HitLocation = kill.HitLoc,
|
HitLocation = hit.HitLoc,
|
||||||
LastStrainAngle = Strain.LastAngle,
|
LastStrainAngle = Strain.LastAngle,
|
||||||
PredictedViewAngles = kill.AnglesList,
|
PredictedViewAngles = hit.AnglesList,
|
||||||
// this is in "meters"
|
// this is in "meters"
|
||||||
Distance = kill.Distance,
|
Distance = hit.Distance,
|
||||||
SessionScore = ClientStats.SessionScore,
|
SessionScore = ClientStats.SessionScore,
|
||||||
HitType = kill.DeathType,
|
HitType = hit.DeathType,
|
||||||
SessionSPM = ClientStats.SessionSPM,
|
SessionSPM = ClientStats.SessionSPM,
|
||||||
StrainAngleBetween = Strain.LastDistance,
|
StrainAngleBetween = Strain.LastDistance,
|
||||||
TimeSinceLastEvent = (int)Strain.LastDeltaTime,
|
TimeSinceLastEvent = (int)Strain.LastDeltaTime,
|
||||||
WeaponId = kill.Weapon
|
WeaponId = hit.Weapon
|
||||||
});
|
});
|
||||||
|
|
||||||
return result ?? new DetectionPenaltyResult()
|
return result ?? new DetectionPenaltyResult()
|
||||||
|
@ -14,8 +14,6 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
public Vector3 LastAngle { get; private set; }
|
public Vector3 LastAngle { get; private set; }
|
||||||
public double LastDeltaTime { get; private set; }
|
public double LastDeltaTime { get; private set; }
|
||||||
|
|
||||||
public int TimesReachedMaxStrain { get; private set; }
|
|
||||||
|
|
||||||
public double GetStrain(bool isDamage, int damage, double killDistance, Vector3 newAngle, double deltaTime)
|
public double GetStrain(bool isDamage, int damage, double killDistance, Vector3 newAngle, double deltaTime)
|
||||||
{
|
{
|
||||||
if (LastAngle == null)
|
if (LastAngle == null)
|
||||||
@ -33,6 +31,10 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
double[] distance = Helpers.Extensions.AngleStuff(newAngle, LastAngle);
|
double[] distance = Helpers.Extensions.AngleStuff(newAngle, LastAngle);
|
||||||
LastDistance = distance[0] + distance[1];
|
LastDistance = distance[0] + distance[1];
|
||||||
|
|
||||||
|
#if DEBUG == true
|
||||||
|
Console.WriteLine($"Last Distance = {LastDistance}");
|
||||||
|
#endif
|
||||||
|
|
||||||
// this happens on first kill
|
// this happens on first kill
|
||||||
if ((distance[0] == 0 && distance[1] == 0) ||
|
if ((distance[0] == 0 && distance[1] == 0) ||
|
||||||
deltaTime == 0 ||
|
deltaTime == 0 ||
|
||||||
@ -41,14 +43,11 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
return CurrentStrain;
|
return CurrentStrain;
|
||||||
}
|
}
|
||||||
|
|
||||||
double newStrain = Math.Pow(distance[0] + distance[1], 0.99) / deltaTime;
|
double newStrain = Math.Pow(LastDistance, 0.99) / deltaTime;
|
||||||
newStrain *= killDistance / 1000.0;
|
newStrain *= killDistance / 1000.0;
|
||||||
|
|
||||||
CurrentStrain += newStrain;
|
CurrentStrain += newStrain;
|
||||||
|
|
||||||
if (CurrentStrain > Thresholds.MaxStrainBan)
|
|
||||||
TimesReachedMaxStrain++;
|
|
||||||
|
|
||||||
LastAngle = newAngle;
|
LastAngle = newAngle;
|
||||||
return CurrentStrain;
|
return CurrentStrain;
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,8 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
public const int HighSampleMinKills = 100;
|
public const int HighSampleMinKills = 100;
|
||||||
public const double KillTimeThreshold = 0.2;
|
public const double KillTimeThreshold = 0.2;
|
||||||
|
|
||||||
public const double MaxStrainBan = 1.12;
|
public const double MaxStrainBan = 0.9;
|
||||||
|
|
||||||
//=exp((MAX(-3.07+(-3.07/sqrt(J20)),-3.07-(-3.07/sqrt(J20))))+(4*(0.869)))
|
|
||||||
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));
|
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));
|
||||||
public const double MaxStrainFlag = 0.36;
|
public const double MaxStrainFlag = 0.36;
|
||||||
|
|
||||||
|
@ -548,7 +548,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
if (Plugin.Config.Configuration().EnableAntiCheat)
|
if (Plugin.Config.Configuration().EnableAntiCheat)
|
||||||
{
|
{
|
||||||
ApplyPenalty(clientDetection.ProcessKill(hit, isDamage), clientDetection, attacker, ctx);
|
ApplyPenalty(clientDetection.ProcessHit(hit, isDamage), clientDetection, attacker, ctx);
|
||||||
ApplyPenalty(clientDetection.ProcessTotalRatio(clientStats), clientDetection, attacker, ctx);
|
ApplyPenalty(clientDetection.ProcessTotalRatio(clientStats), clientDetection, attacker, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,9 @@ namespace SharedLibraryCore
|
|||||||
{
|
{
|
||||||
string formattedMessage = String.Format(RconParser.GetCommandPrefixes().Say, $"{(CustomSayEnabled ? $"{CustomSayName}: " : "")}{message}");
|
string formattedMessage = String.Format(RconParser.GetCommandPrefixes().Say, $"{(CustomSayEnabled ? $"{CustomSayName}: " : "")}{message}");
|
||||||
|
|
||||||
//Logger.WriteVerbose(message.StripColors());
|
#if DEBUG == true
|
||||||
|
Logger.WriteVerbose(message.StripColors());
|
||||||
|
#endif
|
||||||
|
|
||||||
var e = new GameEvent()
|
var e = new GameEvent()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user