diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj
index 4e139c17a4..fe3a253a0e 100755
--- a/OpenRA.Game/OpenRA.Game.csproj
+++ b/OpenRA.Game/OpenRA.Game.csproj
@@ -116,6 +116,7 @@
+
diff --git a/OpenRA.Game/Orders/UnitOrderGenerator.cs b/OpenRA.Game/Orders/UnitOrderGenerator.cs
index f9c6612700..3aa2917822 100644
--- a/OpenRA.Game/Orders/UnitOrderGenerator.cs
+++ b/OpenRA.Game/Orders/UnitOrderGenerator.cs
@@ -51,15 +51,16 @@ namespace OpenRA.Orders
return ChooseCursor(world, mi);
}
- string ChooseCursor( World world, MouseInput mi )
+ string ChooseCursor(World world, MouseInput mi)
{
+
+ var p = Game.controller.MousePosition;
+ var c = Order(world, p.ToInt2(), mi)
+ .Select(o => CursorForOrderString(o.OrderString, o.Subject, o.TargetLocation))
+ .FirstOrDefault(a => a != null);
+
using (new PerfSample("cursor"))
{
- var p = Game.controller.MousePosition;
- var c = Order(world, p.ToInt2(), mi)
- .Select(o => CursorForOrderString(o.OrderString, o.Subject, o.TargetLocation))
- .FirstOrDefault(a => a != null);
-
return c ??
(world.SelectActorsInBox(Game.CellSize * p,
Game.CellSize * p).Any()
diff --git a/OpenRA.Game/Traits/World/SpatialBins.cs b/OpenRA.Game/Traits/World/SpatialBins.cs
new file mode 100644
index 0000000000..ddfac0fbec
--- /dev/null
+++ b/OpenRA.Game/Traits/World/SpatialBins.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Drawing;
+
+namespace OpenRA.Traits
+{
+ class SpatialBinsInfo : ITraitInfo
+ {
+ public readonly int BinSize = 8;
+ public object Create(Actor self) { return new SpatialBins( self, this ); }
+ }
+
+ class SpatialBins : ITick
+ {
+ List[,] bins;
+ int scale;
+
+ public SpatialBins(Actor self, SpatialBinsInfo info)
+ {
+ bins = new List[
+ self.World.Map.MapSize / info.BinSize,
+ self.World.Map.MapSize / info.BinSize];
+
+ scale = Game.CellSize * info.BinSize;
+ }
+
+ public void Tick(Actor self)
+ {
+ for (var j = 0; j < bins.GetUpperBound(1); j++)
+ for (var i = 0; i < bins.GetUpperBound(0); i++)
+ bins[i, j] = new List();
+
+ foreach (var a in self.World.Actors)
+ {
+ if (a.Location.X >= self.World.Map.MapSize
+ || a.Location.Y >= self.World.Map.MapSize)
+ continue;
+
+ var bounds = a.GetBounds(true);
+ var i1 = (int)bounds.Left / scale;
+ var i2 = (int)bounds.Right / scale;
+ var j1 = (int)bounds.Top / scale;
+ var j2 = (int)bounds.Bottom / scale;
+
+ for (var j = j1; j <= j2; j++)
+ for (var i = i1; i <= i2; i++)
+ bins[i, j].Add(a);
+ }
+ }
+
+ IEnumerable ActorsInBins(int i1, int i2, int j1, int j2)
+ {
+ for (var j = j1; j <= j2; j++)
+ for (var i = i1; i <= i2; i++)
+ foreach (var a in bins[i, j])
+ yield return a;
+ }
+
+ public IEnumerable ActorsInBox(int2 a, int2 b)
+ {
+ var r = RectangleF.FromLTRB( a.X, a.Y, b.X, b.Y );
+
+ return ActorsInBins(
+ a.X / scale,
+ a.Y / scale,
+ b.X / scale,
+ b.Y / scale)
+ .Distinct()
+ .Where(u => u.GetBounds(true).IntersectsWith(r));
+ }
+ }
+}
diff --git a/mods/ra/rules.yaml b/mods/ra/rules.yaml
index 07449e9e05..be5e0e20b4 100755
--- a/mods/ra/rules.yaml
+++ b/mods/ra/rules.yaml
@@ -272,6 +272,7 @@ World:
SpawnMapActors:
SpawnDefaultUnits:
EvaAlerts:
+ SpatialBins:
MGG:
GeneratesGap: