From 1bc3a7395fe1f1efd25a5e70376bb06342d870e4 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Sat, 9 Jan 2016 16:49:47 +0000 Subject: [PATCH] Prevent items without size from being added to SpatiallyPartitioned. Items with no size act unexpectedly as they can fail to be returned when querying partition bins as they do not intersect along the top or left edges of the bin. We prevent such items being added in the first place to avoid this scenario. As a side effect - we must now prevent any Immobile items that do not have size from being added to the screen map. --- OpenRA.Game/Primitives/SpatiallyPartitioned.cs | 8 ++++++++ OpenRA.Mods.Common/Traits/Immobile.cs | 8 ++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/OpenRA.Game/Primitives/SpatiallyPartitioned.cs b/OpenRA.Game/Primitives/SpatiallyPartitioned.cs index 6bc9833300..128832fe4d 100644 --- a/OpenRA.Game/Primitives/SpatiallyPartitioned.cs +++ b/OpenRA.Game/Primitives/SpatiallyPartitioned.cs @@ -30,14 +30,22 @@ namespace OpenRA.Primitives itemBoundsBins = Exts.MakeArray(rows * cols, _ => new Dictionary()); } + void ValidateBounds(Rectangle bounds) + { + if (bounds.Width <= 0 || bounds.Height <= 0) + throw new ArgumentException("bounds must be non-empty.", "bounds"); + } + public void Add(T item, Rectangle bounds) { + ValidateBounds(bounds); itemBounds.Add(item, bounds); MutateBins(item, bounds, addItem); } public void Update(T item, Rectangle bounds) { + ValidateBounds(bounds); MutateBins(item, itemBounds[item], removeItem); MutateBins(item, itemBounds[item] = bounds, addItem); } diff --git a/OpenRA.Mods.Common/Traits/Immobile.cs b/OpenRA.Mods.Common/Traits/Immobile.cs index be0ea75bbd..2926c02e25 100644 --- a/OpenRA.Mods.Common/Traits/Immobile.cs +++ b/OpenRA.Mods.Common/Traits/Immobile.cs @@ -55,14 +55,18 @@ namespace OpenRA.Mods.Common.Traits { self.World.ActorMap.AddInfluence(self, this); self.World.ActorMap.AddPosition(self, this); - self.World.ScreenMap.Add(self); + + if (!self.Bounds.Size.IsEmpty) + self.World.ScreenMap.Add(self); } public void RemovedFromWorld(Actor self) { self.World.ActorMap.RemoveInfluence(self, this); self.World.ActorMap.RemovePosition(self, this); - self.World.ScreenMap.Remove(self); + + if (!self.Bounds.Size.IsEmpty) + self.World.ScreenMap.Remove(self); } } }