diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs index b74fb4647..79f9e93ab 100644 --- a/Plugins/Stats/Helpers/StatManager.cs +++ b/Plugins/Stats/Helpers/StatManager.cs @@ -399,7 +399,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers /// public async Task AddScriptHit(bool isDamage, DateTime time, EFClient attacker, EFClient victim, long serverId, string map, string hitLoc, string type, string damage, string weapon, string killOrigin, string deathOrigin, string viewAngles, string offset, string isKillstreakKill, string Ads, - string fraction, string visibilityPercentage, string snapAngles) + string fraction, string visibilityPercentage, string snapAngles, string isAlive, string lastAttackTime) { Vector3 vDeathOrigin = null; Vector3 vKillOrigin = null; @@ -448,7 +448,9 @@ namespace IW4MAdmin.Plugins.Stats.Helpers Fraction = double.Parse(fraction, System.Globalization.CultureInfo.InvariantCulture), VisibilityPercentage = double.Parse(visibilityPercentage, System.Globalization.CultureInfo.InvariantCulture), IsKill = !isDamage, - AnglesList = snapshotAngles + AnglesList = snapshotAngles, + IsAlive = isAlive == "1", + TimeSinceLastAttack = long.Parse(lastAttackTime) }; if (hit.HitLoc == IW4Info.HitLocation.shield) @@ -511,7 +513,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers DetectionPenaltyResult result = new DetectionPenaltyResult() { ClientPenalty = EFPenalty.PenaltyType.Any }; clientDetection.TrackedHits.Add(hit); - if (clientDetection.TrackedHits.Count >= Detection.MIN_HITS_TO_RUN_DETECTION) + if (clientDetection.TrackedHits.Count >= MIN_HITS_TO_RUN_DETECTION) { while (clientDetection.TrackedHits.Count > 0) { @@ -521,20 +523,23 @@ namespace IW4MAdmin.Plugins.Stats.Helpers clientDetection.TrackedHits.Remove(oldestHit); - result = clientDetection.ProcessHit(oldestHit, isDamage); + if (oldestHit.IsAlive) + { + result = clientDetection.ProcessHit(oldestHit, isDamage); #if !DEBUG await ApplyPenalty(result, attacker); #endif - if (clientDetection.Tracker.HasChanges && result.ClientPenalty != EFPenalty.PenaltyType.Any) - { - await SaveTrackedSnapshots(clientDetection); - - if (result.ClientPenalty == EFPenalty.PenaltyType.Ban) + if (clientDetection.Tracker.HasChanges && result.ClientPenalty != EFPenalty.PenaltyType.Any) { - // we don't care about any additional hits now that they're banned - clientDetection.TrackedHits.Clear(); - break; + await SaveTrackedSnapshots(clientDetection); + + if (result.ClientPenalty == EFPenalty.PenaltyType.Ban) + { + // we don't care about any additional hits now that they're banned + clientDetection.TrackedHits.Clear(); + break; + } } } } diff --git a/Plugins/Stats/Models/EFClientKill.cs b/Plugins/Stats/Models/EFClientKill.cs index a7c523547..72a58db4c 100644 --- a/Plugins/Stats/Models/EFClientKill.cs +++ b/Plugins/Stats/Models/EFClientKill.cs @@ -44,5 +44,17 @@ namespace IW4MAdmin.Plugins.Stats.Models public float AdsPercent { get; set; } [NotMapped] public List AnglesList { get; set; } + + /// + /// Indicates if the attacker was alive after last captured angle + /// + [NotMapped] + public bool IsAlive { get; set; } + + /// + /// Specifies the last time the attack button was detected as pressed + /// + [NotMapped] + public long TimeSinceLastAttack { get; set; } } } diff --git a/Plugins/Stats/Plugin.cs b/Plugins/Stats/Plugin.cs index bd0604ada..b0fa519f1 100644 --- a/Plugins/Stats/Plugin.cs +++ b/Plugins/Stats/Plugin.cs @@ -82,7 +82,7 @@ namespace IW4MAdmin.Plugins.Stats break; case GameEvent.EventType.ScriptKill: string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0]; - if ((E.Owner.CustomCallback || ShouldOverrideAnticheatSetting(E.Owner)) && killInfo.Length >= 14 && !ShouldIgnoreEvent(E.Origin, E.Target)) + if ((E.Owner.CustomCallback || ShouldOverrideAnticheatSetting(E.Owner)) && killInfo.Length >= 18 && !ShouldIgnoreEvent(E.Origin, E.Target)) { // this treats "world" damage as self damage if (IsWorldDamage(E.Origin)) @@ -96,7 +96,7 @@ namespace IW4MAdmin.Plugins.Stats #endif await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8], - killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]); + killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15], killInfo[16], killInfo[17]); #if DEBUG S.Logger.WriteInfo($"End ScriptKill {scriptKillCount}"); @@ -129,7 +129,7 @@ namespace IW4MAdmin.Plugins.Stats break; case GameEvent.EventType.ScriptDamage: killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0]; - if ((E.Owner.CustomCallback || ShouldOverrideAnticheatSetting(E.Owner)) && killInfo.Length >= 14 && !ShouldIgnoreEvent(E.Origin, E.Target)) + if ((E.Owner.CustomCallback || ShouldOverrideAnticheatSetting(E.Owner)) && killInfo.Length >= 18 && !ShouldIgnoreEvent(E.Origin, E.Target)) { // this treats "world" damage as self damage if (IsWorldDamage(E.Origin)) @@ -143,7 +143,7 @@ namespace IW4MAdmin.Plugins.Stats #endif await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8], - killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]); + killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15], killInfo[16], killInfo[17]); #if DEBUG S.Logger.WriteInfo($"End ScriptDamage {scriptDamageCount}"); diff --git a/_customcallbacks.gsc b/_customcallbacks.gsc index 7220c6949..51301033d 100644 --- a/_customcallbacks.gsc +++ b/_customcallbacks.gsc @@ -32,6 +32,22 @@ onPlayerConnect( player ) player setClientDvar("cl_autorecord", 1); player setClientDvar("cl_demosKeep", 200); player thread waitForFrameThread(); + player thread waitForAttack(); + } +} + +waitForAttack() +{ + self endon( "disconnect" ); + + self.lastAttackTime = 0; + + for( ;; ) + { + self notifyOnPlayerCommand( "player_shot", "+attack" ); + self waittill( "player_shot" ); + + self.lastAttackTime = getTime(); } } @@ -149,7 +165,7 @@ waitForAdditionalAngles( logString, beforeFrameCount, afterFrameCount ) { fixedIndex = self.angleSnapshot.size - abs(i); } - anglesStr += self.angleSnapshot[fixedIndex] + ":"; + anglesStr += self.angleSnapshot[int(fixedIndex)] + ":"; collectedFrames++; i++; } @@ -169,12 +185,15 @@ waitForAdditionalAngles( logString, beforeFrameCount, afterFrameCount ) { fixedIndex = i % self.angleSnapshot.size; } - anglesStr += self.angleSnapshot[fixedIndex] + ":"; + anglesStr += self.angleSnapshot[int(fixedIndex)] + ":"; collectedFrames++; i++; } - logPrint(logString + ";" + anglesStr + "\n" ); + lastAttack = int(getTime()) - int(self.lastAttackTime); + isAlive = isAlive(self); + + logPrint(logString + ";" + anglesStr + ";" + isAlive + ";" + lastAttack + "\n" ); } vectorScale( vector, scale ) @@ -205,7 +224,7 @@ Process_Hit( type, attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon ) location = victim GetTagOrigin( hitLocationToBone( sHitLoc ) ); isKillstreakKill = !isPlayer( attacker ) || isKillstreakWeapon( sWeapon ); - logLine = "Script" + type + ";" + _attacker.guid + ";" + victim.guid + ";" + _attacker GetTagOrigin("tag_eye") + ";" + location + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + ";" + _attacker getPlayerAngles() + ";" + gettime() + ";" + isKillstreakKill + ";" + _attacker playerADS() + ";0;0"; + logLine = "Script" + type + ";" + _attacker.guid + ";" + victim.guid + ";" + _attacker GetTagOrigin("tag_eye") + ";" + location + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + ";" + _attacker getPlayerAngles() + ";" + int(gettime()) + ";" + isKillstreakKill + ";" + _attacker playerADS() + ";0;0"; attacker thread waitForAdditionalAngles( logLine, 2, 2 ); }