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