From 6b24271a1729d7183a27e97112e33776e1242615 Mon Sep 17 00:00:00 2001 From: Michael Silber Date: Mon, 19 Mar 2018 09:12:19 +0000 Subject: [PATCH] Pass ActorInfo through building-placement-validation code. --- OpenRA.Mods.Common/AI/HackyAI.cs | 9 ++-- .../Orders/PlaceBuildingOrderGenerator.cs | 46 +++++++++---------- .../Traits/Buildings/Building.cs | 4 +- .../Traits/Buildings/BuildingUtils.cs | 24 +++++----- .../Traits/Player/PlaceBuilding.cs | 18 ++++---- OpenRA.Mods.Common/Traits/Transforms.cs | 6 ++- 6 files changed, 53 insertions(+), 54 deletions(-) diff --git a/OpenRA.Mods.Common/AI/HackyAI.cs b/OpenRA.Mods.Common/AI/HackyAI.cs index 136be68b1f..387fb4cfa2 100644 --- a/OpenRA.Mods.Common/AI/HackyAI.cs +++ b/OpenRA.Mods.Common/AI/HackyAI.cs @@ -505,7 +505,8 @@ namespace OpenRA.Mods.Common.AI CPos defenseCenter; public CPos? ChooseBuildLocation(string actorType, bool distanceToBaseIsImportant, BuildingType type) { - var bi = Map.Rules.Actors[actorType].TraitInfoOrDefault(); + var ai = Map.Rules.Actors[actorType]; + var bi = ai.TraitInfoOrDefault(); if (bi == null) return null; @@ -522,10 +523,10 @@ namespace OpenRA.Mods.Common.AI foreach (var cell in cells) { - if (!World.CanPlaceBuilding(actorType, bi, cell, null)) + if (!World.CanPlaceBuilding(cell, ai, bi, null)) continue; - if (distanceToBaseIsImportant && !bi.IsCloseEnoughToBase(World, Player, actorType, cell)) + if (distanceToBaseIsImportant && !bi.IsCloseEnoughToBase(World, Player, ai, cell)) continue; return cell; @@ -935,7 +936,7 @@ namespace OpenRA.Mods.Common.AI bool IsRallyPointValid(CPos x, BuildingInfo info) { - return info != null && World.IsCellBuildable(x, info); + return info != null && World.IsCellBuildable(x, null, info); } void SetRallyPointsForNewProductionBuildings(Actor self) diff --git a/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs b/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs index 9e5339abbd..c183466d5f 100644 --- a/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs +++ b/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs @@ -26,7 +26,7 @@ namespace OpenRA.Mods.Common.Orders enum CellType { Valid = 0, Invalid = 1, LineBuild = 2 } readonly ProductionQueue queue; - readonly string building; + readonly ActorInfo actorInfo; readonly BuildingInfo buildingInfo; readonly PlaceBuildingInfo placeBuildingInfo; readonly BuildingInfluence buildingInfluence; @@ -46,7 +46,6 @@ namespace OpenRA.Mods.Common.Orders this.queue = queue; viewport = worldRenderer.Viewport; placeBuildingInfo = queue.Actor.Owner.PlayerActor.Info.TraitInfo(); - building = name; // Clear selection if using Left-Click Orders if (Game.Settings.Game.UseClassicMouseStyle) @@ -55,12 +54,12 @@ namespace OpenRA.Mods.Common.Orders var map = world.Map; var tileset = world.Map.Tileset.ToLowerInvariant(); - var info = map.Rules.Actors[building]; - buildingInfo = info.TraitInfo(); + actorInfo = map.Rules.Actors[name]; + buildingInfo = actorInfo.TraitInfo(); centerOffset = buildingInfo.CenterOffset(world); topLeftScreenOffset = -worldRenderer.ScreenPxOffset(centerOffset); - var buildableInfo = info.TraitInfo(); + var buildableInfo = actorInfo.TraitInfo(); var mostLikelyProducer = queue.MostLikelyProducer(); faction = buildableInfo.ForceFaction ?? (mostLikelyProducer.Trait != null ? mostLikelyProducer.Trait.Faction : queue.Actor.Owner.Faction.InternalName); @@ -107,7 +106,7 @@ namespace OpenRA.Mods.Common.Orders var orderType = "PlaceBuilding"; var topLeft = viewport.ViewToWorld(Viewport.LastMousePos + topLeftScreenOffset); - var plugInfo = world.Map.Rules.Actors[building].TraitInfoOrDefault(); + var plugInfo = actorInfo.TraitInfoOrDefault(); if (plugInfo != null) { orderType = "PlacePlug"; @@ -119,8 +118,8 @@ namespace OpenRA.Mods.Common.Orders } else { - if (!world.CanPlaceBuilding(building, buildingInfo, topLeft, null) - || !buildingInfo.IsCloseEnoughToBase(world, owner, building, topLeft)) + if (!world.CanPlaceBuilding(topLeft, actorInfo, buildingInfo, null) + || !buildingInfo.IsCloseEnoughToBase(world, owner, actorInfo, topLeft)) { foreach (var order in ClearBlockersOrders(world, topLeft)) yield return order; @@ -129,14 +128,14 @@ namespace OpenRA.Mods.Common.Orders yield break; } - if (world.Map.Rules.Actors[building].HasTraitInfo() && !mi.Modifiers.HasModifier(Modifiers.Shift)) + if (actorInfo.HasTraitInfo() && !mi.Modifiers.HasModifier(Modifiers.Shift)) orderType = "LineBuild"; } yield return new Order(orderType, owner.PlayerActor, Target.FromCell(world, topLeft), false) { // Building to place - TargetString = building, + TargetString = actorInfo.Name, // Actor to associate the placement with ExtraData = queue.Actor.ActorID, @@ -147,7 +146,7 @@ namespace OpenRA.Mods.Common.Orders public void Tick(World world) { - if (queue.CurrentItem() == null || queue.CurrentItem().Item != building) + if (queue.CurrentItem() == null || queue.CurrentItem().Item != actorInfo.Name) world.CancelInputMode(); if (preview == null) @@ -174,14 +173,13 @@ namespace OpenRA.Mods.Common.Orders var centerPosition = world.Map.CenterOfCell(topLeft) + centerOffset; var rules = world.Map.Rules; - var actorInfo = rules.Actors[building]; foreach (var dec in actorInfo.TraitInfos()) foreach (var r in dec.Render(wr, world, actorInfo, centerPosition)) yield return r; var cells = new Dictionary(); - var plugInfo = rules.Actors[building].TraitInfoOrDefault(); + var plugInfo = actorInfo.TraitInfoOrDefault(); if (plugInfo != null) { if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1) @@ -189,36 +187,34 @@ namespace OpenRA.Mods.Common.Orders cells.Add(topLeft, MakeCellType(AcceptsPlug(topLeft, plugInfo))); } - else if (rules.Actors[building].HasTraitInfo()) + else if (actorInfo.HasTraitInfo()) { // Linebuild for walls. if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1) throw new InvalidOperationException("LineBuild requires a 1x1 sized Building"); if (!Game.GetModifierKeys().HasModifier(Modifiers.Shift)) - foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, building, buildingInfo)) - cells.Add(t.First, MakeCellType(buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, building, t.First), true)); + foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, actorInfo, buildingInfo)) + cells.Add(t.First, MakeCellType(buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, t.First), true)); - cells[topLeft] = MakeCellType(buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, building, topLeft)); + cells[topLeft] = MakeCellType(buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, topLeft)); } else { if (!initialized) { - var actor = rules.Actors[building]; - var td = new TypeDictionary() { new FactionInit(faction), new OwnerInit(queue.Actor.Owner), }; - foreach (var api in actor.TraitInfos()) - foreach (var o in api.ActorPreviewInits(actor, ActorPreviewType.PlaceBuilding)) + foreach (var api in actorInfo.TraitInfos()) + foreach (var o in api.ActorPreviewInits(actorInfo, ActorPreviewType.PlaceBuilding)) td.Add(o); - var init = new ActorPreviewInitializer(actor, wr, td); - preview = actor.TraitInfos() + var init = new ActorPreviewInitializer(actorInfo, wr, td); + preview = actorInfo.TraitInfos() .SelectMany(rpi => rpi.RenderPreview(init)) .ToArray(); @@ -233,9 +229,9 @@ namespace OpenRA.Mods.Common.Orders yield return r; var res = world.WorldActor.TraitOrDefault(); - var isCloseEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, building, topLeft); + var isCloseEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, topLeft); foreach (var t in buildingInfo.Tiles(topLeft)) - cells.Add(t, MakeCellType(isCloseEnough && world.IsCellBuildable(t, buildingInfo) && (res == null || res.GetResource(t) == null))); + cells.Add(t, MakeCellType(isCloseEnough && world.IsCellBuildable(t, actorInfo, buildingInfo) && (res == null || res.GetResource(t) == null))); } var cellPalette = wr.Palette(placeBuildingInfo.Palette); diff --git a/OpenRA.Mods.Common/Traits/Buildings/Building.cs b/OpenRA.Mods.Common/Traits/Buildings/Building.cs index 37d46bc8c3..8a76576d3c 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/Building.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/Building.cs @@ -173,9 +173,9 @@ namespace OpenRA.Mods.Common.Traits .SelectMany(gba => gba.AreaTypes)); } - public virtual bool IsCloseEnoughToBase(World world, Player p, string buildingName, CPos topLeft) + public virtual bool IsCloseEnoughToBase(World world, Player p, ActorInfo ai, CPos topLeft) { - var requiresBuildableArea = world.Map.Rules.Actors[buildingName].TraitInfoOrDefault(); + var requiresBuildableArea = ai.TraitInfoOrDefault(); var mapBuildRadius = world.WorldActor.Trait(); if (requiresBuildableArea == null || p.PlayerActor.Trait().BuildAnywhere) diff --git a/OpenRA.Mods.Common/Traits/Buildings/BuildingUtils.cs b/OpenRA.Mods.Common/Traits/Buildings/BuildingUtils.cs index 91eb6d6bf1..edde98d1fe 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/BuildingUtils.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/BuildingUtils.cs @@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Traits { public static class BuildingUtils { - public static bool IsCellBuildable(this World world, CPos cell, BuildingInfo bi, Actor toIgnore = null) + public static bool IsCellBuildable(this World world, CPos cell, ActorInfo ai, BuildingInfo bi, Actor toIgnore = null) { if (!world.Map.Contains(cell)) return false; @@ -38,23 +38,23 @@ namespace OpenRA.Mods.Common.Traits return bi.TerrainTypes.Contains(world.Map.GetTerrainInfo(cell).Type); } - public static bool CanPlaceBuilding(this World world, string name, BuildingInfo building, CPos topLeft, Actor toIgnore) + public static bool CanPlaceBuilding(this World world, CPos cell, ActorInfo ai, BuildingInfo bi, Actor toIgnore) { - if (building.AllowInvalidPlacement) + if (bi.AllowInvalidPlacement) return true; var res = world.WorldActor.TraitOrDefault(); - return building.Tiles(topLeft).All( + return bi.Tiles(cell).All( t => world.Map.Contains(t) && (res == null || res.GetResource(t) == null) && - world.IsCellBuildable(t, building, toIgnore)); + world.IsCellBuildable(t, ai, bi, toIgnore)); } - public static IEnumerable> GetLineBuildCells(World world, CPos location, string name, BuildingInfo bi) + public static IEnumerable> GetLineBuildCells(World world, CPos cell, ActorInfo ai, BuildingInfo bi) { - var lbi = world.Map.Rules.Actors[name].TraitInfo(); - var topLeft = location; // 1x1 assumption! + var lbi = ai.TraitInfo(); + var topLeft = cell; // 1x1 assumption! - if (world.IsCellBuildable(topLeft, bi)) + if (world.IsCellBuildable(topLeft, ai, bi)) yield return Pair.New(topLeft, null); // Start at place location, search outwards @@ -70,12 +70,12 @@ namespace OpenRA.Mods.Common.Traits if (dirs[d] != 0) continue; - var cell = topLeft + i * vecs[d]; - if (world.IsCellBuildable(cell, bi)) + var c = topLeft + i * vecs[d]; + if (world.IsCellBuildable(c, ai, bi)) continue; // Cell is empty; continue search // Cell contains an actor. Is it the type we want? - connectors[d] = world.ActorMap.GetActorsAt(cell) + connectors[d] = world.ActorMap.GetActorsAt(c) .FirstOrDefault(a => a.Info.TraitInfos() .Any(info => info.Types.Overlaps(lbi.NodeTypes) && info.Connections.Contains(vecs[d]))); diff --git a/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs b/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs index 437c0083a3..b424c8c4f8 100644 --- a/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs +++ b/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs @@ -61,18 +61,18 @@ namespace OpenRA.Mods.Common.Traits if (targetActor == null || targetActor.IsDead) return; - var unit = self.World.Map.Rules.Actors[order.TargetString]; + var actorInfo = self.World.Map.Rules.Actors[order.TargetString]; var queue = targetActor.TraitsImplementing() - .FirstOrDefault(q => q.CanBuild(unit) && q.CurrentItem() != null && q.CurrentItem().Item == order.TargetString && q.CurrentItem().RemainingTime == 0); + .FirstOrDefault(q => q.CanBuild(actorInfo) && q.CurrentItem() != null && q.CurrentItem().Item == order.TargetString && q.CurrentItem().RemainingTime == 0); if (queue == null) return; var producer = queue.MostLikelyProducer(); var faction = producer.Trait != null ? producer.Trait.Faction : self.Owner.Faction.InternalName; - var buildingInfo = unit.TraitInfo(); + var buildingInfo = actorInfo.TraitInfo(); - var buildableInfo = unit.TraitInfoOrDefault(); + var buildableInfo = actorInfo.TraitInfoOrDefault(); if (buildableInfo != null && buildableInfo.ForceFaction != null) faction = buildableInfo.ForceFaction; @@ -90,11 +90,11 @@ namespace OpenRA.Mods.Common.Traits Game.Sound.PlayToPlayer(SoundType.World, order.Player, s, placed.CenterPosition); // Build the connection segments - var segmentType = unit.TraitInfo().SegmentType; + var segmentType = actorInfo.TraitInfo().SegmentType; if (string.IsNullOrEmpty(segmentType)) segmentType = order.TargetString; - foreach (var t in BuildingUtils.GetLineBuildCells(w, order.TargetLocation, order.TargetString, buildingInfo)) + foreach (var t in BuildingUtils.GetLineBuildCells(w, order.TargetLocation, actorInfo, buildingInfo)) { if (t.First == order.TargetLocation) continue; @@ -115,7 +115,7 @@ namespace OpenRA.Mods.Common.Traits if (host == null) return; - var plugInfo = unit.TraitInfoOrDefault(); + var plugInfo = actorInfo.TraitInfoOrDefault(); if (plugInfo == null) return; @@ -132,8 +132,8 @@ namespace OpenRA.Mods.Common.Traits } else { - if (!self.World.CanPlaceBuilding(order.TargetString, buildingInfo, order.TargetLocation, null) - || !buildingInfo.IsCloseEnoughToBase(self.World, order.Player, order.TargetString, order.TargetLocation)) + if (!self.World.CanPlaceBuilding(order.TargetLocation, actorInfo, buildingInfo, null) + || !buildingInfo.IsCloseEnoughToBase(self.World, order.Player, actorInfo, order.TargetLocation)) return; var building = w.CreateActor(order.TargetString, new TypeDictionary diff --git a/OpenRA.Mods.Common/Traits/Transforms.cs b/OpenRA.Mods.Common/Traits/Transforms.cs index 827bbc1216..b1cab0cd39 100644 --- a/OpenRA.Mods.Common/Traits/Transforms.cs +++ b/OpenRA.Mods.Common/Traits/Transforms.cs @@ -54,6 +54,7 @@ namespace OpenRA.Mods.Common.Traits public class Transforms : PausableConditionalTrait, IIssueOrder, IResolveOrder, IOrderVoice, IIssueDeployOrder { readonly Actor self; + readonly ActorInfo actorInfo; readonly BuildingInfo buildingInfo; readonly string faction; @@ -61,7 +62,8 @@ namespace OpenRA.Mods.Common.Traits : base(info) { self = init.Self; - buildingInfo = self.World.Map.Rules.Actors[info.IntoActor].TraitInfoOrDefault(); + actorInfo = self.World.Map.Rules.Actors[info.IntoActor]; + buildingInfo = actorInfo.TraitInfoOrDefault(); faction = init.Contains() ? init.Get() : self.Owner.Faction.InternalName; } @@ -79,7 +81,7 @@ namespace OpenRA.Mods.Common.Traits if (building != null && building.Locked) return false; - return buildingInfo == null || self.World.CanPlaceBuilding(Info.IntoActor, buildingInfo, self.Location + Info.Offset, self); + return buildingInfo == null || self.World.CanPlaceBuilding(self.Location + Info.Offset, actorInfo, buildingInfo, self); } public IEnumerable Orders