diff --git a/OpenRA.Mods.Common/Traits/World/ActorMap.cs b/OpenRA.Mods.Common/Traits/World/ActorMap.cs index cf5b0937e4..5dbe2ebbfc 100644 --- a/OpenRA.Mods.Common/Traits/World/ActorMap.cs +++ b/OpenRA.Mods.Common/Traits/World/ActorMap.cs @@ -48,8 +48,8 @@ namespace OpenRA.Mods.Common.Traits readonly Action onActorEntered; readonly Action onActorExited; - - IEnumerable currentActors = Enumerable.Empty(); + readonly HashSet oldActors = new HashSet(); + readonly HashSet currentActors = new HashSet(); public CellTrigger(CPos[] footprint, Action onActorEntered, Action onActorExited) { @@ -67,19 +67,22 @@ namespace OpenRA.Mods.Common.Traits if (!Dirty) return; - var oldActors = currentActors; - currentActors = Footprint.SelectMany(actorMap.GetActorsAt).ToList(); + // PERF: Reuse collection to avoid allocations. + oldActors.Clear(); + oldActors.UnionWith(currentActors); - var entered = currentActors.Except(oldActors); - var exited = oldActors.Except(currentActors); + currentActors.Clear(); + currentActors.UnionWith(Footprint.SelectMany(actorMap.GetActorsAt)); if (onActorEntered != null) - foreach (var a in entered) - onActorEntered(a); + foreach (var a in currentActors) + if (!oldActors.Contains(a)) + onActorEntered(a); if (onActorExited != null) - foreach (var a in exited) - onActorExited(a); + foreach (var a in oldActors) + if (!currentActors.Contains(a)) + onActorExited(a); Dirty = false; } @@ -94,13 +97,13 @@ namespace OpenRA.Mods.Common.Traits readonly Action onActorEntered; readonly Action onActorExited; + readonly HashSet oldActors = new HashSet(); + readonly HashSet currentActors = new HashSet(); WPos position; WDist range; WDist vRange; - IEnumerable currentActors = Enumerable.Empty(); - public ProximityTrigger(WPos pos, WDist range, WDist vRange, Action onActorEntered, Action onActorExited) { this.onActorEntered = onActorEntered; @@ -128,23 +131,26 @@ namespace OpenRA.Mods.Common.Traits if (!Dirty) return; - var oldActors = currentActors; - var delta = new WVec(range, range, WDist.Zero); - currentActors = am.ActorsInBox(position - delta, position + delta) - .Where(a => (a.CenterPosition - position).HorizontalLengthSquared < range.LengthSquared - && (vRange.Length == 0 || (a.World.Map.DistanceAboveTerrain(a.CenterPosition).LengthSquared <= vRange.LengthSquared))) - .ToList(); + // PERF: Reuse collection to avoid allocations. + oldActors.Clear(); + oldActors.UnionWith(currentActors); - var entered = currentActors.Except(oldActors); - var exited = oldActors.Except(currentActors); + var delta = new WVec(range, range, WDist.Zero); + currentActors.Clear(); + currentActors.UnionWith( + am.ActorsInBox(position - delta, position + delta) + .Where(a => (a.CenterPosition - position).HorizontalLengthSquared < range.LengthSquared + && (vRange.Length == 0 || (a.World.Map.DistanceAboveTerrain(a.CenterPosition).LengthSquared <= vRange.LengthSquared)))); if (onActorEntered != null) - foreach (var a in entered) - onActorEntered(a); + foreach (var a in currentActors) + if (!oldActors.Contains(a)) + onActorEntered(a); if (onActorExited != null) - foreach (var a in exited) - onActorExited(a); + foreach (var a in oldActors) + if (!currentActors.Contains(a)) + onActorExited(a); Dirty = false; }