diff --git a/OpenRA.Game/Actor.cs b/OpenRA.Game/Actor.cs index d92e2f6998..fcfe5d1530 100644 --- a/OpenRA.Game/Actor.cs +++ b/OpenRA.Game/Actor.cs @@ -77,6 +77,7 @@ namespace OpenRA readonly IHealth health; readonly IRenderModifier[] renderModifiers; readonly IRender[] renders; + readonly IMouseBounds[] mouseBounds; readonly IDisable[] disables; readonly IVisibilityModifier[] visibilityModifiers; readonly IDefaultVisibility defaultVisibility; @@ -125,6 +126,7 @@ namespace OpenRA health = TraitOrDefault(); renderModifiers = TraitsImplementing().ToArray(); renders = TraitsImplementing().ToArray(); + mouseBounds = TraitsImplementing().ToArray(); disables = TraitsImplementing().ToArray(); visibilityModifiers = TraitsImplementing().ToArray(); defaultVisibility = Trait(); @@ -221,6 +223,18 @@ namespace OpenRA yield return r; } + public Rectangle MouseBounds(WorldRenderer wr) + { + foreach (var mb in mouseBounds) + { + var bounds = mb.MouseoverBounds(this, wr); + if (!bounds.IsEmpty) + return bounds; + } + + return Rectangle.Empty; + } + public void QueueActivity(bool queued, Activity nextActivity) { if (!queued) diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index d88b3c78cb..36f1f2f495 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -102,7 +102,7 @@ namespace OpenRA.Graphics List GenerateRenderables() { - var actors = World.ScreenMap.ActorsInBox(Viewport.TopLeft, Viewport.BottomRight).Append(World.WorldActor); + var actors = World.ScreenMap.RenderableActorsInBox(Viewport.TopLeft, Viewport.BottomRight).Append(World.WorldActor); if (World.RenderPlayer != null) actors = actors.Append(World.RenderPlayer.PlayerActor); @@ -114,7 +114,7 @@ namespace OpenRA.Graphics worldRenderables = worldRenderables.Concat(World.UnpartitionedEffects.SelectMany(e => e.Render(this))); // Partitioned, currently on-screen effects - var effectRenderables = World.ScreenMap.EffectsInBox(Viewport.TopLeft, Viewport.BottomRight); + var effectRenderables = World.ScreenMap.RenderableEffectsInBox(Viewport.TopLeft, Viewport.BottomRight); worldRenderables = worldRenderables.Concat(effectRenderables.SelectMany(e => e.Render(this))); worldRenderables = worldRenderables.OrderBy(RenderableScreenZPositionComparisonKey); @@ -213,12 +213,20 @@ namespace OpenRA.Graphics } if (debugVis.Value != null && debugVis.Value.ScreenMap) - foreach (var r in World.ScreenMap.ItemBounds(World.RenderPlayer)) + { + foreach (var r in World.ScreenMap.RenderBounds(World.RenderPlayer)) Game.Renderer.WorldRgbaColorRenderer.DrawRect( new float3(r.Left, r.Top, r.Bottom), new float3(r.Right, r.Bottom, r.Bottom), 1 / Viewport.Zoom, Color.MediumSpringGreen); + foreach (var r in World.ScreenMap.MouseBounds(World.RenderPlayer)) + Game.Renderer.WorldRgbaColorRenderer.DrawRect( + new float3(r.Left, r.Top, r.Bottom), + new float3(r.Right, r.Bottom, r.Bottom), + 1 / Viewport.Zoom, Color.OrangeRed); + } + Game.Renderer.Flush(); } diff --git a/OpenRA.Game/Orders/GenericSelectTarget.cs b/OpenRA.Game/Orders/GenericSelectTarget.cs index 8d311b1f6d..1e9411d308 100644 --- a/OpenRA.Game/Orders/GenericSelectTarget.cs +++ b/OpenRA.Game/Orders/GenericSelectTarget.cs @@ -10,6 +10,7 @@ #endregion using System.Collections.Generic; +using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Orders @@ -62,7 +63,7 @@ namespace OpenRA.Orders return world.Map.Contains(cell) ? Cursor : "generic-blocked"; } - public override bool InputOverridesSelection(World world, int2 xy, MouseInput mi) + public override bool InputOverridesSelection(WorldRenderer wr, World world, int2 xy, MouseInput mi) { // Custom order generators always override selection return true; diff --git a/OpenRA.Game/Orders/UnitOrderGenerator.cs b/OpenRA.Game/Orders/UnitOrderGenerator.cs index e18fef5658..0390a3f67a 100644 --- a/OpenRA.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRA.Game/Orders/UnitOrderGenerator.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Orders @@ -20,14 +21,14 @@ namespace OpenRA.Orders { static Target TargetForInput(World world, CPos cell, int2 worldPixel, MouseInput mi) { - var actor = world.ScreenMap.ActorsAt(mi) - .Where(a => a.Info.HasTraitInfo() && !world.FogObscures(a)) + var actor = world.ScreenMap.ActorsAtMouse(mi) + .Where(a => a.Actor.Info.HasTraitInfo() && !world.FogObscures(a.Actor)) .WithHighestSelectionPriority(worldPixel); if (actor != null) return Target.FromActor(actor); - var frozen = world.ScreenMap.FrozenActorsAt(world.RenderPlayer, mi) + var frozen = world.ScreenMap.FrozenActorsAtMouse(world.RenderPlayer, mi) .Where(a => a.Info.HasTraitInfo() && a.Visible && a.HasRenderables) .WithHighestSelectionPriority(worldPixel); @@ -78,16 +79,18 @@ namespace OpenRA.Orders } // Used for classic mouse orders, determines whether or not action at xy is move or select - public virtual bool InputOverridesSelection(World world, int2 xy, MouseInput mi) + public virtual bool InputOverridesSelection(WorldRenderer wr, World world, int2 xy, MouseInput mi) { - var actor = world.ScreenMap.ActorsAt(xy).WithHighestSelectionPriority(xy); + var actor = world.ScreenMap.ActorsAtMouse(xy).WithHighestSelectionPriority(xy); if (actor == null) return true; var target = Target.FromActor(actor); var cell = world.Map.CellContaining(target.CenterPosition); var actorsAt = world.ActorMap.GetActorsAt(cell).ToList(); - var underCursor = world.Selection.Actors.WithHighestSelectionPriority(xy); + var underCursor = world.Selection.Actors + .Select(a => new ActorBoundsPair(a, a.MouseBounds(wr))) + .WithHighestSelectionPriority(xy); var o = OrderForUnit(underCursor, target, actorsAt, cell, mi); if (o != null) diff --git a/OpenRA.Game/SelectableExts.cs b/OpenRA.Game/SelectableExts.cs index b78b5be298..172a9737b1 100644 --- a/OpenRA.Game/SelectableExts.cs +++ b/OpenRA.Game/SelectableExts.cs @@ -13,6 +13,8 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Linq; +using OpenRA.Graphics; +using OpenRA.Primitives; namespace OpenRA.Traits { @@ -45,21 +47,29 @@ namespace OpenRA.Traits } } - public static Actor WithHighestSelectionPriority(this IEnumerable actors, int2 selectionPixel) + public static Actor WithHighestSelectionPriority(this IEnumerable actors, int2 selectionPixel) { - return actors.MaxByOrDefault(a => CalculateActorSelectionPriority(a.Info, a.SelectableBounds, selectionPixel)); + if (!actors.Any()) + return null; + + return actors.MaxBy(a => CalculateActorSelectionPriority(a.Actor.Info, a.Bounds, selectionPixel)).Actor; } public static FrozenActor WithHighestSelectionPriority(this IEnumerable actors, int2 selectionPixel) { - return actors.MaxByOrDefault(a => CalculateActorSelectionPriority(a.Info, a.SelectableBounds, selectionPixel)); + return actors.MaxByOrDefault(a => CalculateActorSelectionPriority(a.Info, a.MouseBounds, selectionPixel)); } static long CalculateActorSelectionPriority(ActorInfo info, Rectangle bounds, int2 selectionPixel) { - var centerPixel = new int2(bounds.X, bounds.Y); - var pixelDistance = (centerPixel - selectionPixel).Length; + if (bounds.IsEmpty) + return info.SelectionPriority(); + var centerPixel = new int2( + bounds.Left + bounds.Size.Width / 2, + bounds.Top + bounds.Size.Height / 2); + + var pixelDistance = (centerPixel - selectionPixel).Length; return ((long)-pixelDistance << 32) + info.SelectionPriority(); } diff --git a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs index 14da553a33..8fbb7673cc 100644 --- a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs +++ b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs @@ -52,6 +52,9 @@ namespace OpenRA.Traits public IRenderable[] Renderables = NoRenderables; public Rectangle[] ScreenBounds = NoBounds; + // TODO: Replace this with an int2[] polygon + public Rectangle MouseBounds = Rectangle.Empty; + static readonly IRenderable[] NoRenderables = new IRenderable[0]; static readonly Rectangle[] NoBounds = new Rectangle[0]; @@ -298,7 +301,7 @@ namespace OpenRA.Traits public virtual IEnumerable Render(Actor self, WorldRenderer wr) { - return world.ScreenMap.FrozenActorsInBox(owner, wr.Viewport.TopLeft, wr.Viewport.BottomRight) + return world.ScreenMap.RenderableFrozenActorsInBox(owner, wr.Viewport.TopLeft, wr.Viewport.BottomRight) .Where(f => f.Visible) .SelectMany(ff => ff.Render(wr)); } diff --git a/OpenRA.Game/Traits/Selectable.cs b/OpenRA.Game/Traits/Selectable.cs index 42ed086a75..8b8c5f685c 100644 --- a/OpenRA.Game/Traits/Selectable.cs +++ b/OpenRA.Game/Traits/Selectable.cs @@ -9,6 +9,10 @@ */ #endregion +using System.Collections.Generic; +using System.Drawing; +using OpenRA.Graphics; + namespace OpenRA.Traits { [Desc("This actor is selectable. Defines bounds of selectable area, selection class and selection priority.")] @@ -19,6 +23,9 @@ namespace OpenRA.Traits [Desc("Bounds for the selectable area.")] public readonly int[] Bounds = null; + [Desc("Area outside the visible selection box that is enabled for selection")] + public readonly int Margin = 0; + [Desc("All units having the same selection class specified will be selected with select-by-type commands (e.g. double-click). " + "Defaults to the actor name when not defined or inherited.")] public readonly string Class = null; @@ -28,7 +35,7 @@ namespace OpenRA.Traits public object Create(ActorInitializer init) { return new Selectable(init.Self, this); } } - public class Selectable + public class Selectable : IMouseBounds { public readonly string Class = null; @@ -39,5 +46,20 @@ namespace OpenRA.Traits Class = string.IsNullOrEmpty(info.Class) ? self.Info.Name : info.Class; Info = info; } + + Rectangle IMouseBounds.MouseoverBounds(Actor self, WorldRenderer wr) + { + if (Info.Bounds == null) + return Rectangle.Empty; + + var size = new int2(Info.Bounds[0], Info.Bounds[1]); + + var offset = -size / 2 - new int2(Info.Margin, Info.Margin); + if (Info.Bounds.Length > 2) + offset += new int2(Info.Bounds[2], Info.Bounds[3]); + + var xy = wr.ScreenPxPosition(self.CenterPosition) + offset; + return new Rectangle(xy.X, xy.Y, size.X + 2 * Info.Margin, size.Y + 2 * Info.Margin); + } } } diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index f66fa09d80..32f059159b 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -105,6 +105,10 @@ namespace OpenRA.Traits public interface IAutoSelectionSizeInfo : ITraitInfoInterface { } public interface IAutoSelectionSize { int2 SelectionSize(Actor self); } + // TODO: Replace Rectangle with an int2[] polygon + public interface IMouseBounds { Rectangle MouseoverBounds(Actor self, WorldRenderer wr); } + public interface IAutoMouseBounds { Rectangle AutoMouseoverBounds(Actor self, WorldRenderer wr); } + public interface IAutoRenderSizeInfo : ITraitInfoInterface { } public interface IAutoRenderSize { int2 RenderSize(Actor self); } diff --git a/OpenRA.Game/Traits/World/ScreenMap.cs b/OpenRA.Game/Traits/World/ScreenMap.cs index dc439fe7dd..2dc7393a7e 100644 --- a/OpenRA.Game/Traits/World/ScreenMap.cs +++ b/OpenRA.Game/Traits/World/ScreenMap.cs @@ -19,6 +19,26 @@ using OpenRA.Primitives; namespace OpenRA.Traits { + public struct ActorBoundsPair : IEquatable + { + public readonly Actor Actor; + + // TODO: Replace this with an int2[] polygon + public readonly Rectangle Bounds; + + public ActorBoundsPair(Actor actor, Rectangle bounds) { Actor = actor; Bounds = bounds; } + + public static bool operator ==(ActorBoundsPair me, ActorBoundsPair other) { return me.Actor == other.Actor && Equals(me.Bounds, other.Bounds); } + public static bool operator !=(ActorBoundsPair me, ActorBoundsPair other) { return !(me == other); } + + public override int GetHashCode() { return Actor.GetHashCode() ^ Bounds.GetHashCode(); } + + public bool Equals(ActorBoundsPair other) { return this == other; } + public override bool Equals(object obj) { return obj is ActorBoundsPair && Equals((ActorBoundsPair)obj); } + + public override string ToString() { return "{0}->{1}".F(Actor.Info.Name, Bounds.GetType().Name); } + } + public class ScreenMapInfo : ITraitInfo { [Desc("Size of partition bins (world pixels)")] @@ -32,9 +52,14 @@ namespace OpenRA.Traits static readonly IEnumerable NoFrozenActors = new FrozenActor[0]; readonly Func frozenActorIsValid = fa => fa.IsValid; readonly Func actorIsInWorld = a => a.IsInWorld; - readonly Cache> partitionedFrozenActors; - readonly SpatiallyPartitioned partitionedActors; - readonly SpatiallyPartitioned partitionedEffects; + readonly Func selectActorAndBounds; + readonly Cache> partitionedMouseFrozenActors; + readonly SpatiallyPartitioned partitionedMouseActors; + readonly Dictionary partitionedMouseActorBounds = new Dictionary(); + + readonly Cache> partitionedRenderableFrozenActors; + readonly SpatiallyPartitioned partitionedRenderableActors; + readonly SpatiallyPartitioned partitionedRenderableEffects; // Updates are done in one pass to ensure all bound changes have been applied readonly HashSet addOrUpdateActors = new HashSet(); @@ -49,14 +74,19 @@ namespace OpenRA.Traits var size = world.Map.Grid.TileSize; var width = world.Map.MapSize.X * size.Width; var height = world.Map.MapSize.Y * size.Height; - partitionedFrozenActors = new Cache>( + + partitionedMouseFrozenActors = new Cache>( _ => new SpatiallyPartitioned(width, height, info.BinSize)); + partitionedMouseActors = new SpatiallyPartitioned(width, height, info.BinSize); + selectActorAndBounds = a => partitionedMouseActorBounds[a]; + + partitionedRenderableFrozenActors = new Cache>( + _ => new SpatiallyPartitioned(width, height, info.BinSize)); + partitionedRenderableActors = new SpatiallyPartitioned(width, height, info.BinSize); + partitionedRenderableEffects = new SpatiallyPartitioned(width, height, info.BinSize); addOrUpdateFrozenActors = new Cache>(_ => new HashSet()); removeFrozenActors = new Cache>(_ => new HashSet()); - - partitionedActors = new SpatiallyPartitioned(width, height, info.BinSize); - partitionedEffects = new SpatiallyPartitioned(width, height, info.BinSize); } public void WorldLoaded(World w, WorldRenderer wr) { worldRenderer = wr; } @@ -94,7 +124,7 @@ namespace OpenRA.Traits var screenHeight = Math.Abs(size.Height); var screenBounds = new Rectangle(screenPos.X - screenWidth / 2, screenPos.Y - screenHeight / 2, screenWidth, screenHeight); if (ValidBounds(screenBounds)) - partitionedEffects.Add(effect, screenBounds); + partitionedRenderableEffects.Add(effect, screenBounds); } public void Add(IEffect effect, WPos position, Sprite sprite) @@ -117,34 +147,41 @@ namespace OpenRA.Traits public void Remove(IEffect effect) { - partitionedEffects.Remove(effect); + partitionedRenderableEffects.Remove(effect); } - bool ValidBounds(Rectangle bounds) + static bool ValidBounds(Rectangle bounds) { return bounds.Width > 0 && bounds.Height > 0; } - public IEnumerable FrozenActorsAt(Player viewer, int2 worldPx) + public IEnumerable FrozenActorsAtMouse(Player viewer, int2 worldPx) { if (viewer == null) return NoFrozenActors; - return partitionedFrozenActors[viewer].At(worldPx).Where(frozenActorIsValid); + + return partitionedMouseFrozenActors[viewer] + .At(worldPx) + .Where(frozenActorIsValid) + .Where(x => x.MouseBounds.Contains(worldPx)); } - public IEnumerable FrozenActorsAt(Player viewer, MouseInput mi) + public IEnumerable FrozenActorsAtMouse(Player viewer, MouseInput mi) { - return FrozenActorsAt(viewer, worldRenderer.Viewport.ViewToWorldPx(mi.Location)); + return FrozenActorsAtMouse(viewer, worldRenderer.Viewport.ViewToWorldPx(mi.Location)); } - public IEnumerable ActorsAt(int2 worldPx) + public IEnumerable ActorsAtMouse(int2 worldPx) { - return partitionedActors.At(worldPx).Where(actorIsInWorld); + return partitionedMouseActors.At(worldPx) + .Where(actorIsInWorld) + .Select(selectActorAndBounds) + .Where(x => x.Bounds.Contains(worldPx)); } - public IEnumerable ActorsAt(MouseInput mi) + public IEnumerable ActorsAtMouse(MouseInput mi) { - return ActorsAt(worldRenderer.Viewport.ViewToWorldPx(mi.Location)); + return ActorsAtMouse(worldRenderer.Viewport.ViewToWorldPx(mi.Location)); } static Rectangle RectWithCorners(int2 a, int2 b) @@ -152,36 +189,35 @@ namespace OpenRA.Traits return 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(int2 a, int2 b) + public IEnumerable ActorsInMouseBox(int2 a, int2 b) { - return ActorsInBox(RectWithCorners(a, b)); + return ActorsInMouseBox(RectWithCorners(a, b)); } - public IEnumerable EffectsInBox(int2 a, int2 b) + public IEnumerable ActorsInMouseBox(Rectangle r) { - return partitionedEffects.InBox(RectWithCorners(a, b)); + return partitionedMouseActors.InBox(r) + .Where(actorIsInWorld) + .Select(selectActorAndBounds) + .Where(x => r.IntersectsWith(x.Bounds)); } - public IEnumerable ActorsInBox(Rectangle r) + public IEnumerable RenderableActorsInBox(int2 a, int2 b) { - return partitionedActors.InBox(r).Where(actorIsInWorld); + return partitionedRenderableActors.InBox(RectWithCorners(a, b)).Where(actorIsInWorld); } - public IEnumerable FrozenActorsInBox(Player p, int2 a, int2 b) + public IEnumerable RenderableEffectsInBox(int2 a, int2 b) { - return FrozenActorsInBox(p, RectWithCorners(a, b)); + return partitionedRenderableEffects.InBox(RectWithCorners(a, b)); } - public IEnumerable EffectsInBox(Rectangle r) - { - return partitionedEffects.InBox(r); - } - - public IEnumerable FrozenActorsInBox(Player p, Rectangle r) + public IEnumerable RenderableFrozenActorsInBox(Player p, int2 a, int2 b) { if (p == null) return NoFrozenActors; - return partitionedFrozenActors[p].InBox(r).Where(frozenActorIsValid); + + return partitionedRenderableFrozenActors[p].InBox(RectWithCorners(a, b)).Where(frozenActorIsValid); } Rectangle AggregateBounds(IEnumerable screenBounds) @@ -196,24 +232,54 @@ namespace OpenRA.Traits return bounds; } + Rectangle AggregateBounds(IEnumerable vertices) + { + if (!vertices.Any()) + return Rectangle.Empty; + + var first = vertices.First(); + var rect = new Rectangle(first.X, first.Y, 0, 0); + foreach (var v in vertices.Skip(1)) + rect = Rectangle.Union(rect, new Rectangle(v.X, v.Y, 0, 0)); + + return rect; + } + public void Tick() { foreach (var a in addOrUpdateActors) { - var bounds = AggregateBounds(a.ScreenBounds(worldRenderer)); - if (!bounds.Size.IsEmpty) + var mouseBounds = a.MouseBounds(worldRenderer); + if (!mouseBounds.Size.IsEmpty) { - if (partitionedActors.Contains(a)) - partitionedActors.Update(a, bounds); + if (partitionedMouseActors.Contains(a)) + partitionedMouseActors.Update(a, mouseBounds); else - partitionedActors.Add(a, bounds); + partitionedMouseActors.Add(a, mouseBounds); + + partitionedMouseActorBounds[a] = new ActorBoundsPair(a, mouseBounds); } else - partitionedActors.Remove(a); + partitionedMouseActors.Remove(a); + + var screenBounds = AggregateBounds(a.ScreenBounds(worldRenderer)); + if (!screenBounds.Size.IsEmpty) + { + if (partitionedRenderableActors.Contains(a)) + partitionedRenderableActors.Update(a, screenBounds); + else + partitionedRenderableActors.Add(a, screenBounds); + } + else + partitionedRenderableActors.Remove(a); } foreach (var a in removeActors) - partitionedActors.Remove(a); + { + partitionedMouseActors.Remove(a); + partitionedMouseActorBounds.Remove(a); + partitionedRenderableActors.Remove(a); + } addOrUpdateActors.Clear(); removeActors.Clear(); @@ -222,16 +288,27 @@ namespace OpenRA.Traits { foreach (var fa in kv.Value) { - var bounds = AggregateBounds(fa.ScreenBounds); - if (!bounds.Size.IsEmpty) + var mouseBounds = fa.MouseBounds; + if (!mouseBounds.Size.IsEmpty) { - if (partitionedFrozenActors[kv.Key].Contains(fa)) - partitionedFrozenActors[kv.Key].Update(fa, bounds); + if (partitionedMouseFrozenActors[kv.Key].Contains(fa)) + partitionedMouseFrozenActors[kv.Key].Update(fa, mouseBounds); else - partitionedFrozenActors[kv.Key].Add(fa, bounds); + partitionedMouseFrozenActors[kv.Key].Add(fa, mouseBounds); } else - partitionedFrozenActors[kv.Key].Remove(fa); + partitionedMouseFrozenActors[kv.Key].Remove(fa); + + var screenBounds = AggregateBounds(fa.ScreenBounds); + if (!screenBounds.Size.IsEmpty) + { + if (partitionedRenderableFrozenActors[kv.Key].Contains(fa)) + partitionedRenderableFrozenActors[kv.Key].Update(fa, screenBounds); + else + partitionedRenderableFrozenActors[kv.Key].Add(fa, screenBounds); + } + else + partitionedRenderableFrozenActors[kv.Key].Remove(fa); } kv.Value.Clear(); @@ -240,18 +317,28 @@ namespace OpenRA.Traits foreach (var kv in removeFrozenActors) { foreach (var fa in kv.Value) - partitionedFrozenActors[kv.Key].Remove(fa); + { + partitionedMouseFrozenActors[kv.Key].Remove(fa); + partitionedRenderableFrozenActors[kv.Key].Remove(fa); + } kv.Value.Clear(); } } - public IEnumerable ItemBounds(Player viewer) + public IEnumerable RenderBounds(Player viewer) { - var bounds = partitionedActors.ItemBounds - .Concat(partitionedEffects.ItemBounds); + var bounds = partitionedRenderableActors.ItemBounds + .Concat(partitionedRenderableEffects.ItemBounds); - return viewer != null ? bounds.Concat(partitionedFrozenActors[viewer].ItemBounds) : bounds; + return viewer != null ? bounds.Concat(partitionedRenderableFrozenActors[viewer].ItemBounds) : bounds; + } + + public IEnumerable MouseBounds(Player viewer) + { + var bounds = partitionedMouseActors.ItemBounds; + + return viewer != null ? bounds.Concat(partitionedMouseFrozenActors[viewer].ItemBounds) : bounds; } } } diff --git a/OpenRA.Mods.Cnc/Traits/Minelayer.cs b/OpenRA.Mods.Cnc/Traits/Minelayer.cs index 7e49e1af74..e3a98b0d77 100644 --- a/OpenRA.Mods.Cnc/Traits/Minelayer.cs +++ b/OpenRA.Mods.Cnc/Traits/Minelayer.cs @@ -186,7 +186,8 @@ namespace OpenRA.Mods.Cnc.Traits yield break; } - var underCursor = world.ScreenMap.ActorsAt(mi) + var underCursor = world.ScreenMap.ActorsAtMouse(mi) + .Select(a => a.Actor) .Where(a => !world.FogObscures(a)) .MaxByOrDefault(a => a.Info.HasTraitInfo() ? a.Info.TraitInfo().Priority : int.MinValue); diff --git a/OpenRA.Mods.Cnc/Traits/Render/WithVoxelUnloadBody.cs b/OpenRA.Mods.Cnc/Traits/Render/WithVoxelUnloadBody.cs index 5bde4b9898..9ce1ad7f69 100644 --- a/OpenRA.Mods.Cnc/Traits/Render/WithVoxelUnloadBody.cs +++ b/OpenRA.Mods.Cnc/Traits/Render/WithVoxelUnloadBody.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; @@ -45,22 +46,26 @@ namespace OpenRA.Mods.Cnc.Traits.Render } } - public class WithVoxelUnloadBody : IAutoSelectionSize, IAutoRenderSize + public class WithVoxelUnloadBody : IAutoSelectionSize, IAutoRenderSize, IAutoMouseBounds { public bool Docked; readonly int2 size; + readonly ModelAnimation modelAnimation; + readonly RenderVoxels rv; public WithVoxelUnloadBody(Actor self, WithVoxelUnloadBodyInfo info) { var body = self.Trait(); - var rv = self.Trait(); + rv = self.Trait(); var idleModel = self.World.ModelCache.GetModelSequence(rv.Image, info.IdleSequence); - rv.Add(new ModelAnimation(idleModel, () => WVec.Zero, + modelAnimation = new ModelAnimation(idleModel, () => WVec.Zero, () => new[] { body.QuantizeOrientation(self, self.Orientation) }, () => Docked, - () => 0, info.ShowShadow)); + () => 0, info.ShowShadow); + + rv.Add(modelAnimation); // Selection size var rvi = self.Info.TraitInfo(); @@ -76,5 +81,10 @@ namespace OpenRA.Mods.Cnc.Traits.Render int2 IAutoSelectionSize.SelectionSize(Actor self) { return size; } int2 IAutoRenderSize.RenderSize(Actor self) { return size; } + + Rectangle IAutoMouseBounds.AutoMouseoverBounds(Actor self, WorldRenderer wr) + { + return modelAnimation.ScreenBounds(self.CenterPosition, wr, rv.Info.Scale); + } } } diff --git a/OpenRA.Mods.Cnc/Traits/Render/WithVoxelWalkerBody.cs b/OpenRA.Mods.Cnc/Traits/Render/WithVoxelWalkerBody.cs index e047246778..26ccbc381c 100644 --- a/OpenRA.Mods.Cnc/Traits/Render/WithVoxelWalkerBody.cs +++ b/OpenRA.Mods.Cnc/Traits/Render/WithVoxelWalkerBody.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common; @@ -47,12 +48,15 @@ namespace OpenRA.Mods.Cnc.Traits.Render } } - public class WithVoxelWalkerBody : IAutoSelectionSize, ITick, IActorPreviewInitModifier, IAutoRenderSize + public class WithVoxelWalkerBody : IAutoSelectionSize, ITick, IActorPreviewInitModifier, IAutoRenderSize, IAutoMouseBounds { readonly WithVoxelWalkerBodyInfo info; readonly IMove movement; readonly IFacing facing; readonly int2 size; + readonly ModelAnimation modelAnimation; + readonly RenderVoxels rv; + int oldFacing; uint tick, frame, frames; @@ -63,13 +67,15 @@ namespace OpenRA.Mods.Cnc.Traits.Render facing = self.Trait(); var body = self.Trait(); - var rv = self.Trait(); + rv = self.Trait(); var model = self.World.ModelCache.GetModelSequence(rv.Image, info.Sequence); frames = model.Frames; - rv.Add(new ModelAnimation(model, () => WVec.Zero, + modelAnimation = new ModelAnimation(model, () => WVec.Zero, () => new[] { body.QuantizeOrientation(self, self.Orientation) }, - () => false, () => frame, info.ShowShadow)); + () => false, () => frame, info.ShowShadow); + + rv.Add(modelAnimation); // Selection size var rvi = self.Info.TraitInfo(); @@ -98,6 +104,11 @@ namespace OpenRA.Mods.Cnc.Traits.Render { inits.Add(new BodyAnimationFrameInit(frame)); } + + Rectangle IAutoMouseBounds.AutoMouseoverBounds(Actor self, WorldRenderer wr) + { + return modelAnimation.ScreenBounds(self.CenterPosition, wr, rv.Info.Scale); + } } public class BodyAnimationFrameInit : IActorInit diff --git a/OpenRA.Mods.Common/Orders/GlobalButtonOrderGenerator.cs b/OpenRA.Mods.Common/Orders/GlobalButtonOrderGenerator.cs index 1e782c47f1..6b8f79c4a6 100644 --- a/OpenRA.Mods.Common/Orders/GlobalButtonOrderGenerator.cs +++ b/OpenRA.Mods.Common/Orders/GlobalButtonOrderGenerator.cs @@ -37,7 +37,8 @@ namespace OpenRA.Mods.Common.Orders { if (mi.Button == MouseButton.Left) { - var underCursor = world.ScreenMap.ActorsAt(mi) + var underCursor = world.ScreenMap.ActorsAtMouse(mi) + .Select(a => a.Actor) .FirstOrDefault(a => a.Owner == world.LocalPlayer && a.TraitsImplementing() .Any(Exts.IsTraitEnabled)); diff --git a/OpenRA.Mods.Common/Orders/GuardOrderGenerator.cs b/OpenRA.Mods.Common/Orders/GuardOrderGenerator.cs index 1898f6a3f4..99ebe50273 100644 --- a/OpenRA.Mods.Common/Orders/GuardOrderGenerator.cs +++ b/OpenRA.Mods.Common/Orders/GuardOrderGenerator.cs @@ -59,7 +59,8 @@ namespace OpenRA.Mods.Common.Orders static IEnumerable FriendlyGuardableUnits(World world, MouseInput mi) { - return world.ScreenMap.ActorsAt(mi) + return world.ScreenMap.ActorsAtMouse(mi) + .Select(a => a.Actor) .Where(a => !a.IsDead && a.AppearsFriendlyTo(world.LocalPlayer.PlayerActor) && a.Info.HasTraitInfo() && diff --git a/OpenRA.Mods.Common/Orders/RepairOrderGenerator.cs b/OpenRA.Mods.Common/Orders/RepairOrderGenerator.cs index f20645ce54..98c050de66 100644 --- a/OpenRA.Mods.Common/Orders/RepairOrderGenerator.cs +++ b/OpenRA.Mods.Common/Orders/RepairOrderGenerator.cs @@ -32,7 +32,8 @@ namespace OpenRA.Mods.Common.Orders if (mi.Button != MouseButton.Left) yield break; - var underCursor = world.ScreenMap.ActorsAt(mi) + var underCursor = world.ScreenMap.ActorsAtMouse(mi) + .Select(a => a.Actor) .FirstOrDefault(a => a.AppearsFriendlyTo(world.LocalPlayer.PlayerActor) && !world.FogObscures(a)); if (underCursor == null) diff --git a/OpenRA.Mods.Common/Traits/AttackMove.cs b/OpenRA.Mods.Common/Traits/AttackMove.cs index 8330e3dc84..62a1bbb936 100644 --- a/OpenRA.Mods.Common/Traits/AttackMove.cs +++ b/OpenRA.Mods.Common/Traits/AttackMove.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; +using OpenRA.Graphics; using OpenRA.Mods.Common.Activities; using OpenRA.Orders; using OpenRA.Traits; @@ -178,7 +179,7 @@ namespace OpenRA.Mods.Common.Traits return prefix + "-blocked"; } - public override bool InputOverridesSelection(World world, int2 xy, MouseInput mi) + public override bool InputOverridesSelection(WorldRenderer wr, World world, int2 xy, MouseInput mi) { // Custom order generators always override selection return true; diff --git a/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs b/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs index 4c85716329..6998484edc 100644 --- a/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs +++ b/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs @@ -128,6 +128,7 @@ namespace OpenRA.Mods.Common.Traits { IRenderable[] renderables = null; Rectangle[] bounds = null; + Rectangle mouseBounds = Rectangle.Empty; for (var playerIndex = 0; playerIndex < frozenStates.Count; playerIndex++) { var frozen = frozenStates[playerIndex].FrozenActor; @@ -139,6 +140,7 @@ namespace OpenRA.Mods.Common.Traits isRendering = true; renderables = self.Render(wr).ToArray(); bounds = self.ScreenBounds(wr).ToArray(); + mouseBounds = self.MouseBounds(wr); isRendering = false; } @@ -146,6 +148,7 @@ namespace OpenRA.Mods.Common.Traits frozen.NeedRenderables = false; frozen.Renderables = renderables; frozen.ScreenBounds = bounds; + frozen.MouseBounds = mouseBounds; self.World.ScreenMap.AddOrUpdate(self.World.Players[playerIndex], frozen); } } diff --git a/OpenRA.Mods.Common/Traits/Render/AutoRenderSize.cs b/OpenRA.Mods.Common/Traits/Render/AutoRenderSize.cs index d04750fd11..6959a8016f 100644 --- a/OpenRA.Mods.Common/Traits/Render/AutoRenderSize.cs +++ b/OpenRA.Mods.Common/Traits/Render/AutoRenderSize.cs @@ -9,6 +9,10 @@ */ #endregion +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits.Render @@ -16,17 +20,28 @@ namespace OpenRA.Mods.Common.Traits.Render [Desc("Automatically calculates the screen map boundaries from the sprite size.")] public class AutoRenderSizeInfo : ITraitInfo, Requires, IAutoRenderSizeInfo { - public object Create(ActorInitializer init) { return new AutoRenderSize(this); } + public object Create(ActorInitializer init) { return new AutoRenderSize(init.Self); } } - public class AutoRenderSize : IAutoRenderSize + public class AutoRenderSize : IAutoRenderSize, IMouseBounds { - public AutoRenderSize(AutoRenderSizeInfo info) { } + readonly RenderSprites rs; + + public AutoRenderSize(Actor self) + { + rs = self.Trait(); + } public int2 RenderSize(Actor self) { - var rs = self.Trait(); return rs.AutoRenderSize(self); } + + Rectangle IMouseBounds.MouseoverBounds(Actor self, WorldRenderer wr) + { + return self.TraitsImplementing() + .Select(s => s.AutoMouseoverBounds(self, wr)) + .FirstOrDefault(r => !r.IsEmpty); + } } } diff --git a/OpenRA.Mods.Common/Traits/Render/CustomRenderSize.cs b/OpenRA.Mods.Common/Traits/Render/CustomRenderSize.cs index 7c6ad0dd8c..af8a0d6a17 100644 --- a/OpenRA.Mods.Common/Traits/Render/CustomRenderSize.cs +++ b/OpenRA.Mods.Common/Traits/Render/CustomRenderSize.cs @@ -9,6 +9,8 @@ */ #endregion +using System.Drawing; +using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -22,7 +24,7 @@ namespace OpenRA.Mods.Common.Traits public object Create(ActorInitializer init) { return new CustomRenderSize(this); } } - public class CustomRenderSize : IAutoRenderSize + public class CustomRenderSize : IAutoRenderSize, IMouseBounds { readonly CustomRenderSizeInfo info; public CustomRenderSize(CustomRenderSizeInfo info) { this.info = info; } @@ -31,5 +33,20 @@ namespace OpenRA.Mods.Common.Traits { return new int2(info.CustomBounds[0], info.CustomBounds[1]); } + + Rectangle IMouseBounds.MouseoverBounds(Actor self, WorldRenderer wr) + { + if (info.CustomBounds == null) + return Rectangle.Empty; + + var size = new int2(info.CustomBounds[0], info.CustomBounds[1]); + + var offset = -size / 2; + if (info.CustomBounds.Length > 2) + offset += new int2(info.CustomBounds[2], info.CustomBounds[3]); + + var xy = wr.ScreenPxPosition(self.CenterPosition); + return new Rectangle(xy.X, xy.Y, size.X, size.Y); + } } } diff --git a/OpenRA.Mods.Common/Traits/Render/RenderSprites.cs b/OpenRA.Mods.Common/Traits/Render/RenderSprites.cs index 4327ebbbd0..e09552c810 100644 --- a/OpenRA.Mods.Common/Traits/Render/RenderSprites.cs +++ b/OpenRA.Mods.Common/Traits/Render/RenderSprites.cs @@ -151,8 +151,8 @@ namespace OpenRA.Mods.Common.Traits.Render } } + public readonly RenderSpritesInfo Info; readonly string faction; - readonly RenderSpritesInfo info; readonly List anims = new List(); string cachedImage; @@ -165,7 +165,7 @@ namespace OpenRA.Mods.Common.Traits.Render public RenderSprites(ActorInitializer init, RenderSpritesInfo info) { - this.info = info; + Info = info; faction = init.Contains() ? init.Get() : init.Self.Owner.Faction.InternalName; } @@ -174,7 +174,7 @@ namespace OpenRA.Mods.Common.Traits.Render if (cachedImage != null) return cachedImage; - return cachedImage = info.GetImage(self.Info, self.World.Map.Rules.Sequences, faction); + return cachedImage = Info.GetImage(self.Info, self.World.Map.Rules.Sequences, faction); } public void UpdatePalette() @@ -199,7 +199,7 @@ namespace OpenRA.Mods.Common.Traits.Render a.CachePalette(wr, owner); } - foreach (var r in a.Animation.Render(self, wr, a.PaletteReference, info.Scale)) + foreach (var r in a.Animation.Render(self, wr, a.PaletteReference, Info.Scale)) yield return r; } } @@ -208,7 +208,7 @@ namespace OpenRA.Mods.Common.Traits.Render { foreach (var a in anims) if (a.IsVisible) - yield return a.Animation.ScreenBounds(self, wr, info.Scale); + yield return a.Animation.ScreenBounds(self, wr, Info.Scale); } void ITick.Tick(Actor self) @@ -231,8 +231,8 @@ namespace OpenRA.Mods.Common.Traits.Render // Use defaults if (palette == null) { - palette = info.Palette ?? info.PlayerPalette; - isPlayerPalette = info.Palette == null; + palette = Info.Palette ?? Info.PlayerPalette; + isPlayerPalette = Info.Palette == null; } anims.Add(new AnimationWrapper(anim, palette, isPlayerPalette)); @@ -281,7 +281,7 @@ namespace OpenRA.Mods.Common.Traits.Render { return anims.Where(b => b.IsVisible && b.Animation.Animation.CurrentSequence != null) - .Select(a => (a.Animation.Animation.Image.Size.XY * info.Scale).ToInt2()) + .Select(a => (a.Animation.Animation.Image.Size.XY * Info.Scale).ToInt2()) .FirstOrDefault(); } diff --git a/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs b/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs index b4916945d6..94f3b2e0ad 100644 --- a/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs +++ b/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs @@ -97,11 +97,12 @@ namespace OpenRA.Mods.Common.Traits.Render } } + public readonly RenderVoxelsInfo Info; + readonly List components = new List(); readonly Dictionary wrappers = new Dictionary(); readonly Actor self; - readonly RenderVoxelsInfo info; readonly BodyOrientation body; readonly WRot camera; readonly WRot lightSource; @@ -109,7 +110,7 @@ namespace OpenRA.Mods.Common.Traits.Render public RenderVoxels(Actor self, RenderVoxelsInfo info) { this.self = self; - this.info = info; + Info = info; body = self.Trait(); camera = new WRot(WAngle.Zero, body.CameraPitch - new WAngle(256), new WAngle(256)); lightSource = new WRot(WAngle.Zero, new WAngle(256) - info.LightPitch, info.LightYaw); @@ -133,16 +134,16 @@ namespace OpenRA.Mods.Common.Traits.Render { if (initializePalettes) { - var paletteName = info.Palette ?? info.PlayerPalette + self.Owner.InternalName; + var paletteName = Info.Palette ?? Info.PlayerPalette + self.Owner.InternalName; colorPalette = wr.Palette(paletteName); - normalsPalette = wr.Palette(info.NormalsPalette); - shadowPalette = wr.Palette(info.ShadowPalette); + normalsPalette = wr.Palette(Info.NormalsPalette); + shadowPalette = wr.Palette(Info.ShadowPalette); initializePalettes = false; } return new IRenderable[] { new ModelRenderable( - components, self.CenterPosition, 0, camera, info.Scale, - lightSource, info.LightAmbientColor, info.LightDiffuseColor, + components, self.CenterPosition, 0, camera, Info.Scale, + lightSource, Info.LightAmbientColor, Info.LightDiffuseColor, colorPalette, normalsPalette, shadowPalette) }; } @@ -151,10 +152,10 @@ namespace OpenRA.Mods.Common.Traits.Render var pos = self.CenterPosition; foreach (var c in components) if (c.IsVisible) - yield return c.ScreenBounds(pos, wr, info.Scale); + yield return c.ScreenBounds(pos, wr, Info.Scale); } - public string Image { get { return info.Image ?? self.Info.Name; } } + public string Image { get { return Info.Image ?? self.Info.Name; } } public void Add(ModelAnimation m) { components.Add(m); diff --git a/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs b/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs index ad2accf7aa..697ec8a1db 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Drawing; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; using OpenRA.Traits; @@ -43,9 +44,10 @@ namespace OpenRA.Mods.Common.Traits.Render } } - public class WithSpriteBody : PausableConditionalTrait, INotifyDamageStateChanged, INotifyBuildComplete + public class WithSpriteBody : PausableConditionalTrait, INotifyDamageStateChanged, INotifyBuildComplete, IAutoMouseBounds { public readonly Animation DefaultAnimation; + readonly RenderSprites rs; public WithSpriteBody(ActorInitializer init, WithSpriteBodyInfo info) : this(init, info, () => 0) { } @@ -53,7 +55,7 @@ namespace OpenRA.Mods.Common.Traits.Render protected WithSpriteBody(ActorInitializer init, WithSpriteBodyInfo info, Func baseFacing) : base(info) { - var rs = init.Self.Trait(); + rs = init.Self.Trait(); Func paused = () => IsTraitPaused && DefaultAnimation.CurrentSequence.Name == NormalizeSequence(init.Self, Info.Sequence); @@ -125,5 +127,10 @@ namespace OpenRA.Mods.Common.Traits.Render { DamageStateChanged(self); } + + Rectangle IAutoMouseBounds.AutoMouseoverBounds(Actor self, WorldRenderer wr) + { + return DefaultAnimation != null ? DefaultAnimation.ScreenBounds(wr, self.CenterPosition, WVec.Zero, rs.Info.Scale) : Rectangle.Empty; + } } } diff --git a/OpenRA.Mods.Common/Traits/Render/WithVoxelBody.cs b/OpenRA.Mods.Common/Traits/Render/WithVoxelBody.cs index caf3b97b03..5ed6054ec8 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithVoxelBody.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithVoxelBody.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; @@ -39,21 +40,24 @@ namespace OpenRA.Mods.Common.Traits.Render } } - public class WithVoxelBody : ConditionalTrait, IAutoSelectionSize, IAutoRenderSize + public class WithVoxelBody : ConditionalTrait, IAutoSelectionSize, IAutoRenderSize, IAutoMouseBounds { readonly int2 size; + readonly ModelAnimation modelAnimation; + readonly RenderVoxels rv; public WithVoxelBody(Actor self, WithVoxelBodyInfo info) : base(info) { var body = self.Trait(); - var rv = self.Trait(); + rv = self.Trait(); var model = self.World.ModelCache.GetModelSequence(rv.Image, info.Sequence); - rv.Add(new ModelAnimation(model, () => WVec.Zero, + modelAnimation = new ModelAnimation(model, () => WVec.Zero, () => new[] { body.QuantizeOrientation(self, self.Orientation) }, - () => IsTraitDisabled, () => 0, info.ShowShadow)); + () => IsTraitDisabled, () => 0, info.ShowShadow); + rv.Add(modelAnimation); // Selection size var rvi = self.Info.TraitInfo(); var s = (int)(rvi.Scale * model.Size.Aggregate(Math.Max)); @@ -62,5 +66,10 @@ namespace OpenRA.Mods.Common.Traits.Render public int2 SelectionSize(Actor self) { return size; } public int2 RenderSize(Actor self) { return size; } + + Rectangle IAutoMouseBounds.AutoMouseoverBounds(Actor self, WorldRenderer wr) + { + return modelAnimation.ScreenBounds(self.CenterPosition, wr, rv.Info.Scale); + } } } diff --git a/OpenRA.Mods.Common/Widgets/ViewportControllerWidget.cs b/OpenRA.Mods.Common/Widgets/ViewportControllerWidget.cs index 21ae51742c..3e7109870b 100644 --- a/OpenRA.Mods.Common/Widgets/ViewportControllerWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ViewportControllerWidget.cs @@ -229,8 +229,8 @@ namespace OpenRA.Mods.Common.Widgets } var worldPixel = worldRenderer.Viewport.ViewToWorldPx(Viewport.LastMousePos); - var underCursor = world.ScreenMap.ActorsAt(worldPixel) - .Where(a => a.Info.HasTraitInfo() && !world.FogObscures(a)) + var underCursor = world.ScreenMap.ActorsAtMouse(worldPixel) + .Where(a => a.Actor.Info.HasTraitInfo() && !world.FogObscures(a.Actor)) .WithHighestSelectionPriority(worldPixel); if (underCursor != null) @@ -245,7 +245,7 @@ namespace OpenRA.Mods.Common.Widgets return; } - var frozen = world.ScreenMap.FrozenActorsAt(world.RenderPlayer, worldPixel) + var frozen = world.ScreenMap.FrozenActorsAtMouse(world.RenderPlayer, worldPixel) .Where(a => a.TooltipInfo != null && a.IsValid) .WithHighestSelectionPriority(worldPixel); diff --git a/OpenRA.Mods.Common/Widgets/WorldInteractionControllerWidget.cs b/OpenRA.Mods.Common/Widgets/WorldInteractionControllerWidget.cs index 9b966bd021..abe38220ad 100644 --- a/OpenRA.Mods.Common/Widgets/WorldInteractionControllerWidget.cs +++ b/OpenRA.Mods.Common/Widgets/WorldInteractionControllerWidget.cs @@ -107,11 +107,11 @@ namespace OpenRA.Mods.Common.Widgets { if (!IsValidDragbox && World.Selection.Actors.Any() && !multiClick) { - var selectableActor = World.ScreenMap.ActorsAt(mousePos).Any(x => + var selectableActor = World.ScreenMap.ActorsAtMouse(mousePos).Select(a => a.Actor).Any(x => x.Info.HasTraitInfo() && (x.Owner.IsAlliedWith(World.RenderPlayer) || !World.FogObscures(x))); var uog = (UnitOrderGenerator)World.OrderGenerator; - if (!selectableActor || uog.InputOverridesSelection(World, mousePos, mi)) + if (!selectableActor || uog.InputOverridesSelection(worldRenderer, World, mousePos, mi)) { // Order units instead of selecting ApplyOrders(World, mi); @@ -124,7 +124,7 @@ namespace OpenRA.Mods.Common.Widgets if (multiClick) { - var unit = World.ScreenMap.ActorsAt(mousePos) + var unit = World.ScreenMap.ActorsAtMouse(mousePos) .WithHighestSelectionPriority(mousePos); if (unit != null && unit.Owner == (World.RenderPlayer ?? World.LocalPlayer)) @@ -294,7 +294,8 @@ namespace OpenRA.Mods.Common.Widgets static IEnumerable SelectActorsOnScreen(World world, WorldRenderer wr, IEnumerable selectionClasses, Player player) { - return SelectActorsByOwnerAndSelectionClass(world.ScreenMap.ActorsInBox(wr.Viewport.TopLeft, wr.Viewport.BottomRight), player, selectionClasses); + var actors = world.ScreenMap.ActorsInMouseBox(wr.Viewport.TopLeft, wr.Viewport.BottomRight).Select(a => a.Actor); + return SelectActorsByOwnerAndSelectionClass(actors, player, selectionClasses); } static IEnumerable SelectActorsInWorld(World world, IEnumerable selectionClasses, Player player) @@ -322,7 +323,8 @@ namespace OpenRA.Mods.Common.Widgets if ((a - b).Length <= Game.Settings.Game.SelectionDeadzone) a = b; - return world.ScreenMap.ActorsInBox(a, b) + return world.ScreenMap.ActorsInMouseBox(a, b) + .Select(x => x.Actor) .Where(x => x.Info.HasTraitInfo() && (x.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(x))) .SubsetWithHighestSelectionPriority(); }