diff --git a/OpenRA.Game/Actor.cs b/OpenRA.Game/Actor.cs index e9adebf8dd..4fcd7f5f5e 100755 --- a/OpenRA.Game/Actor.cs +++ b/OpenRA.Game/Actor.cs @@ -24,13 +24,11 @@ namespace OpenRA public readonly World World; public readonly uint ActorID; + public Lazy Bounds; Lazy occupySpace; Lazy facing; - public Cached Bounds; - public Cached ExtendedBounds; - public IOccupySpace OccupiesSpace { get { return occupySpace.Value; } } public CPos Location { get { return occupySpace.Value.TopLeft; } } @@ -76,27 +74,25 @@ namespace OpenRA facing = Lazy.New(() => TraitOrDefault()); - size = Lazy.New(() => - { - var si = Info.Traits.GetOrDefault(); - if (si != null && si.Bounds != null) - return new int2(si.Bounds[0], si.Bounds[1]); - - return TraitsImplementing().Select(x => x.SelectionSize(this)).FirstOrDefault(); - }); - applyIRender = (x, wr) => x.Render(this, wr); applyRenderModifier = (m, p, wr) => p.ModifyRender(this, wr, m); - Bounds = Cached.New(() => CalculateBounds(false)); - ExtendedBounds = Cached.New(() => CalculateBounds(true)); + Bounds = Lazy.New(() => + { + var si = Info.Traits.GetOrDefault(); + var size = (si != null && si.Bounds != null) ? new int2(si.Bounds[0], si.Bounds[1]) : + TraitsImplementing().Select(x => x.SelectionSize(this)).FirstOrDefault(); + + var offset = -size / 2; + if (si != null && si.Bounds != null && si.Bounds.Length > 2) + offset += new int2(si.Bounds[2], si.Bounds[3]); + + return new Rectangle(offset.X, offset.Y, size.X, size.Y); + }); } public void Tick() { - Bounds.Invalidate(); - ExtendedBounds.Invalidate(); - currentActivity = Traits.Util.RunActivity(this, currentActivity); } @@ -105,8 +101,6 @@ namespace OpenRA get { return currentActivity == null; } } - OpenRA.FileFormats.Lazy size; - // note: these delegates are cached to avoid massive allocation. Func> applyIRender; Func, IRenderModifier, WorldRenderer, IEnumerable> applyRenderModifier; @@ -117,34 +111,6 @@ namespace OpenRA return mods.Aggregate(sprites, (m, p) => applyRenderModifier(m, p, wr)); } - // When useAltitude = true, the bounding box is extended - // vertically to altitude = 0 to support FindUnitsInCircle queries - // When false, the bounding box is given for the actor - // at its current altitude - Rectangle CalculateBounds(bool useAltitude) - { - var sizeVector = (PVecInt)size.Value; - var loc = CenterLocation - sizeVector / 2; - - var si = Info.Traits.GetOrDefault(); - if (si != null && si.Bounds != null && si.Bounds.Length > 2) - { - loc += new PVecInt(si.Bounds[2], si.Bounds[3]); - } - - var ios = occupySpace.Value; - if (ios != null) - { - var altitude = ios.CenterPosition.Z * Game.CellSize / 1024; - loc -= new PVecInt(0, altitude); - - if (useAltitude) - sizeVector = new PVecInt(sizeVector.X, sizeVector.Y + altitude); - } - - return new Rectangle(loc.X, loc.Y, sizeVector.X, sizeVector.Y); - } - public bool IsInWorld { get; internal set; } public void QueueActivity(bool queued, Activity nextActivity) diff --git a/OpenRA.Game/ActorInitializer.cs b/OpenRA.Game/ActorInitializer.cs index 71ee1eb43f..f342c21d24 100755 --- a/OpenRA.Game/ActorInitializer.cs +++ b/OpenRA.Game/ActorInitializer.cs @@ -10,6 +10,7 @@ using System.Linq; using OpenRA.FileFormats; +using OpenRA.Traits; namespace OpenRA { diff --git a/OpenRA.Game/ActorMap.cs b/OpenRA.Game/ActorMap.cs deleted file mode 100644 index 5fc8ac1f8f..0000000000 --- a/OpenRA.Game/ActorMap.cs +++ /dev/null @@ -1,122 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA -{ - public enum SubCell { FullCell, TopLeft, TopRight, Center, BottomLeft, BottomRight } - - public class ActorMap - { - class InfluenceNode - { - public InfluenceNode next; - public SubCell subCell; - public Actor actor; - } - - InfluenceNode[,] influence; - Map map; - - public ActorMap( World world ) - { - map = world.Map; - influence = new InfluenceNode[world.Map.MapSize.X, world.Map.MapSize.Y]; - - world.ActorAdded += a => Add( a, a.OccupiesSpace ); - world.ActorRemoved += a => Remove( a, a.OccupiesSpace ); - } - - public IEnumerable GetUnitsAt(CPos a) - { - if (!map.IsInMap(a)) yield break; - - for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next ) - if (!i.actor.Destroyed) - yield return i.actor; - } - - public IEnumerable GetUnitsAt(CPos a, SubCell sub) - { - if (!map.IsInMap(a)) yield break; - - for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next ) - if (!i.actor.Destroyed && (i.subCell == sub || i.subCell == SubCell.FullCell)) - yield return i.actor; - } - - public bool HasFreeSubCell(CPos a) - { - if (!AnyUnitsAt(a)) - return true; - - return new[]{ SubCell.TopLeft, SubCell.TopRight, SubCell.Center, - SubCell.BottomLeft, SubCell.BottomRight }.Any(b => !AnyUnitsAt(a,b)); - } - - public SubCell? FreeSubCell(CPos a) - { - if (!HasFreeSubCell(a)) - return null; - - return new[]{ SubCell.TopLeft, SubCell.TopRight, SubCell.Center, - SubCell.BottomLeft, SubCell.BottomRight }.First(b => !AnyUnitsAt(a,b)); - } - - - public bool AnyUnitsAt(CPos a) - { - return influence[ a.X, a.Y ] != null; - } - - public bool AnyUnitsAt(CPos a, SubCell sub) - { - for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next ) - if (i.subCell == sub || i.subCell == SubCell.FullCell) - return true; - - return false; - } - - public void Add( Actor self, IOccupySpace unit ) - { - if (unit != null) - foreach( var c in unit.OccupiedCells() ) - influence[ c.First.X, c.First.Y ] = new InfluenceNode { next = influence[ c.First.X, c.First.Y ], subCell = c.Second, actor = self }; - } - - public void Remove( Actor self, IOccupySpace unit ) - { - if (unit != null) - foreach (var c in unit.OccupiedCells()) - RemoveInner( ref influence[ c.First.X, c.First.Y ], self ); - } - - void RemoveInner( ref InfluenceNode influenceNode, Actor toRemove ) - { - if( influenceNode == null ) - return; - else if( influenceNode.actor == toRemove ) - influenceNode = influenceNode.next; - - if (influenceNode != null) - RemoveInner( ref influenceNode.next, toRemove ); - } - - public void Update(Actor self, IOccupySpace unit) - { - Remove(self, unit); - if (!self.IsDead()) Add(self, unit); - } - } -} diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 5e76423425..825f73af25 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -213,8 +213,11 @@ namespace OpenRA viewport = new Viewport(new int2(Renderer.Resolution), map.Bounds, Renderer); orderManager.world = new World(modData.Manifest, map, orderManager, isShellmap); worldRenderer = new WorldRenderer(orderManager.world); + orderManager.world.LoadComplete(worldRenderer); + + if (orderManager.GameStarted) + return; - if (orderManager.GameStarted) return; Ui.MouseFocusWidget = null; Ui.KeyboardFocusWidget = null; diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index ea6b61a1d0..56c2f10c9b 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -73,12 +73,11 @@ namespace OpenRA.Graphics List GenerateRenderables() { - var bounds = Game.viewport.WorldBounds(world); var comparer = new RenderableComparer(this); - - var tl = bounds.TopLeftAsCPos(); - var br = bounds.BottomRightAsCPos(); - var actors = world.FindActorsInBox(tl, br) + var vb = Game.viewport.ViewBounds(world); + var tl = Game.viewport.ViewToWorldPx(new int2(vb.Left, vb.Top)).ToInt2(); + var br = Game.viewport.ViewToWorldPx(new int2(vb.Right, vb.Bottom)).ToInt2(); + var actors = world.ScreenMap.ActorsInBox(tl, br) .Append(world.WorldActor) .ToList(); @@ -151,14 +150,15 @@ namespace OpenRA.Graphics Game.Renderer.Flush(); } - public void DrawSelectionBox(Actor selectedUnit, Color c) + public void DrawSelectionBox(Actor a, Color c) { - var bounds = selectedUnit.Bounds.Value; + var pos = ScreenPxPosition(a.CenterPosition); + var bounds = a.Bounds.Value; - var xy = new float2(bounds.Left, bounds.Top); - var Xy = new float2(bounds.Right, bounds.Top); - var xY = new float2(bounds.Left, bounds.Bottom); - var XY = new float2(bounds.Right, bounds.Bottom); + var xy = pos + new float2(bounds.Left, bounds.Top); + var Xy = pos + new float2(bounds.Right, bounds.Top); + var xY = pos + new float2(bounds.Left, bounds.Bottom); + var XY = pos + new float2(bounds.Right, bounds.Bottom); var wlr = Game.Renderer.WorldLineRenderer; wlr.DrawLine(xy, xy + new float2(4, 0), c, c); diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index f4846fecb7..410110aeee 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -83,7 +83,6 @@ - @@ -185,7 +184,6 @@ - @@ -238,6 +236,8 @@ + + diff --git a/OpenRA.Game/Orders/UnitOrderGenerator.cs b/OpenRA.Game/Orders/UnitOrderGenerator.cs index af8e2c5bad..f405c6a7f3 100644 --- a/OpenRA.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRA.Game/Orders/UnitOrderGenerator.cs @@ -19,8 +19,8 @@ namespace OpenRA.Orders { public IEnumerable Order(World world, CPos xy, MouseInput mi) { - var underCursor = world.FindUnitsAtMouse(mi.Location) - .Where(a => a.HasTrait()) + var underCursor = world.ScreenMap.ActorsAt(Game.viewport.ViewToWorldPx(mi.Location)) + .Where(a => !world.FogObscures(a) && a.HasTrait()) .OrderByDescending(a => a.Info.SelectionPriority()) .FirstOrDefault(); @@ -59,10 +59,9 @@ namespace OpenRA.Orders public string GetCursor(World world, CPos xy, MouseInput mi) { - bool useSelect = false; - - var underCursor = world.FindUnitsAtMouse(mi.Location) - .Where(a => a.HasTrait()) + var useSelect = false; + var underCursor = world.ScreenMap.ActorsAt(Game.viewport.ViewToWorldPx(mi.Location)) + .Where(a => !world.FogObscures(a) && a.HasTrait()) .OrderByDescending(a => a.Info.SelectionPriority()) .FirstOrDefault(); diff --git a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs index 20521cd096..9cb594ca35 100755 --- a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs +++ b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs @@ -20,10 +20,7 @@ namespace OpenRA.Traits { public class FrozenActorLayerInfo : ITraitInfo { - [Desc("Size of partition bins (screen pixels)")] - public readonly int BinSize = 250; - - public object Create(ActorInitializer init) { return new FrozenActorLayer(init.world, this); } + public object Create(ActorInitializer init) { return new FrozenActorLayer(init.self); } } public class FrozenActor @@ -98,34 +95,21 @@ namespace OpenRA.Traits [Sync] public int VisibilityHash; [Sync] public int FrozenHash; - readonly FrozenActorLayerInfo info; + readonly World world; + readonly Player owner; Dictionary frozen; - List[,] bins; - public FrozenActorLayer(World world, FrozenActorLayerInfo info) + public FrozenActorLayer(Actor self) { - this.info = info; + world = self.World; + owner = self.Owner; frozen = new Dictionary(); - bins = new List[ - world.Map.MapSize.X * Game.CellSize / info.BinSize, - world.Map.MapSize.Y * Game.CellSize / info.BinSize]; - - for (var j = 0; j <= bins.GetUpperBound(1); j++) - for (var i = 0; i <= bins.GetUpperBound(0); i++) - bins[i, j] = new List(); } public void Add(FrozenActor fa) { frozen.Add(fa.ID, fa); - - var top = (int)Math.Max(0, fa.Bounds.Top / info.BinSize); - var left = (int)Math.Max(0, fa.Bounds.Left / info.BinSize); - var bottom = (int)Math.Min(bins.GetUpperBound(1), fa.Bounds.Bottom / info.BinSize); - var right = (int)Math.Min(bins.GetUpperBound(0), fa.Bounds.Right / info.BinSize); - for (var j = top; j <= bottom; j++) - for (var i = left; i <= right; i++) - bins[i, j].Add(fa); + world.ScreenMap.Add(owner, fa); } public void Tick(Actor self) @@ -148,8 +132,7 @@ namespace OpenRA.Traits foreach (var r in remove) { - foreach (var bin in bins) - bin.Remove(frozen[r]); + world.ScreenMap.Remove(owner, frozen[r]); frozen.Remove(r); } } @@ -161,13 +144,6 @@ namespace OpenRA.Traits .SelectMany(ff => ff.Render(wr)); } - public IEnumerable FrozenActorsAt(int2 pxPos) - { - var x = (pxPos.X / info.BinSize).Clamp(0, bins.GetUpperBound(0)); - var y = (pxPos.Y / info.BinSize).Clamp(0, bins.GetUpperBound(1)); - return bins[x, y].Where(p => p.Bounds.Contains(pxPos) && p.IsValid); - } - public FrozenActor FromID(uint id) { FrozenActor ret; diff --git a/OpenRA.Game/Traits/Selectable.cs b/OpenRA.Game/Traits/Selectable.cs index 0a5d6d9609..b01cc222c8 100644 --- a/OpenRA.Game/Traits/Selectable.cs +++ b/OpenRA.Game/Traits/Selectable.cs @@ -40,7 +40,9 @@ namespace OpenRA.Traits if (!Info.Selectable) return; + var pos = wr.ScreenPxPosition(self.CenterPosition); var bounds = self.Bounds.Value; + bounds.Offset(pos.X, pos.Y); var xy = new float2(bounds.Left, bounds.Top); var Xy = new float2(bounds.Right, bounds.Top); @@ -56,7 +58,9 @@ namespace OpenRA.Traits if (!Info.Selectable) return; + var pos = wr.ScreenPxPosition(self.CenterPosition); var bounds = self.Bounds.Value; + bounds.Offset(pos.X, pos.Y); var xy = new float2(bounds.Left, bounds.Top); var Xy = new float2(bounds.Right, bounds.Top); diff --git a/OpenRA.Game/Traits/SelectionDecorations.cs b/OpenRA.Game/Traits/SelectionDecorations.cs index d9981c52b5..be999bd9b9 100644 --- a/OpenRA.Game/Traits/SelectionDecorations.cs +++ b/OpenRA.Game/Traits/SelectionDecorations.cs @@ -34,7 +34,10 @@ namespace OpenRA.Traits if (self.World.FogObscures(self)) return; + var pos = wr.ScreenPxPosition(self.CenterPosition); var bounds = self.Bounds.Value; + bounds.Offset(pos.X, pos.Y); + var xy = new float2(bounds.Left, bounds.Top); var xY = new float2(bounds.Left, bounds.Bottom); diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 62cb04cb45..63863d7847 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -174,7 +174,7 @@ namespace OpenRA.Traits public interface UsesInit where T : IActorInit { } public interface INotifySelection { void SelectionChanged(); } - public interface IWorldLoaded { void WorldLoaded(World w); } + public interface IWorldLoaded { void WorldLoaded(World w, WorldRenderer wr); } public interface ICreatePlayers { void CreatePlayers(World w); } public interface IBotInfo { string Name { get; } } diff --git a/OpenRA.Game/Traits/Waypoint.cs b/OpenRA.Game/Traits/Waypoint.cs index 2ea8e2a381..a0cf83becd 100644 --- a/OpenRA.Game/Traits/Waypoint.cs +++ b/OpenRA.Game/Traits/Waypoint.cs @@ -18,9 +18,9 @@ namespace OpenRA.Traits public object Create( ActorInitializer init ) { return new Waypoint( init ); } } - class Waypoint : IOccupySpace, ISync + class Waypoint : IOccupySpace, ISync, INotifyAddedToWorld, INotifyRemovedFromWorld { - [Sync] CPos location; + [Sync] readonly CPos location; public Waypoint(ActorInitializer init) { @@ -30,5 +30,19 @@ namespace OpenRA.Traits public CPos TopLeft { get { return location; } } public IEnumerable> OccupiedCells() { yield break; } public WPos CenterPosition { get { return location.CenterPosition; } } + + 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 new file mode 100644 index 0000000000..26a845fb51 --- /dev/null +++ b/OpenRA.Game/Traits/World/ActorMap.cs @@ -0,0 +1,180 @@ +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +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 } + + public class ActorMapInfo : ITraitInfo + { + [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 + { + class InfluenceNode + { + public InfluenceNode next; + public SubCell subCell; + public Actor actor; + } + + readonly ActorMapInfo info; + readonly Map map; + InfluenceNode[,] influence; + + 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) + { + if (!map.IsInMap(a)) + yield break; + + for (var i = influence[a.X, a.Y]; i != null; i = i.next) + if (!i.actor.Destroyed) + yield return i.actor; + } + + public IEnumerable GetUnitsAt(CPos a, SubCell sub) + { + if (!map.IsInMap(a)) + yield break; + + for (var i = influence[a.X, a.Y]; i != null; i = i.next) + if (!i.actor.Destroyed && (i.subCell == sub || i.subCell == SubCell.FullCell)) + yield return i.actor; + } + + public bool HasFreeSubCell(CPos a) + { + if (!AnyUnitsAt(a)) + return true; + + return new[] { SubCell.TopLeft, SubCell.TopRight, SubCell.Center, + SubCell.BottomLeft, SubCell.BottomRight }.Any(b => !AnyUnitsAt(a,b)); + } + + public SubCell? FreeSubCell(CPos a) + { + if (!HasFreeSubCell(a)) + return null; + + return new[] { SubCell.TopLeft, SubCell.TopRight, SubCell.Center, + SubCell.BottomLeft, SubCell.BottomRight }.First(b => !AnyUnitsAt(a,b)); + } + + + public bool AnyUnitsAt(CPos a) + { + return influence[a.X, a.Y] != null; + } + + public bool AnyUnitsAt(CPos a, SubCell sub) + { + for (var i = influence[a.X, a.Y]; i != null; i = i.next) + if (i.subCell == sub || i.subCell == SubCell.FullCell) + return true; + + return false; + } + + public void AddInfluence(Actor self, IOccupySpace ios) + { + foreach (var c in ios.OccupiedCells()) + influence[c.First.X, c.First.Y] = new InfluenceNode { next = influence[c.First.X, c.First.Y], subCell = c.Second, actor = self }; + } + + public void RemoveInfluence(Actor self, IOccupySpace ios) + { + foreach (var c in ios.OccupiedCells()) + RemoveInfluenceInner(ref influence[c.First.X, c.First.Y], self); + } + + void RemoveInfluenceInner(ref InfluenceNode influenceNode, Actor toRemove) + { + if (influenceNode == null) + return; + else if (influenceNode.actor == toRemove) + influenceNode = influenceNode.next; + + 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); + } + + public IEnumerable ActorsInBox(WPos a, WPos b) + { + var left = Math.Min(a.X, b.X); + var top = Math.Min(a.Y, b.Y); + var right = Math.Max(a.X, b.X); + var bottom = Math.Max(a.Y, b.Y); + var i1 = (left / info.BinSize).Clamp(0, cols - 1); + var i2 = (right / info.BinSize).Clamp(0, cols - 1); + var j1 = (top / info.BinSize).Clamp(0, rows - 1); + var j2 = (bottom / info.BinSize).Clamp(0, rows - 1); + + for (var j = j1; j <= j2; j++) + { + for (var i = i1; i <= i2; i++) + { + foreach (var actor in actors[j*cols + i]) + { + var c = actor.CenterPosition; + if (left <= c.X && c.X <= right && top <= c.Y && c.Y <= bottom) + yield return actor; + } + } + } + } + } +} diff --git a/OpenRA.Game/Traits/World/ResourceLayer.cs b/OpenRA.Game/Traits/World/ResourceLayer.cs index 8994a17a62..7f44e87ab5 100644 --- a/OpenRA.Game/Traits/World/ResourceLayer.cs +++ b/OpenRA.Game/Traits/World/ResourceLayer.cs @@ -57,7 +57,7 @@ namespace OpenRA.Traits } } - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { this.world = w; content = new CellContents[w.Map.MapSize.X, w.Map.MapSize.Y]; diff --git a/OpenRA.Game/Traits/World/ScreenMap.cs b/OpenRA.Game/Traits/World/ScreenMap.cs new file mode 100755 index 0000000000..684a60c365 --- /dev/null +++ b/OpenRA.Game/Traits/World/ScreenMap.cs @@ -0,0 +1,159 @@ +#region Copyright & License Information +/* + * Copyright 2007-2013 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Traits +{ + public class ScreenMapInfo : ITraitInfo + { + [Desc("Size of partition bins (world pixels)")] + public readonly int BinSize = 250; + + public object Create(ActorInitializer init) { return new ScreenMap(init.world, this); } + } + + public class ScreenMap : IWorldLoaded + { + ScreenMapInfo info; + WorldRenderer worldRenderer; + Cache[]> frozen; + Dictionary[] actors; + int rows, cols; + + public ScreenMap(World world, ScreenMapInfo info) + { + this.info = info; + cols = world.Map.MapSize.X * Game.CellSize / info.BinSize + 1; + rows = world.Map.MapSize.Y * Game.CellSize / info.BinSize + 1; + + frozen = new Cache[]>(InitializeFrozenActors); + actors = new Dictionary[rows * cols]; + for (var j = 0; j < rows; j++) + for (var i = 0; i < cols; i++) + actors[j * cols + i] = new Dictionary(); + } + + public void WorldLoaded(World w, WorldRenderer wr) { worldRenderer = wr; } + + Dictionary[] InitializeFrozenActors(Player p) + { + var f = new Dictionary[rows * cols]; + for (var j = 0; j < rows; j++) + for (var i = 0; i < cols; i++) + f[j * cols + i] = new Dictionary(); + + return f; + } + + public void Add(Player viewer, FrozenActor fa) + { + var pos = worldRenderer.ScreenPxPosition(fa.CenterPosition); + var bounds = fa.Bounds; + bounds.Offset(pos.X, pos.Y); + + var top = Math.Max(0, bounds.Top / info.BinSize); + var left = Math.Max(0, bounds.Left / info.BinSize); + var bottom = Math.Min(rows - 1, bounds.Bottom / info.BinSize); + var right = Math.Min(cols - 1, bounds.Right / info.BinSize); + + for (var j = top; j <= bottom; j++) + for (var i = left; i <= right; i++) + frozen[viewer][j*cols + i].Add(fa, bounds); + } + + public void Remove(Player viewer, FrozenActor fa) + { + foreach (var bin in frozen[viewer]) + bin.Remove(fa); + } + + public void Add(Actor a) + { + var pos = worldRenderer.ScreenPxPosition(a.CenterPosition); + var bounds = a.Bounds.Value; + bounds.Offset(pos.X, pos.Y); + + var top = Math.Max(0, bounds.Top / info.BinSize); + var left = Math.Max(0, bounds.Left / info.BinSize); + var bottom = Math.Min(rows - 1, bounds.Bottom / info.BinSize); + var right = Math.Min(cols - 1, bounds.Right / info.BinSize); + + for (var j = top; j <= bottom; j++) + for (var i = left; i <= right; i++) + actors[j * cols + i].Add(a, bounds); + } + + public void Remove(Actor a) + { + foreach (var bin in actors) + bin.Remove(a); + } + + public void Update(Actor a) + { + Remove(a); + Add(a); + } + + public IEnumerable FrozenActorsAt(Player viewer, int2 pxPos) + { + var i = (pxPos.X / info.BinSize).Clamp(0, cols - 1); + var j = (pxPos.Y / info.BinSize).Clamp(0, rows - 1); + return frozen[viewer][j*cols + i] + .Where(kv => kv.Key.IsValid && kv.Value.Contains(pxPos)) + .Select(kv => kv.Key); + } + + public IEnumerable ActorsAt(int2 pxPos) + { + var i = (pxPos.X / info.BinSize).Clamp(0, cols - 1); + var j = (pxPos.Y / info.BinSize).Clamp(0, rows - 1); + return actors[j * cols + i] + .Where(kv => kv.Key.IsInWorld && kv.Value.Contains(pxPos)) + .Select(kv => kv.Key); + } + + // Legacy fallback + public IEnumerable ActorsAt(PPos pxPos) { return ActorsAt(pxPos.ToInt2()); } + + public IEnumerable ActorsInBox(int2 a, int2 b) + { + return ActorsInBox(Rectangle.FromLTRB(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Max(a.X, b.X), Math.Max(a.Y, b.Y))); + } + + public IEnumerable ActorsInBox(Rectangle r) + { + var left = (r.Left / info.BinSize).Clamp(0, cols - 1); + var right = (r.Right / info.BinSize).Clamp(0, cols - 1); + var top = (r.Top / info.BinSize).Clamp(0, rows - 1); + var bottom = (r.Bottom / info.BinSize).Clamp(0, rows - 1); + + for (var j = top; j <= bottom; j++) + { + for (var i = left; i <= right; i++) + { + var ret = actors[j * cols + i] + .Where(kv => kv.Key.IsInWorld && kv.Value.IntersectsWith(r)) + .Select(kv => kv.Key); + + foreach (var a in ret) + yield return a; + } + } + } + } +} diff --git a/OpenRA.Game/Traits/World/SpatialBins.cs b/OpenRA.Game/Traits/World/SpatialBins.cs deleted file mode 100644 index a6b17a508c..0000000000 --- a/OpenRA.Game/Traits/World/SpatialBins.cs +++ /dev/null @@ -1,87 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see COPYING. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; - -namespace OpenRA.Traits -{ - class SpatialBinsInfo : ITraitInfo - { - public readonly int BinSize = 8; - public object Create(ActorInitializer init) { return new SpatialBins( init.self, this ); } - } - - class SpatialBins : ITick - { - List[,] bins; - int scale; - - public SpatialBins(Actor self, SpatialBinsInfo info) - { - bins = new List[ - self.World.Map.MapSize.X / info.BinSize, - self.World.Map.MapSize.Y / info.BinSize]; - - scale = Game.CellSize * info.BinSize; - - for (var j = 0; j <= bins.GetUpperBound(1); j++) - for (var i = 0; i <= bins.GetUpperBound(0); i++) - bins[i, j] = new List(); - } - - 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].Clear(); - - foreach (var a in self.World.ActorsWithTrait()) - { - var bounds = a.Actor.ExtendedBounds.Value; - - if (bounds.Right <= Game.CellSize * self.World.Map.Bounds.Left) continue; - if (bounds.Bottom <= Game.CellSize * self.World.Map.Bounds.Top) continue; - if (bounds.Left >= Game.CellSize * self.World.Map.Bounds.Right) continue; - if (bounds.Top >= Game.CellSize * self.World.Map.Bounds.Bottom) continue; - - var i1 = Math.Max(0, bounds.Left / scale); - var i2 = Math.Min(bins.GetUpperBound(0), bounds.Right / scale); - var j1 = Math.Max(0, bounds.Top / scale); - var j2 = Math.Min(bins.GetUpperBound(1), bounds.Bottom / scale); - - for (var j = j1; j <= j2; j++) - for (var i = i1; i <= i2; i++) - bins[i, j].Add(a.Actor); - } - } - - IEnumerable ActorsInBins(int i1, int i2, int j1, int j2) - { - j1 = Math.Max(0, j1); j2 = Math.Min(j2, bins.GetUpperBound(1)); - i1 = Math.Max(0, i1); i2 = Math.Min(i2, bins.GetUpperBound(0)); - 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(PPos a, PPos b) - { - var r = Rectangle.FromLTRB(a.X, a.Y, b.X, b.Y); - - return ActorsInBins(a.X / scale, b.X / scale, a.Y / scale, b.Y / scale) - .Distinct() - .Where(u => u.IsInWorld && u.ExtendedBounds.Value.IntersectsWith(r)); - } - } -} diff --git a/OpenRA.Game/Widgets/ViewportControllerWidget.cs b/OpenRA.Game/Widgets/ViewportControllerWidget.cs index 25b4970904..10324995b0 100755 --- a/OpenRA.Game/Widgets/ViewportControllerWidget.cs +++ b/OpenRA.Game/Widgets/ViewportControllerWidget.cs @@ -103,8 +103,8 @@ namespace OpenRA.Widgets return; } - var underCursor = world.FindUnitsAtMouse(Viewport.LastMousePos) - .Where(a => a.HasTrait()) + var underCursor = world.ScreenMap.ActorsAt(Game.viewport.ViewToWorldPx(Viewport.LastMousePos)) + .Where(a => !world.FogObscures(a) && a.HasTrait()) .OrderByDescending(a => a.Info.SelectionPriority()) .FirstOrDefault(); diff --git a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs index 80d981b50a..d58e682a35 100644 --- a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs +++ b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs @@ -90,7 +90,7 @@ namespace OpenRA.Widgets { if (MultiClick) { - var unit = SelectActorsInBox(world, xy, xy, _ => true).FirstOrDefault(); + var unit = world.ScreenMap.ActorsAt(xy).FirstOrDefault(); var visibleWorld = Game.viewport.ViewBounds(world); var topLeft = Game.viewport.ViewToWorldPx(new int2(visibleWorld.Left, visibleWorld.Top)); @@ -185,7 +185,7 @@ namespace OpenRA.Widgets static readonly Actor[] NoActors = {}; IEnumerable SelectActorsInBox(World world, PPos a, PPos b, Func cond) { - return world.FindActorsInBox(a.ToWPos(0), b.ToWPos(0)) + return world.ScreenMap.ActorsInBox(a.ToInt2(), b.ToInt2()) .Where(x => x.HasTrait() && x.Trait().Info.Selectable && !world.FogObscures(x) && cond(x)) .GroupBy(x => x.GetSelectionPriority()) .OrderByDescending(g => g.Key) diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index 8934ba0c3e..01e27d1649 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -79,6 +79,7 @@ namespace OpenRA public readonly Map Map; public readonly TileSet TileSet; public readonly ActorMap ActorMap; + public readonly ScreenMap ScreenMap; public void IssueOrder( Order o ) { orderManager.IssueOrder( o ); } /* avoid exposing the OM to mod code */ @@ -121,8 +122,9 @@ namespace OpenRA TileSet = Rules.TileSets[Map.Tileset]; SharedRandom = new XRandom(orderManager.LobbyInfo.GlobalSettings.RandomSeed); - WorldActor = CreateActor( "World", new TypeDictionary() ); - ActorMap = new ActorMap(this); + WorldActor = CreateActor("World", new TypeDictionary()); + ActorMap = WorldActor.Trait(); + ScreenMap = WorldActor.Trait(); // Add players foreach (var cmp in WorldActor.TraitsImplementing()) @@ -135,8 +137,12 @@ namespace OpenRA p.Stances[q] = Stance.Neutral; Sound.SoundVolumeModifier = 1.0f; + } + + public void LoadComplete(WorldRenderer wr) + { foreach (var wlh in WorldActor.TraitsImplementing()) - wlh.WorldLoaded(this); + wlh.WorldLoaded(this, wr); } public Actor CreateActor( string name, TypeDictionary initDict ) diff --git a/OpenRA.Game/WorldUtils.cs b/OpenRA.Game/WorldUtils.cs index 94f635ba1d..df54b6d96b 100755 --- a/OpenRA.Game/WorldUtils.cs +++ b/OpenRA.Game/WorldUtils.cs @@ -21,38 +21,24 @@ namespace OpenRA { public static class WorldUtils { - public static IEnumerable FindUnitsAtMouse(this World world, int2 mouseLocation) - { - var loc = Game.viewport.ViewToWorldPx(mouseLocation).ToWPos(0); - return FindActorsInBox(world, loc, loc).Where(a => !world.FogObscures(a)); - } - public static readonly IEnumerable NoFrozenActors = new FrozenActor[0].AsEnumerable(); public static IEnumerable FindFrozenActorsAtMouse(this World world, int2 mouseLocation) { if (world.RenderPlayer == null) return NoFrozenActors; - var frozenLayer = world.RenderPlayer.PlayerActor.TraitOrDefault(); - if (frozenLayer == null) - return NoFrozenActors; - - var loc = Game.viewport.ViewToWorldPx(mouseLocation).ToInt2(); - return frozenLayer.FrozenActorsAt(loc); + return world.ScreenMap.FrozenActorsAt(world.RenderPlayer, Game.viewport.ViewToWorldPx(mouseLocation).ToInt2()); } public static IEnumerable FindActorsInBox(this World world, CPos tl, CPos br) { + // TODO: Support diamond boxes for isometric maps? return world.FindActorsInBox(tl.TopLeft, br.BottomRight); } public static IEnumerable FindActorsInBox(this World world, WPos tl, WPos br) { - var a = PPos.FromWPos(tl); - var b = PPos.FromWPos(br); - var u = PPos.Min(a, b); - var v = PPos.Max(a, b); - return world.WorldActor.Trait().ActorsInBox(u,v); + return world.ActorMap.ActorsInBox(tl, br); } public static Actor ClosestTo(this IEnumerable actors, Actor a) @@ -73,13 +59,8 @@ namespace OpenRA // Target ranges are calculated in 2D, so ignore height differences var vec = new WVec(r, r, WRange.Zero); var rSq = r.Range*r.Range; - return world.FindActorsInBox(origin - vec, origin + vec).Where(a => - { - var pos = a.CenterPosition; - var dx = (long)(pos.X - origin.X); - var dy = (long)(pos.Y - origin.Y); - return dx*dx + dy*dy <= rSq; - }); + return world.FindActorsInBox(origin - vec, origin + vec).Where( + a => (a.CenterPosition - origin).HorizontalLengthSquared <= rSq); } } diff --git a/OpenRA.Mods.Cnc/Missions/CncShellmapScript.cs b/OpenRA.Mods.Cnc/Missions/CncShellmapScript.cs index c56c0dd91f..5e2e1041c5 100755 --- a/OpenRA.Mods.Cnc/Missions/CncShellmapScript.cs +++ b/OpenRA.Mods.Cnc/Missions/CncShellmapScript.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Move; using OpenRA.Traits; @@ -24,7 +25,7 @@ namespace OpenRA.Mods.RA static CPos viewportOrigin; Dictionary actors; - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { var b = w.Map.Bounds; viewportOrigin = new CPos(b.Left + b.Width / 2, b.Top + b.Height / 2); diff --git a/OpenRA.Mods.Cnc/Missions/Gdi01Script.cs b/OpenRA.Mods.Cnc/Missions/Gdi01Script.cs index 6261f6689a..627f4224eb 100644 --- a/OpenRA.Mods.Cnc/Missions/Gdi01Script.cs +++ b/OpenRA.Mods.Cnc/Missions/Gdi01Script.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Move; @@ -28,7 +29,7 @@ namespace OpenRA.Mods.Cnc.Missions Dictionary actors; Dictionary players; - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { players = w.Players.ToDictionary(p => p.InternalName); actors = w.WorldActor.Trait().Actors; diff --git a/OpenRA.Mods.Cnc/Missions/Nod01Script.cs b/OpenRA.Mods.Cnc/Missions/Nod01Script.cs index be8b23def6..607acb2a16 100644 --- a/OpenRA.Mods.Cnc/Missions/Nod01Script.cs +++ b/OpenRA.Mods.Cnc/Missions/Nod01Script.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.Cnc; using OpenRA.Mods.RA; using OpenRA.Mods.RA.Activities; @@ -162,7 +163,7 @@ namespace OpenRA.Mods.Cnc.Missions nr3.QueueActivity(nr3.Trait().ScriptedMove(nr3.Location - new CVec(0, -5))); } - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { world = w; nod = w.Players.Single(p => p.InternalName == "NOD"); diff --git a/OpenRA.Mods.RA/Air/Aircraft.cs b/OpenRA.Mods.RA/Air/Aircraft.cs index 90e4285b56..ab88485cc6 100755 --- a/OpenRA.Mods.RA/Air/Aircraft.cs +++ b/OpenRA.Mods.RA/Air/Aircraft.cs @@ -36,7 +36,7 @@ namespace OpenRA.Mods.RA.Air public int GetInitialFacing() { return InitialFacing; } } - public class Aircraft : IFacing, IPositionable, ISync, INotifyKilled, IIssueOrder, IOrderVoice + public class Aircraft : IFacing, IPositionable, ISync, INotifyKilled, IIssueOrder, IOrderVoice, INotifyAddedToWorld, INotifyRemovedFromWorld { static readonly Pair[] NoCells = new Pair[] { }; @@ -101,15 +101,35 @@ namespace OpenRA.Mods.RA.Air UnReserve(); } - public void SetPosition(Actor self, CPos cell) + public void SetPosition(Actor self, WPos pos) { - // Changes position, but not altitude - CenterPosition = cell.CenterPosition + new WVec(0, 0, CenterPosition.Z); + CenterPosition = pos; + + if (self.IsInWorld) + { + self.World.ScreenMap.Update(self); + self.World.ActorMap.UpdatePosition(self, this); + } } - public void SetPosition(Actor self, WPos pos) { CenterPosition = pos; } + // Changes position, but not altitude + public void SetPosition(Actor self, CPos cell) { SetPosition(self, cell.CenterPosition + new WVec(0, 0, CenterPosition.Z)); } public void SetVisualPosition(Actor self, WPos pos) { SetPosition(self, pos); } + 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); + } + public bool AircraftCanEnter(Actor a) { if (self.AppearsHostileTo(a)) diff --git a/OpenRA.Mods.RA/BridgeLayer.cs b/OpenRA.Mods.RA/BridgeLayer.cs index 5ef0ca2bdc..8711c9de9b 100644 --- a/OpenRA.Mods.RA/BridgeLayer.cs +++ b/OpenRA.Mods.RA/BridgeLayer.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -36,7 +37,7 @@ namespace OpenRA.Mods.RA this.world = self.World; } - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { Bridges = new Bridge[w.Map.MapSize.X, w.Map.MapSize.Y]; diff --git a/OpenRA.Mods.RA/Buildings/Building.cs b/OpenRA.Mods.RA/Buildings/Building.cs index be027171d7..60a3490dd5 100755 --- a/OpenRA.Mods.RA/Buildings/Building.cs +++ b/OpenRA.Mods.RA/Buildings/Building.cs @@ -97,7 +97,7 @@ namespace OpenRA.Mods.RA.Buildings } } - public class Building : INotifyDamage, IOccupySpace, INotifyCapture, ISync, ITechTreePrerequisite + public class Building : INotifyDamage, IOccupySpace, INotifyCapture, ISync, ITechTreePrerequisite, INotifyAddedToWorld, INotifyRemovedFromWorld { readonly Actor self; public readonly BuildingInfo Info; @@ -157,5 +157,19 @@ namespace OpenRA.Mods.RA.Buildings { PlayerPower = newOwner.PlayerActor.Trait(); } + + 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 b1ab283250..2fdeb44bce 100644 --- a/OpenRA.Mods.RA/Crate.cs +++ b/OpenRA.Mods.RA/Crate.cs @@ -24,7 +24,7 @@ namespace OpenRA.Mods.RA } // ITeleportable is required for paradrop - class Crate : ITick, IPositionable, ICrushable, ISync, INotifyParachuteLanded + class Crate : ITick, IPositionable, ICrushable, ISync, INotifyParachuteLanded, INotifyAddedToWorld, INotifyRemovedFromWorld { readonly Actor self; readonly CrateInfo info; @@ -103,9 +103,7 @@ namespace OpenRA.Mods.RA public void SetPosition(Actor self, CPos cell) { - if (self.IsInWorld) - self.World.ActorMap.Remove(self, this); - + self.World.ActorMap.RemoveInfluence(self, this); Location = cell; CenterPosition = cell.CenterPosition; @@ -115,12 +113,30 @@ namespace OpenRA.Mods.RA rs.anim.PlayRepeating(seq); if (self.IsInWorld) - self.World.ActorMap.Add(self, this); + { + self.World.ActorMap.AddInfluence(self, this); + self.World.ActorMap.UpdatePosition(self, this); + self.World.ScreenMap.Update(self); + } } public bool CrushableBy(string[] crushClasses, Player owner) { return crushClasses.Contains("crate"); } + + 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/GainsExperience.cs b/OpenRA.Mods.RA/GainsExperience.cs index 135e4ba4b1..5c9edd51e0 100644 --- a/OpenRA.Mods.RA/GainsExperience.cs +++ b/OpenRA.Mods.RA/GainsExperience.cs @@ -117,9 +117,12 @@ namespace OpenRA.Mods.RA if (self.World.FogObscures(self)) yield break; + var pos = wr.ScreenPxPosition(self.CenterPosition); var bounds = self.Bounds.Value; - var pos = new PPos(bounds.Right, bounds.Bottom - 2).ToWPos(0); - yield return new SpriteRenderable(RankAnim.Image, pos, WVec.Zero, 0, wr.Palette("effect"), 1f, true); + bounds.Offset(pos.X, pos.Y); + + var effectPos = new PPos(bounds.Right, bounds.Bottom - 2).ToWPos(0); + yield return new SpriteRenderable(RankAnim.Image, effectPos, WVec.Zero, 0, wr.Palette("effect"), 1f, true); } } diff --git a/OpenRA.Mods.RA/Guard.cs b/OpenRA.Mods.RA/Guard.cs index 94cf1cba70..ef60634cc8 100644 --- a/OpenRA.Mods.RA/Guard.cs +++ b/OpenRA.Mods.RA/Guard.cs @@ -58,7 +58,7 @@ namespace OpenRA.Mods.RA yield break; } - var target = FriendlyGuardableUnitsAtMouse(world, mi).FirstOrDefault(); + var target = FriendlyGuardableUnits(world, mi).FirstOrDefault(); if (target == null || subjects.All(s => s.IsDead())) yield break; @@ -79,19 +79,19 @@ namespace OpenRA.Mods.RA public string GetCursor(World world, CPos xy, MouseInput mi) { - if (world.Map.IsInMap(xy)) - { - var targets = FriendlyGuardableUnitsAtMouse(world, mi); - if (targets.Any() && (subjects.Count() > 1 || (subjects.Count() == 1 && subjects.First() != targets.First()))) - return "guard"; - } - return "move-blocked"; + var multiple = subjects.Count() > 1; + var canGuard = FriendlyGuardableUnits(world, mi) + .Any(a => multiple || a != subjects.First()); + + return canGuard ? "guard" : "move-blocked"; } - static IEnumerable FriendlyGuardableUnitsAtMouse(World world, MouseInput mi) + static IEnumerable FriendlyGuardableUnits(World world, MouseInput mi) { - return world.FindUnitsAtMouse(mi.Location) - .Where(a => !a.IsDead() && a.AppearsFriendlyTo(world.LocalPlayer.PlayerActor) && a.HasTrait()); + return world.ScreenMap.ActorsAt(Game.viewport.ViewToWorldPx(mi.Location)) + .Where(a => !world.FogObscures(a) && !a.IsDead() && + a.AppearsFriendlyTo(world.LocalPlayer.PlayerActor) && + a.HasTrait()); } } diff --git a/OpenRA.Mods.RA/Husk.cs b/OpenRA.Mods.RA/Husk.cs index 8c5a4cd27e..2e9c0b0383 100644 --- a/OpenRA.Mods.RA/Husk.cs +++ b/OpenRA.Mods.RA/Husk.cs @@ -25,7 +25,7 @@ namespace OpenRA.Mods.RA public int GetInitialFacing() { return 128; } } - class Husk : IPositionable, IFacing, ISync + class Husk : IPositionable, IFacing, ISync, INotifyAddedToWorld, INotifyRemovedFromWorld { readonly HuskInfo info; readonly Actor self; @@ -64,14 +64,34 @@ namespace OpenRA.Mods.RA } public void SetPosition(Actor self, CPos cell) { SetPosition(self, cell.CenterPosition); } - public void SetVisualPosition(Actor self, WPos pos) { CenterPosition = pos; } + public void SetVisualPosition(Actor self, WPos pos) + { + CenterPosition = pos; + self.World.ScreenMap.Update(self); + } public void SetPosition(Actor self, WPos pos) { - self.World.ActorMap.Remove(self, this); + self.World.ActorMap.RemoveInfluence(self, this); CenterPosition = pos; TopLeft = pos.ToCPos(); - self.World.ActorMap.Add(self, this); + 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/LoadWidgetAtGameStart.cs b/OpenRA.Mods.RA/LoadWidgetAtGameStart.cs index d284e4532d..cb387d7e57 100644 --- a/OpenRA.Mods.RA/LoadWidgetAtGameStart.cs +++ b/OpenRA.Mods.RA/LoadWidgetAtGameStart.cs @@ -8,6 +8,7 @@ */ #endregion +using OpenRA.Graphics; using OpenRA.Traits; using OpenRA.Widgets; @@ -28,7 +29,7 @@ namespace OpenRA.Mods.RA this.Info = Info; } - public void WorldLoaded(World world) + public void WorldLoaded(World world, WorldRenderer wr) { // Clear any existing widget state if (Info.ClearRoot) diff --git a/OpenRA.Mods.RA/MPStartLocations.cs b/OpenRA.Mods.RA/MPStartLocations.cs index a64af630f4..2597fce1ad 100755 --- a/OpenRA.Mods.RA/MPStartLocations.cs +++ b/OpenRA.Mods.RA/MPStartLocations.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Network; using OpenRA.Traits; @@ -26,7 +27,7 @@ namespace OpenRA.Mods.RA { public Dictionary Start = new Dictionary(); - public void WorldLoaded(World world) + public void WorldLoaded(World world, WorldRenderer wr) { var taken = world.LobbyInfo.Clients.Where(c => c.SpawnPoint != 0 && c.Slot != null) .Select(c => (CPos) world.Map.GetSpawnPoints()[c.SpawnPoint-1]).ToList(); diff --git a/OpenRA.Mods.RA/Mine.cs b/OpenRA.Mods.RA/Mine.cs index 3c3ad8df31..aa45da5d14 100644 --- a/OpenRA.Mods.RA/Mine.cs +++ b/OpenRA.Mods.RA/Mine.cs @@ -26,7 +26,7 @@ namespace OpenRA.Mods.RA public object Create(ActorInitializer init) { return new Mine(init, this); } } - class Mine : ICrushable, IOccupySpace, ISync + class Mine : ICrushable, IOccupySpace, ISync, INotifyAddedToWorld, INotifyRemovedFromWorld { readonly Actor self; readonly MineInfo info; @@ -62,6 +62,20 @@ namespace OpenRA.Mods.RA public IEnumerable> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); } public WPos CenterPosition { get { return location.CenterPosition; } } + + 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); + } } /* tag trait for stuff that shouldnt trigger mines */ diff --git a/OpenRA.Mods.RA/Minelayer.cs b/OpenRA.Mods.RA/Minelayer.cs index a8f56b9913..d52144080c 100644 --- a/OpenRA.Mods.RA/Minelayer.cs +++ b/OpenRA.Mods.RA/Minelayer.cs @@ -106,7 +106,8 @@ namespace OpenRA.Mods.RA yield break; } - var underCursor = world.FindUnitsAtMouse(mi.Location) + var underCursor = world.ScreenMap.ActorsAt(Game.viewport.ViewToWorldPx(mi.Location)) + .Where(a => !world.FogObscures(a)) .OrderByDescending(a => a.Info.Traits.Contains() ? a.Info.Traits.Get().Priority : int.MinValue) .FirstOrDefault(); diff --git a/OpenRA.Mods.RA/Missions/Allies01Script.cs b/OpenRA.Mods.RA/Missions/Allies01Script.cs index 789e7c40ed..4f80c447f6 100644 --- a/OpenRA.Mods.RA/Missions/Allies01Script.cs +++ b/OpenRA.Mods.RA/Missions/Allies01Script.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Air; using OpenRA.Mods.RA.Move; @@ -274,7 +275,7 @@ namespace OpenRA.Mods.RA.Missions actor.Trait().stance = UnitStance.Defend; } - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { world = w; diff --git a/OpenRA.Mods.RA/Missions/Allies02Script.cs b/OpenRA.Mods.RA/Missions/Allies02Script.cs index fcd455985f..5a281de234 100644 --- a/OpenRA.Mods.RA/Missions/Allies02Script.cs +++ b/OpenRA.Mods.RA/Missions/Allies02Script.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Air; using OpenRA.Mods.RA.Buildings; @@ -270,7 +271,7 @@ namespace OpenRA.Mods.RA.Missions { new LocationInit(yakEntryPoint.Location), new OwnerInit(soviets), - new FacingInit(Util.GetFacing(yakAttackPoint.Location - yakEntryPoint.Location, 0)), + new FacingInit(Traits.Util.GetFacing(yakAttackPoint.Location - yakEntryPoint.Location, 0)), new AltitudeInit(Rules.Info[YakName].Traits.Get().CruiseAltitude) }); } @@ -405,7 +406,7 @@ namespace OpenRA.Mods.RA.Missions unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Move.Move(townPoint.Location, SovietTownMoveNearEnough))); } - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { world = w; diff --git a/OpenRA.Mods.RA/Missions/Allies03Script.cs b/OpenRA.Mods.RA/Missions/Allies03Script.cs index 9bebeabf7c..b471b023d3 100644 --- a/OpenRA.Mods.RA/Missions/Allies03Script.cs +++ b/OpenRA.Mods.RA/Missions/Allies03Script.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Air; using OpenRA.Mods.RA.Buildings; @@ -335,7 +336,7 @@ namespace OpenRA.Mods.RA.Missions { new OwnerInit(owner), new LocationInit(entry), - new FacingInit(Util.GetFacing(to - entry, 0)) + new FacingInit(Traits.Util.GetFacing(to - entry, 0)) }); unit.QueueActivity(new Move.Move(to)); return unit; @@ -380,7 +381,7 @@ namespace OpenRA.Mods.RA.Missions } } - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { world = w; diff --git a/OpenRA.Mods.RA/Missions/Allies04Script.cs b/OpenRA.Mods.RA/Missions/Allies04Script.cs index 173d461f2a..b880170720 100644 --- a/OpenRA.Mods.RA/Missions/Allies04Script.cs +++ b/OpenRA.Mods.RA/Missions/Allies04Script.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Move; @@ -350,7 +351,7 @@ namespace OpenRA.Mods.RA.Missions actor.Trait().stance = UnitStance.Defend; } - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { world = w; diff --git a/OpenRA.Mods.RA/Missions/DefaultShellmapScript.cs b/OpenRA.Mods.RA/Missions/DefaultShellmapScript.cs index 6dfbbe6371..9114b90693 100644 --- a/OpenRA.Mods.RA/Missions/DefaultShellmapScript.cs +++ b/OpenRA.Mods.RA/Missions/DefaultShellmapScript.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Air; using OpenRA.Traits; @@ -23,7 +24,7 @@ namespace OpenRA.Mods.RA Dictionary Actors; static CPos ViewportOrigin; - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { var b = w.Map.Bounds; ViewportOrigin = new CPos(b.Left + b.Width/2, b.Top + b.Height/2); diff --git a/OpenRA.Mods.RA/Missions/DesertShellmapScript.cs b/OpenRA.Mods.RA/Missions/DesertShellmapScript.cs index c0e8661733..05e9d85525 100644 --- a/OpenRA.Mods.RA/Missions/DesertShellmapScript.cs +++ b/OpenRA.Mods.RA/Missions/DesertShellmapScript.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Air; using OpenRA.Mods.RA.Buildings; @@ -90,7 +91,7 @@ namespace OpenRA.Mods.RA.Missions { var actor = OffmapAttackers.Random(world.SharedRandom); var spawn = offmapAttackerSpawns.Random(world.SharedRandom); - var u = world.CreateActor(actor, soviets, spawn.Location, Util.GetFacing(attackLocation.Location - spawn.Location, 0)); + var u = world.CreateActor(actor, soviets, spawn.Location, Traits.Util.GetFacing(attackLocation.Location - spawn.Location, 0)); var cargo = u.TraitOrDefault(); if (cargo != null) { @@ -176,7 +177,7 @@ namespace OpenRA.Mods.RA.Missions { foreach (var tank in HeavyTanks) { - var u = world.CreateActor(tank, soviets, heavyTankSpawn.Location, Util.GetFacing(heavyTankWP.Location - heavyTankSpawn.Location, 0)); + var u = world.CreateActor(tank, soviets, heavyTankSpawn.Location, Traits.Util.GetFacing(heavyTankWP.Location - heavyTankSpawn.Location, 0)); u.QueueActivity(new AttackMove.AttackMoveActivity(u, new Move.Move(heavyTankWP.Location, 0))); } ironCurtain.Trait().Activate(ironCurtain, new Order { TargetLocation = heavyTankSpawn.Location }); @@ -187,7 +188,7 @@ namespace OpenRA.Mods.RA.Missions var chronoInfo = new List>(); foreach (var tank in MediumTanks.Select((x, i) => new { x, i })) { - var u = world.CreateActor(tank.x, allies, mediumTankChronoSpawn.Location, Util.GetFacing(heavyTankWP.Location - mediumTankChronoSpawn.Location, 0)); + var u = world.CreateActor(tank.x, allies, mediumTankChronoSpawn.Location, Traits.Util.GetFacing(heavyTankWP.Location - mediumTankChronoSpawn.Location, 0)); chronoInfo.Add(Pair.New(u, new CPos(mediumTankChronoSpawn.Location.X + tank.i, mediumTankChronoSpawn.Location.Y))); } RASpecialPowers.Chronoshift(world, chronoInfo, chronosphere, -1, false); @@ -201,7 +202,7 @@ namespace OpenRA.Mods.RA.Missions { new OwnerInit(soviets), new LocationInit(waypoints[0]), - new FacingInit(Util.GetFacing(waypoints[1] - waypoints[0], 0)) + new FacingInit(Traits.Util.GetFacing(waypoints[1] - waypoints[0], 0)) }); foreach (var waypoint in waypoints) m.QueueActivity(Fly.ToCell(waypoint)); @@ -210,7 +211,7 @@ namespace OpenRA.Mods.RA.Missions void SendChinookReinforcements(CPos entry, Actor lz) { - var chinook = world.CreateActor("tran", allies, entry, Util.GetFacing(lz.Location - entry, 0)); + var chinook = world.CreateActor("tran", allies, entry, Traits.Util.GetFacing(lz.Location - entry, 0)); var cargo = chinook.Trait(); while (cargo.HasSpace(1)) @@ -234,7 +235,7 @@ namespace OpenRA.Mods.RA.Missions alliedWarFactory.Trait().SetPrimaryProducer(alliedWarFactory, true); } - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { world = w; diff --git a/OpenRA.Mods.RA/Missions/FortLonestarScript.cs b/OpenRA.Mods.RA/Missions/FortLonestarScript.cs index bc4360879a..51604bdc88 100644 --- a/OpenRA.Mods.RA/Missions/FortLonestarScript.cs +++ b/OpenRA.Mods.RA/Missions/FortLonestarScript.cs @@ -12,6 +12,7 @@ using System; using System.Drawing; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Move; @@ -342,7 +343,7 @@ namespace OpenRA.Mods.RA.Missions bool SpawnVehicles = true; - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { world = w; soviets = w.Players.Single(p => p.InternalName == "Soviets"); diff --git a/OpenRA.Mods.RA/Missions/MonsterTankMadnessScript.cs b/OpenRA.Mods.RA/Missions/MonsterTankMadnessScript.cs index 6b4da0cd2d..78793f84e8 100644 --- a/OpenRA.Mods.RA/Missions/MonsterTankMadnessScript.cs +++ b/OpenRA.Mods.RA/Missions/MonsterTankMadnessScript.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using System.Linq; +using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Move; @@ -258,7 +259,7 @@ namespace OpenRA.Mods.RA.Missions { Sound.Play("reinfor1.aud"); foreach (var unit in units) - world.CreateActor(unit, greece, startEntryPoint.Location, Util.GetFacing(startBridgeEndPoint.CenterPosition - startEntryPoint.CenterPosition, 0)) + world.CreateActor(unit, greece, startEntryPoint.Location, Traits.Util.GetFacing(startBridgeEndPoint.CenterPosition - startEntryPoint.CenterPosition, 0)) .QueueActivity(new Move.Move(startMovePoint.Location, 0)); } @@ -266,7 +267,7 @@ namespace OpenRA.Mods.RA.Missions { Sound.Play("reinfor1.aud"); foreach (var unit in units) - world.CreateActor(unit, greece, alliedBaseEntryPoint.Location, Util.GetFacing(alliedBaseMovePoint.CenterPosition - alliedBaseEntryPoint.CenterPosition, 0)) + world.CreateActor(unit, greece, alliedBaseEntryPoint.Location, Traits.Util.GetFacing(alliedBaseMovePoint.CenterPosition - alliedBaseEntryPoint.CenterPosition, 0)) .QueueActivity(new Move.Move(alliedBaseMovePoint.Location, 0)); } @@ -294,7 +295,7 @@ namespace OpenRA.Mods.RA.Missions OnObjectivesUpdated(true); } - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { world = w; diff --git a/OpenRA.Mods.RA/Missions/Soviet01ClassicScript.cs b/OpenRA.Mods.RA/Missions/Soviet01ClassicScript.cs index b910b948e9..257221e235 100644 --- a/OpenRA.Mods.RA/Missions/Soviet01ClassicScript.cs +++ b/OpenRA.Mods.RA/Missions/Soviet01ClassicScript.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Air; using OpenRA.Mods.RA.Buildings; @@ -107,7 +108,7 @@ namespace OpenRA.Mods.RA.Missions { new OwnerInit(ussr), new LocationInit(entry), - new FacingInit(Util.GetFacing(airfield.Location - entry, 0)), + new FacingInit(Traits.Util.GetFacing(airfield.Location - entry, 0)), new AltitudeInit(Rules.Info["yak"].Traits.Get().CruiseAltitude) }); @@ -133,7 +134,7 @@ namespace OpenRA.Mods.RA.Missions })); } - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { world = w; diff --git a/OpenRA.Mods.RA/Missions/Survival01Script.cs b/OpenRA.Mods.RA/Missions/Survival01Script.cs index 4a77635de2..f4365ead65 100644 --- a/OpenRA.Mods.RA/Missions/Survival01Script.cs +++ b/OpenRA.Mods.RA/Missions/Survival01Script.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Move; @@ -271,7 +272,7 @@ namespace OpenRA.Mods.RA.Missions OnObjectivesUpdated(true); } - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { world = w; diff --git a/OpenRA.Mods.RA/Missions/Survival02Script.cs b/OpenRA.Mods.RA/Missions/Survival02Script.cs index 47b54ab47b..d8180c21ab 100644 --- a/OpenRA.Mods.RA/Missions/Survival02Script.cs +++ b/OpenRA.Mods.RA/Missions/Survival02Script.cs @@ -13,6 +13,7 @@ using System.Linq; using System; using System.Drawing; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Move; using OpenRA.Traits; @@ -351,7 +352,7 @@ namespace OpenRA.Mods.RA.Missions bool producing = true; - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { world = w; allies = w.Players.SingleOrDefault(p => p.InternalName == "Allies"); diff --git a/OpenRA.Mods.RA/Move/Mobile.cs b/OpenRA.Mods.RA/Move/Mobile.cs index 5f5345e0b5..fb315d6267 100755 --- a/OpenRA.Mods.RA/Move/Mobile.cs +++ b/OpenRA.Mods.RA/Move/Mobile.cs @@ -144,7 +144,7 @@ namespace OpenRA.Mods.RA.Move public int GetInitialFacing() { return InitialFacing; } } - public class Mobile : IIssueOrder, IResolveOrder, IOrderVoice, IPositionable, IMove, IFacing, ISync + public class Mobile : IIssueOrder, IResolveOrder, IOrderVoice, IPositionable, IMove, IFacing, ISync, INotifyAddedToWorld, INotifyRemovedFromWorld { public readonly Actor self; public readonly MobileInfo Info; @@ -231,6 +231,25 @@ namespace OpenRA.Mods.RA.Move public void SetVisualPosition(Actor self, WPos pos) { 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); } public IEnumerable Orders { get { yield return new MoveOrderTargeter(Info); } } @@ -430,13 +449,13 @@ namespace OpenRA.Mods.RA.Move public void AddInfluence() { if (self.IsInWorld) - self.World.ActorMap.Add(self, this); + self.World.ActorMap.AddInfluence(self, this); } public void RemoveInfluence() { if (self.IsInWorld) - self.World.ActorMap.Remove(self, this); + self.World.ActorMap.RemoveInfluence(self, this); } public void Nudge(Actor self, Actor nudger, bool force) diff --git a/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs b/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs index 2a0eecc226..dc600a5407 100755 --- a/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs +++ b/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs @@ -39,9 +39,8 @@ namespace OpenRA.Mods.RA.Orders { if (mi.Button == MouseButton.Left) { - var underCursor = world.FindUnitsAtMouse(mi.Location) - .Where(a => a.Owner == world.LocalPlayer - && a.HasTrait()).FirstOrDefault(); + var underCursor = world.ScreenMap.ActorsAt(Game.viewport.ViewToWorldPx(mi.Location)) + .Where(a => a.Owner == world.LocalPlayer && a.HasTrait()).FirstOrDefault(); if (underCursor != null) yield return new Order(order, underCursor, false); diff --git a/OpenRA.Mods.RA/Orders/RepairOrderGenerator.cs b/OpenRA.Mods.RA/Orders/RepairOrderGenerator.cs index d57d624c36..c2d931ba4a 100644 --- a/OpenRA.Mods.RA/Orders/RepairOrderGenerator.cs +++ b/OpenRA.Mods.RA/Orders/RepairOrderGenerator.cs @@ -30,8 +30,8 @@ namespace OpenRA.Mods.RA.Orders { if (mi.Button == MouseButton.Left) { - var underCursor = world.FindUnitsAtMouse(mi.Location) - .Where(a => a.AppearsFriendlyTo(world.LocalPlayer.PlayerActor) && a.HasTrait()).FirstOrDefault(); + var underCursor = world.ScreenMap.ActorsAt(Game.viewport.ViewToWorldPx(mi.Location)) + .Where(a => !world.FogObscures(a) && a.AppearsFriendlyTo(world.LocalPlayer.PlayerActor) && a.HasTrait()).FirstOrDefault(); if (underCursor == null) yield break; diff --git a/OpenRA.Mods.RA/SpawnMPUnits.cs b/OpenRA.Mods.RA/SpawnMPUnits.cs index e7c093b591..e824df78a6 100644 --- a/OpenRA.Mods.RA/SpawnMPUnits.cs +++ b/OpenRA.Mods.RA/SpawnMPUnits.cs @@ -12,6 +12,7 @@ using System; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Move; using OpenRA.Traits; @@ -21,7 +22,7 @@ namespace OpenRA.Mods.RA public class SpawnMPUnits : IWorldLoaded { - public void WorldLoaded(World world) + public void WorldLoaded(World world, WorldRenderer wr) { foreach (var s in world.WorldActor.Trait().Start) SpawnUnitsForPlayer(world, s.Key, s.Value); diff --git a/OpenRA.Mods.RA/SpawnMapActors.cs b/OpenRA.Mods.RA/SpawnMapActors.cs index 2d116499f4..5999564846 100644 --- a/OpenRA.Mods.RA/SpawnMapActors.cs +++ b/OpenRA.Mods.RA/SpawnMapActors.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Linq; +using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -20,7 +21,7 @@ namespace OpenRA.Mods.RA { public Dictionary Actors = new Dictionary(); - public void WorldLoaded(World world) + public void WorldLoaded(World world, WorldRenderer wr) { foreach (var actorReference in world.Map.Actors.Value) { diff --git a/OpenRA.Mods.RA/World/DebugOverlay.cs b/OpenRA.Mods.RA/World/DebugOverlay.cs index 9afb185bc9..729a953f6a 100644 --- a/OpenRA.Mods.RA/World/DebugOverlay.cs +++ b/OpenRA.Mods.RA/World/DebugOverlay.cs @@ -20,7 +20,7 @@ namespace OpenRA.Mods.RA World world; public bool Visible; - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { this.world = w; this.refreshTick = 0; diff --git a/OpenRA.Mods.RA/World/DomainIndex.cs b/OpenRA.Mods.RA/World/DomainIndex.cs index 72551e1374..d5490afd15 100644 --- a/OpenRA.Mods.RA/World/DomainIndex.cs +++ b/OpenRA.Mods.RA/World/DomainIndex.cs @@ -14,6 +14,7 @@ using System.Drawing; using System.Linq; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Mods.RA.Move; using OpenRA.Support; using OpenRA.Traits; @@ -27,7 +28,7 @@ namespace OpenRA.Mods.RA { Dictionary domainIndexes; - public void WorldLoaded(World world) + public void WorldLoaded(World world, WorldRenderer wr) { domainIndexes = new Dictionary(); var movementClasses = new HashSet( diff --git a/OpenRA.Mods.RA/World/PlayMusicOnMapLoad.cs b/OpenRA.Mods.RA/World/PlayMusicOnMapLoad.cs index b9c0669ad3..fe60262301 100644 --- a/OpenRA.Mods.RA/World/PlayMusicOnMapLoad.cs +++ b/OpenRA.Mods.RA/World/PlayMusicOnMapLoad.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Traits; using OpenRA.Widgets; @@ -30,7 +31,7 @@ namespace OpenRA.Mods.RA public PlayMusicOnMapLoad(PlayMusicOnMapLoadInfo info) { Info = info; } - public void WorldLoaded(World w) { PlayMusic(); } + public void WorldLoaded(World w, WorldRenderer wr) { PlayMusic(); } void PlayMusic() { diff --git a/OpenRA.Mods.RA/World/ResourceClaimLayer.cs b/OpenRA.Mods.RA/World/ResourceClaimLayer.cs index 1228f7b67d..80e1aaf7dd 100644 --- a/OpenRA.Mods.RA/World/ResourceClaimLayer.cs +++ b/OpenRA.Mods.RA/World/ResourceClaimLayer.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -34,7 +35,7 @@ namespace OpenRA.Mods.RA } } - public void WorldLoaded(OpenRA.World w) + public void WorldLoaded(OpenRA.World w, WorldRenderer wr) { // NOTE(jsd): 32 seems a sane default initial capacity for the total # of harvesters in a game. Purely a guesstimate. claimByCell = new Dictionary(32); diff --git a/OpenRA.Mods.RA/World/SmudgeLayer.cs b/OpenRA.Mods.RA/World/SmudgeLayer.cs index dda25e7a34..f70e3313eb 100644 --- a/OpenRA.Mods.RA/World/SmudgeLayer.cs +++ b/OpenRA.Mods.RA/World/SmudgeLayer.cs @@ -43,7 +43,7 @@ namespace OpenRA.Mods.RA smudgeSprites = Info.Types.Select(x => Game.modData.SpriteLoader.LoadAllSprites(x)).ToArray(); } - public void WorldLoaded(World w) + public void WorldLoaded(World w, WorldRenderer wr) { world = w; tiles = new Dictionary>(); diff --git a/mods/cnc/rules/system.yaml b/mods/cnc/rules/system.yaml index 4d1ce3e2da..748199d14b 100644 --- a/mods/cnc/rules/system.yaml +++ b/mods/cnc/rules/system.yaml @@ -206,6 +206,8 @@ Player: FrozenActorLayer: World: + ScreenMap: + ActorMap: LoadWidgetAtGameStart: Widget: INGAME_ROOT CncMenuPaletteEffect: @@ -363,8 +365,6 @@ World: BaseActor: mcv SupportActors: e1,e1,e1,e1,e1,e2,e2,e2,e3,e3,apc,mtnk SpawnMPUnits: - SpatialBins: - BinSize: 4 CrateSpawner: Minimum: 1 Maximum: 6 diff --git a/mods/d2k/rules/system.yaml b/mods/d2k/rules/system.yaml index 94d209e1dc..f719298a56 100644 --- a/mods/d2k/rules/system.yaml +++ b/mods/d2k/rules/system.yaml @@ -357,6 +357,8 @@ Player: PlayerStatistics: World: + ScreenMap: + ActorMap: LoadWidgetAtGameStart: Widget: INGAME_ROOT ScreenShaker: @@ -474,8 +476,6 @@ World: Races: ordos BaseActor: mcvo SpawnMPUnits: - SpatialBins: - BinSize: 4 PathFinder: ValidateOrder: DebugPauseState: diff --git a/mods/ra/rules/system.yaml b/mods/ra/rules/system.yaml index 14f64b79c1..4881555cd3 100644 --- a/mods/ra/rules/system.yaml +++ b/mods/ra/rules/system.yaml @@ -529,6 +529,8 @@ Player: PlayerStatistics: World: + ScreenMap: + ActorMap: LoadWidgetAtGameStart: Widget: INGAME_ROOT ScreenShaker: @@ -680,8 +682,6 @@ World: OuterSupportRadius: 5 MPStartLocations: SpawnMPUnits: - SpatialBins: - BinSize: 4 PathFinder: ValidateOrder: DebugPauseState: diff --git a/mods/ts/rules/system.yaml b/mods/ts/rules/system.yaml index 5a5bfdb1dd..d0567f83e1 100644 --- a/mods/ts/rules/system.yaml +++ b/mods/ts/rules/system.yaml @@ -42,6 +42,8 @@ Player: PlayerStatistics: World: + ScreenMap: + ActorMap: LoadWidgetAtGameStart: Widget: INGAME_ROOT BuildingInfluence: @@ -122,8 +124,6 @@ World: BaseActor: mcv MPStartLocations: SpawnMPUnits: - SpatialBins: - BinSize: 4 PathFinder: ValidateOrder: DebugPauseState: