diff --git a/OpenRA.Game/Traits/Waypoint.cs b/OpenRA.Game/Traits/Waypoint.cs index c7afeae949..a0cf83becd 100644 --- a/OpenRA.Game/Traits/Waypoint.cs +++ b/OpenRA.Game/Traits/Waypoint.cs @@ -20,7 +20,7 @@ namespace OpenRA.Traits class Waypoint : IOccupySpace, ISync, INotifyAddedToWorld, INotifyRemovedFromWorld { - [Sync] CPos location; + [Sync] readonly CPos location; public Waypoint(ActorInitializer init) { @@ -34,12 +34,14 @@ namespace OpenRA.Traits public void AddedToWorld(Actor self) { self.World.ActorMap.AddInfluence(self, this); + self.World.ActorMap.AddPosition(self, this); 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); } } diff --git a/OpenRA.Game/Traits/World/ActorMap.cs b/OpenRA.Game/Traits/World/ActorMap.cs index af50470346..7a74294f40 100644 --- a/OpenRA.Game/Traits/World/ActorMap.cs +++ b/OpenRA.Game/Traits/World/ActorMap.cs @@ -10,15 +10,19 @@ using System.Collections.Generic; using System.Linq; +using OpenRA.FileFormats; using OpenRA.Traits; namespace OpenRA.Traits { public enum SubCell { FullCell, TopLeft, TopRight, Center, BottomLeft, BottomRight } - class ActorMapInfo : ITraitInfo + public class ActorMapInfo : ITraitInfo { - public object Create(ActorInitializer init) { return new ActorMap(init.world); } + [Desc("Size of partition bins (cells)")] + public readonly int BinSize = 10; + + public object Create(ActorInitializer init) { return new ActorMap(init.world, this); } } public class ActorMap @@ -30,13 +34,25 @@ namespace OpenRA.Traits public Actor actor; } + readonly ActorMapInfo info; + readonly Map map; InfluenceNode[,] influence; - Map map; - public ActorMap(World world) + List[] actors; + int rows, cols; + + public ActorMap(World world, ActorMapInfo info) { + this.info = info; map = world.Map; influence = new InfluenceNode[world.Map.MapSize.X, world.Map.MapSize.Y]; + + cols = world.Map.MapSize.X / info.BinSize + 1; + rows = world.Map.MapSize.Y / info.BinSize + 1; + actors = new List[rows * cols]; + for (var j = 0; j < rows; j++) + for (var i = 0; i < cols; i++) + actors[j * cols + i] = new List(); } public IEnumerable GetUnitsAt(CPos a) @@ -114,5 +130,25 @@ namespace OpenRA.Traits if (influenceNode != null) RemoveInfluenceInner(ref influenceNode.next, toRemove); } + + public void AddPosition(Actor a, IOccupySpace ios) + { + var pos = ios.CenterPosition; + var i = (pos.X / info.BinSize).Clamp(0, cols - 1); + var j = (pos.Y / info.BinSize).Clamp(0, rows - 1); + actors[j*cols + i].Add(a); + } + + public void RemovePosition(Actor a, IOccupySpace ios) + { + foreach (var bin in actors) + bin.Remove(a); + } + + public void UpdatePosition(Actor a, IOccupySpace ios) + { + RemovePosition(a, ios); + AddPosition(a, ios); + } } } diff --git a/OpenRA.Mods.RA/Air/Aircraft.cs b/OpenRA.Mods.RA/Air/Aircraft.cs index c1baf48b51..ab88485cc6 100755 --- a/OpenRA.Mods.RA/Air/Aircraft.cs +++ b/OpenRA.Mods.RA/Air/Aircraft.cs @@ -106,7 +106,10 @@ namespace OpenRA.Mods.RA.Air CenterPosition = pos; if (self.IsInWorld) + { self.World.ScreenMap.Update(self); + self.World.ActorMap.UpdatePosition(self, this); + } } // Changes position, but not altitude @@ -116,12 +119,14 @@ namespace OpenRA.Mods.RA.Air public void AddedToWorld(Actor self) { self.World.ActorMap.AddInfluence(self, this); + self.World.ActorMap.AddPosition(self, this); 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); } diff --git a/OpenRA.Mods.RA/Buildings/Building.cs b/OpenRA.Mods.RA/Buildings/Building.cs index 0ec7af8b7a..60a3490dd5 100755 --- a/OpenRA.Mods.RA/Buildings/Building.cs +++ b/OpenRA.Mods.RA/Buildings/Building.cs @@ -161,12 +161,14 @@ namespace OpenRA.Mods.RA.Buildings public void AddedToWorld(Actor self) { self.World.ActorMap.AddInfluence(self, this); + self.World.ActorMap.AddPosition(self, this); 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); } } diff --git a/OpenRA.Mods.RA/Crate.cs b/OpenRA.Mods.RA/Crate.cs index 68ba35bb26..2fdeb44bce 100644 --- a/OpenRA.Mods.RA/Crate.cs +++ b/OpenRA.Mods.RA/Crate.cs @@ -103,9 +103,7 @@ namespace OpenRA.Mods.RA public void SetPosition(Actor self, CPos cell) { - if (self.IsInWorld) - self.World.ActorMap.RemoveInfluence(self, this); - + self.World.ActorMap.RemoveInfluence(self, this); Location = cell; CenterPosition = cell.CenterPosition; @@ -117,6 +115,7 @@ namespace OpenRA.Mods.RA if (self.IsInWorld) { self.World.ActorMap.AddInfluence(self, this); + self.World.ActorMap.UpdatePosition(self, this); self.World.ScreenMap.Update(self); } } @@ -129,12 +128,14 @@ namespace OpenRA.Mods.RA public void AddedToWorld(Actor self) { self.World.ActorMap.AddInfluence(self, this); + self.World.ActorMap.AddPosition(self, this); 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); } } diff --git a/OpenRA.Mods.RA/Husk.cs b/OpenRA.Mods.RA/Husk.cs index 9e41fb64ca..2e9c0b0383 100644 --- a/OpenRA.Mods.RA/Husk.cs +++ b/OpenRA.Mods.RA/Husk.cs @@ -76,18 +76,21 @@ namespace OpenRA.Mods.RA CenterPosition = pos; TopLeft = pos.ToCPos(); self.World.ActorMap.AddInfluence(self, this); + self.World.ActorMap.UpdatePosition(self, this); self.World.ScreenMap.Update(self); } public void AddedToWorld(Actor self) { self.World.ActorMap.AddInfluence(self, this); + self.World.ActorMap.AddPosition(self, this); 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); } } diff --git a/OpenRA.Mods.RA/Mine.cs b/OpenRA.Mods.RA/Mine.cs index f42264d4a8..aa45da5d14 100644 --- a/OpenRA.Mods.RA/Mine.cs +++ b/OpenRA.Mods.RA/Mine.cs @@ -66,12 +66,14 @@ namespace OpenRA.Mods.RA public void AddedToWorld(Actor self) { self.World.ActorMap.AddInfluence(self, this); + self.World.ActorMap.AddPosition(self, this); 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); } } diff --git a/OpenRA.Mods.RA/Move/Mobile.cs b/OpenRA.Mods.RA/Move/Mobile.cs index 1679654e42..fb315d6267 100755 --- a/OpenRA.Mods.RA/Move/Mobile.cs +++ b/OpenRA.Mods.RA/Move/Mobile.cs @@ -232,18 +232,23 @@ namespace OpenRA.Mods.RA.Move { CenterPosition = pos; if (self.IsInWorld) + { self.World.ScreenMap.Update(self); + self.World.ActorMap.UpdatePosition(self, this); + } } public void AddedToWorld(Actor self) { self.World.ActorMap.AddInfluence(self, this); + self.World.ActorMap.AddPosition(self, this); 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); }