diff --git a/EVTCAnalytics/Processing/Encounters/Results/AgentBuffGainedDeterminer.cs b/EVTCAnalytics/Processing/Encounters/Results/AgentBuffGainedDeterminer.cs index 3f2c2a04..6ca6130c 100644 --- a/EVTCAnalytics/Processing/Encounters/Results/AgentBuffGainedDeterminer.cs +++ b/EVTCAnalytics/Processing/Encounters/Results/AgentBuffGainedDeterminer.cs @@ -17,7 +17,7 @@ public class AgentBuffGainedDeterminer(Agent agent, uint buffId, bool ignoreInit protected override Event GetEvent(IEnumerable events) { - var filteredEvents = stopAtDespawn ? events.TakeWhile(x => !(x is AgentDespawnEvent despawn && despawn.Agent == agent)) : events; + var filteredEvents = stopAtDespawn ? TakeUntilDespawn(events) : events; if (ignoreInitial) { @@ -29,10 +29,30 @@ protected override Event GetEvent(IEnumerable events) else { return filteredEvents - .TakeWhile(x => x is not AgentDespawnEvent) .OfType() .FirstOrDefault(x => x.Agent == agent && x.Buff.Id == buffId); } } + + private IEnumerable TakeUntilDespawn(IEnumerable events) + { + // Very rarely, arcdps has been seen to emit a despawn event instead of a spawn event + // (specifically, this has been observed once with arcdps 20220330). + // To work around this issue, we ignore despawn events that happen very soon after the first event. + const long earlyDespawnThreshold = 200; + + long firstTime = long.MaxValue; + foreach (var e in events) + { + firstTime = Math.Min(firstTime, e.Time); + + if (e is AgentDespawnEvent despawn && despawn.Agent == agent && despawn.Time - firstTime > earlyDespawnThreshold) + { + yield break; + } + + yield return e; + } + } } }