From c6c3a8c60d266b5fc4550c237262fed7b3547adc Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 12 Jun 2020 13:21:09 +0100 Subject: [PATCH] Make ActorPreview and EditorActorPreview wrap ActorReference. --- OpenRA.Game/Map/ActorInitializer.cs | 3 + OpenRA.Game/Map/ActorReference.cs | 115 ++++++++++++++++-- OpenRA.Game/Map/MapPreview.cs | 2 +- OpenRA.Game/World.cs | 5 + .../EditorBrushes/EditorActorBrush.cs | 2 +- .../EditorBrushes/EditorCopyPasteBrush.cs | 8 +- OpenRA.Mods.Common/Graphics/ActorPreview.cs | 86 ++++--------- OpenRA.Mods.Common/Lint/CheckPlayers.cs | 4 +- OpenRA.Mods.Common/Traits/Air/Aircraft.cs | 2 +- .../Traits/AppearsOnMapPreview.cs | 4 +- OpenRA.Mods.Common/Traits/AutoTarget.cs | 2 +- .../Traits/Buildings/FreeActor.cs | 4 +- .../Conditions/GrantConditionOnDeploy.cs | 2 +- OpenRA.Mods.Common/Traits/Health.cs | 2 +- OpenRA.Mods.Common/Traits/Mobile.cs | 13 +- OpenRA.Mods.Common/Traits/Turreted.cs | 12 +- .../Traits/World/EditorActorLayer.cs | 4 +- .../Traits/World/EditorActorPreview.cs | 108 +++++++++++----- .../Traits/World/EditorCursorLayer.cs | 25 ++-- .../Traits/World/SpawnMapActors.cs | 9 +- .../UtilityCommands/ImportLegacyMapCommand.cs | 5 +- .../UtilityCommands/ResizeMapCommand.cs | 10 +- 22 files changed, 265 insertions(+), 162 deletions(-) diff --git a/OpenRA.Game/Map/ActorInitializer.cs b/OpenRA.Game/Map/ActorInitializer.cs index fcf11e2335..1d4f22e3e4 100644 --- a/OpenRA.Game/Map/ActorInitializer.cs +++ b/OpenRA.Game/Map/ActorInitializer.cs @@ -145,6 +145,9 @@ namespace OpenRA protected ValueActorInit(TraitInfo info, T value) : base(info.InstanceName) { this.value = value; } + protected ValueActorInit(string instanceName, T value) + : base(instanceName) { this.value = value; } + protected ValueActorInit(T value) { this.value = value; } public virtual T Value { get { return value; } } diff --git a/OpenRA.Game/Map/ActorReference.cs b/OpenRA.Game/Map/ActorReference.cs index ba873af104..1977dacac2 100644 --- a/OpenRA.Game/Map/ActorReference.cs +++ b/OpenRA.Game/Map/ActorReference.cs @@ -13,8 +13,10 @@ using System; using System.Collections; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Runtime.Serialization; using OpenRA.Primitives; +using OpenRA.Traits; namespace OpenRA { @@ -23,13 +25,10 @@ namespace OpenRA public class ActorReference : IEnumerable { public string Type; - public TypeDictionary InitDict - { - get { return initDict.Value; } - } - Lazy initDict; + internal TypeDictionary InitDict { get { return initDict.Value; } } + public ActorReference(string type) : this(type, new Dictionary()) { } @@ -52,6 +51,18 @@ namespace OpenRA }); } + public ActorReference(string type, TypeDictionary inits) + { + Type = type; + initDict = new Lazy(() => + { + var dict = new TypeDictionary(); + foreach (var i in inits) + dict.Add(i); + return dict; + }); + } + static ActorInit LoadInit(string initName, MiniYaml initYaml) { var initInstance = initName.Split(ActorInfo.TraitInstanceSeparator); @@ -74,7 +85,7 @@ namespace OpenRA public MiniYaml Save(Func initFilter = null) { var ret = new MiniYaml(Type); - foreach (var o in InitDict) + foreach (var o in initDict.Value) { var init = o as ActorInit; if (init == null || o is ISuppressInitExport) @@ -94,7 +105,17 @@ namespace OpenRA return ret; } - // for initialization syntax + public IEnumerator GetEnumerator() { return initDict.Value.GetEnumerator(); } + + public ActorReference Clone() + { + var clone = new ActorReference(Type); + foreach (var init in initDict.Value) + clone.initDict.Value.Add(init); + + return clone; + } + public void Add(ActorInit init) { if (init is ISingleInstanceInit && InitDict.Contains(init.GetType())) @@ -103,15 +124,83 @@ namespace OpenRA InitDict.Add(init); } - public IEnumerator GetEnumerator() { return InitDict.GetEnumerator(); } + public void Remove(ActorInit o) { initDict.Value.Remove(o); } - public ActorReference Clone() + public int RemoveAll() where T : ActorInit { - var clone = new ActorReference(Type); - foreach (var init in InitDict) - clone.InitDict.Add(init); + var removed = 0; + foreach (var o in initDict.Value.WithInterface().ToList()) + { + removed++; + initDict.Value.Remove(o); + } - return clone; + return removed; } + + public IEnumerable GetAll() where T : ActorInit + { + return initDict.Value.WithInterface(); + } + + public T GetOrDefault(TraitInfo info) where T : ActorInit + { + var inits = initDict.Value.WithInterface(); + + // Traits tagged with an instance name prefer inits with the same name. + // If a more specific init is not available, fall back to an unnamed init. + // If duplicate inits are defined, take the last to match standard yaml override expectations + if (info != null && !string.IsNullOrEmpty(info.InstanceName)) + return inits.LastOrDefault(i => i.InstanceName == info.InstanceName) ?? + inits.LastOrDefault(i => string.IsNullOrEmpty(i.InstanceName)); + + // Untagged traits will only use untagged inits + return inits.LastOrDefault(i => string.IsNullOrEmpty(i.InstanceName)); + } + + public T Get(TraitInfo info) where T : ActorInit + { + var init = GetOrDefault(info); + if (init == null) + throw new InvalidOperationException("TypeDictionary does not contain instance of type `{0}`".F(typeof(T))); + + return init; + } + + public U GetValue(TraitInfo info) where T : ValueActorInit + { + return Get(info).Value; + } + + public U GetValue(TraitInfo info, U fallback) where T : ValueActorInit + { + var init = GetOrDefault(info); + return init != null ? init.Value : fallback; + } + + public bool Contains(TraitInfo info) where T : ActorInit { return GetOrDefault(info) != null; } + + public T GetOrDefault() where T : ActorInit, ISingleInstanceInit + { + return initDict.Value.GetOrDefault(); + } + + public T Get() where T : ActorInit, ISingleInstanceInit + { + return initDict.Value.Get(); + } + + public U GetValue() where T : ValueActorInit, ISingleInstanceInit + { + return Get().Value; + } + + public U GetValue(U fallback) where T : ValueActorInit, ISingleInstanceInit + { + var init = GetOrDefault(); + return init != null ? init.Value : fallback; + } + + public bool Contains() where T : ActorInit, ISingleInstanceInit { return GetOrDefault() != null; } } } diff --git a/OpenRA.Game/Map/MapPreview.cs b/OpenRA.Game/Map/MapPreview.cs index 1d6217dc68..eb294d971c 100644 --- a/OpenRA.Game/Map/MapPreview.cs +++ b/OpenRA.Game/Map/MapPreview.cs @@ -276,7 +276,7 @@ namespace OpenRA foreach (var kv in actorDefinitions.Nodes.Where(d => d.Value.Value == "mpspawn")) { var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); - spawns.Add(s.InitDict.Get().Value); + spawns.Add(s.Get().Value); } newData.SpawnPoints = spawns.ToArray(); diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index df51498ed5..4c34c8d83e 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -334,6 +334,11 @@ namespace OpenRA return CreateActor(true, name, initDict); } + public Actor CreateActor(bool addToWorld, ActorReference reference) + { + return CreateActor(addToWorld, reference.Type, reference.InitDict); + } + public Actor CreateActor(bool addToWorld, string name, TypeDictionary initDict) { var a = new Actor(this, name, initDict); diff --git a/OpenRA.Mods.Common/EditorBrushes/EditorActorBrush.cs b/OpenRA.Mods.Common/EditorBrushes/EditorActorBrush.cs index 0c13703072..5fa06d4ebf 100644 --- a/OpenRA.Mods.Common/EditorBrushes/EditorActorBrush.cs +++ b/OpenRA.Mods.Common/EditorBrushes/EditorActorBrush.cs @@ -62,7 +62,7 @@ namespace OpenRA.Mods.Common.Widgets if (!actor.Footprint.All(c => world.Map.Tiles.Contains(c.Key))) return true; - var action = new AddActorAction(editorLayer, actor.Actor); + var action = new AddActorAction(editorLayer, actor.Export()); editorActionManager.Add(action); } diff --git a/OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs b/OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs index 5683c57a3a..980de0e440 100644 --- a/OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs +++ b/OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs @@ -134,11 +134,11 @@ namespace OpenRA.Mods.Common.Widgets continue; var copy = preview.Export(); - if (copy.InitDict.Contains()) + var locationInit = copy.GetOrDefault(); + if (locationInit != null) { - var location = copy.InitDict.Get(); - copy.InitDict.Remove(location); - copy.InitDict.Add(new LocationInit(location.Value + offset)); + copy.RemoveAll(); + copy.Add(new LocationInit(locationInit.Value + offset)); } previews.Add(preview.ID, copy); diff --git a/OpenRA.Mods.Common/Graphics/ActorPreview.cs b/OpenRA.Mods.Common/Graphics/ActorPreview.cs index 64dacf065f..7555c40bd9 100644 --- a/OpenRA.Mods.Common/Graphics/ActorPreview.cs +++ b/OpenRA.Mods.Common/Graphics/ActorPreview.cs @@ -33,74 +33,34 @@ namespace OpenRA.Mods.Common.Graphics public readonly WorldRenderer WorldRenderer; public World World { get { return WorldRenderer.World; } } - readonly TypeDictionary dict; + readonly ActorReference reference; public ActorPreviewInitializer(ActorInfo actor, WorldRenderer worldRenderer, TypeDictionary dict) { Actor = actor; WorldRenderer = worldRenderer; - this.dict = dict; + reference = new ActorReference(actor.Name, dict); } - public T GetOrDefault(TraitInfo info) where T : ActorInit + public ActorPreviewInitializer(ActorReference actor, WorldRenderer worldRenderer) { - var inits = dict.WithInterface(); - - // Traits tagged with an instance name prefer inits with the same name. - // If a more specific init is not available, fall back to an unnamed init. - // If duplicate inits are defined, take the last to match standard yaml override expectations - if (info != null && !string.IsNullOrEmpty(info.InstanceName)) - return inits.LastOrDefault(i => i.InstanceName == info.InstanceName) ?? - inits.LastOrDefault(i => string.IsNullOrEmpty(i.InstanceName)); - - // Untagged traits will only use untagged inits - return inits.LastOrDefault(i => string.IsNullOrEmpty(i.InstanceName)); + Actor = worldRenderer.World.Map.Rules.Actors[actor.Type]; + reference = actor; + WorldRenderer = worldRenderer; } - public T Get(TraitInfo info) where T : ActorInit - { - var init = GetOrDefault(info); - if (init == null) - throw new InvalidOperationException("TypeDictionary does not contain instance of type `{0}`".F(typeof(T))); - - return init; - } - - public U GetValue(TraitInfo info) where T : ValueActorInit - { - return Get(info).Value; - } - - public U GetValue(TraitInfo info, U fallback) where T : ValueActorInit - { - var init = GetOrDefault(info); - return init != null ? init.Value : fallback; - } - - public bool Contains() where T : ActorInit, ISingleInstanceInit { return GetOrDefault() != null; } - - public T GetOrDefault() where T : ActorInit, ISingleInstanceInit - { - return dict.GetOrDefault(); - } - - public T Get() where T : ActorInit, ISingleInstanceInit - { - return dict.Get(); - } - - public U GetValue() where T : ValueActorInit, ISingleInstanceInit - { - return Get().Value; - } - - public U GetValue(U fallback) where T : ValueActorInit, ISingleInstanceInit - { - var init = GetOrDefault(); - return init != null ? init.Value : fallback; - } - - public bool Contains(TraitInfo info) where T : ActorInit { return GetOrDefault(info) != null; } + // Forward IActorInitializer queries to the actor reference + // ActorReference can't reference a World instance, which prevents it from implementing this directly. + public T GetOrDefault(TraitInfo info) where T : ActorInit { return reference.GetOrDefault(info); } + public T Get(TraitInfo info) where T : ActorInit { return reference.Get(info); } + public U GetValue(TraitInfo info) where T : ValueActorInit { return reference.GetValue(info); } + public U GetValue(TraitInfo info, U fallback) where T : ValueActorInit { return reference.GetValue(info, fallback); } + public bool Contains(TraitInfo info) where T : ActorInit { return reference.Contains(info); } + public T GetOrDefault() where T : ActorInit, ISingleInstanceInit { return reference.GetOrDefault(); } + public T Get() where T : ActorInit, ISingleInstanceInit { return reference.Get(); } + public U GetValue() where T : ValueActorInit, ISingleInstanceInit { return reference.GetValue(); } + public U GetValue(U fallback) where T : ValueActorInit, ISingleInstanceInit { return reference.GetValue(fallback); } + public bool Contains() where T : ActorInit, ISingleInstanceInit { return reference.Contains(); } public Func GetOrientation() { @@ -109,7 +69,7 @@ namespace OpenRA.Mods.Common.Graphics return () => WRot.Zero; // Dynamic facing takes priority - var dynamicInit = dict.GetOrDefault(); + var dynamicInit = reference.GetOrDefault(); if (dynamicInit != null) { // TODO: Account for terrain slope @@ -118,7 +78,7 @@ namespace OpenRA.Mods.Common.Graphics } // Fall back to initial actor facing if an Init isn't available - var facingInit = dict.GetOrDefault(); + var facingInit = reference.GetOrDefault(); var facing = facingInit != null ? facingInit.Value : facingInfo.GetInitialFacing(); var orientation = WRot.FromFacing(facing); return () => orientation; @@ -131,7 +91,7 @@ namespace OpenRA.Mods.Common.Graphics return () => WAngle.Zero; // Dynamic facing takes priority - var dynamicInit = dict.GetOrDefault(); + var dynamicInit = reference.GetOrDefault(); if (dynamicInit != null) { var getFacing = dynamicInit.Value; @@ -139,14 +99,14 @@ namespace OpenRA.Mods.Common.Graphics } // Fall back to initial actor facing if an Init isn't available - var facingInit = dict.GetOrDefault(); + var facingInit = reference.GetOrDefault(); var facing = WAngle.FromFacing(facingInit != null ? facingInit.Value : facingInfo.GetInitialFacing()); return () => facing; } public DamageState GetDamageState() { - var health = dict.GetOrDefault(); + var health = reference.GetOrDefault(); if (health == null) return DamageState.Undamaged; diff --git a/OpenRA.Mods.Common/Lint/CheckPlayers.cs b/OpenRA.Mods.Common/Lint/CheckPlayers.cs index 4b4580c28f..ff3713f2f1 100644 --- a/OpenRA.Mods.Common/Lint/CheckPlayers.cs +++ b/OpenRA.Mods.Common/Lint/CheckPlayers.cs @@ -70,7 +70,7 @@ namespace OpenRA.Mods.Common.Lint foreach (var kv in map.ActorDefinitions.Where(d => d.Value.Value == "mpspawn")) { var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); - spawns.Add(s.InitDict.Get().Value); + spawns.Add(s.Get().Value); } if (playerCount > spawns.Count) @@ -88,7 +88,7 @@ namespace OpenRA.Mods.Common.Lint foreach (var kv in map.ActorDefinitions) { var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); - var ownerInit = actorReference.InitDict.GetOrDefault(); + var ownerInit = actorReference.GetOrDefault(); if (ownerInit == null) emitError("Actor {0} is not owned by any player.".F(kv.Key)); else diff --git a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs index 2221a6e24c..da98bfca2f 100644 --- a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs +++ b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs @@ -184,7 +184,7 @@ namespace OpenRA.Mods.Common.Traits yield return new EditorActorSlider("Facing", EditorFacingDisplayOrder, 0, 255, 8, actor => { - var init = actor.Init(); + var init = actor.GetInitOrDefault(this); return init != null ? init.Value : InitialFacing; }, (actor, value) => actor.ReplaceInit(new FacingInit((int)value))); diff --git a/OpenRA.Mods.Common/Traits/AppearsOnMapPreview.cs b/OpenRA.Mods.Common/Traits/AppearsOnMapPreview.cs index 502dad40bd..a301a22423 100644 --- a/OpenRA.Mods.Common/Traits/AppearsOnMapPreview.cs +++ b/OpenRA.Mods.Common/Traits/AppearsOnMapPreview.cs @@ -42,14 +42,14 @@ namespace OpenRA.Mods.Common.Traits } else { - var owner = map.PlayerDefinitions.Single(p => s.InitDict.Get().InternalName == p.Value.Nodes.Last(k => k.Key == "Name").Value.Value); + var owner = map.PlayerDefinitions.Single(p => s.Get().InternalName == p.Value.Nodes.Last(k => k.Key == "Name").Value.Value); var colorValue = owner.Value.Nodes.Where(n => n.Key == "Color"); var ownerColor = colorValue.Any() ? colorValue.First().Value.Value : "FFFFFF"; Color.TryParse(ownerColor, out color); } var ios = ai.TraitInfo(); - var cells = ios.OccupiedCells(ai, s.InitDict.Get().Value); + var cells = ios.OccupiedCells(ai, s.Get().Value); foreach (var cell in cells) destinationBuffer.Add(new Pair(cell.Key.ToMPos(map), color)); } diff --git a/OpenRA.Mods.Common/Traits/AutoTarget.cs b/OpenRA.Mods.Common/Traits/AutoTarget.cs index 857286348f..62eb5cd0f0 100644 --- a/OpenRA.Mods.Common/Traits/AutoTarget.cs +++ b/OpenRA.Mods.Common/Traits/AutoTarget.cs @@ -119,7 +119,7 @@ namespace OpenRA.Mods.Common.Traits yield return new EditorActorDropdown("Stance", EditorStanceDisplayOrder, labels, actor => { - var init = actor.Init(); + var init = actor.GetInitOrDefault(this); var stance = init != null ? init.Value : InitialStance; return stances[(int)stance]; }, diff --git a/OpenRA.Mods.Common/Traits/Buildings/FreeActor.cs b/OpenRA.Mods.Common/Traits/Buildings/FreeActor.cs index dce1f0e31d..f5b258f078 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/FreeActor.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/FreeActor.cs @@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Traits yield return new EditorActorCheckbox("Spawn Child Actor", EditorFreeActorDisplayOrder, actor => { - var init = actor.Init(); + var init = actor.GetInitOrDefault(this); if (init != null) return init.Value; @@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Traits }, (actor, value) => { - actor.ReplaceInit(new FreeActorInit(this, value)); + actor.ReplaceInit(new FreeActorInit(this, value), this); }); } diff --git a/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDeploy.cs b/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDeploy.cs index e759ecc854..5ba4a9aec6 100644 --- a/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDeploy.cs +++ b/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDeploy.cs @@ -72,7 +72,7 @@ namespace OpenRA.Mods.Common.Traits yield return new EditorActorCheckbox("Deployed", EditorDeployedDisplayOrder, actor => { - var init = actor.Init(); + var init = actor.GetInitOrDefault(); if (init != null) return init.Value == DeployState.Deployed; diff --git a/OpenRA.Mods.Common/Traits/Health.cs b/OpenRA.Mods.Common/Traits/Health.cs index d98368ca4b..ba402b5b68 100644 --- a/OpenRA.Mods.Common/Traits/Health.cs +++ b/OpenRA.Mods.Common/Traits/Health.cs @@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Traits yield return new EditorActorSlider("Health", EditorHealthDisplayOrder, 0, 100, 5, actor => { - var init = actor.Init(); + var init = actor.GetInitOrDefault(); return init != null ? init.Value : 100; }, (actor, value) => actor.ReplaceInit(new HealthInit((int)value))); diff --git a/OpenRA.Mods.Common/Traits/Mobile.cs b/OpenRA.Mods.Common/Traits/Mobile.cs index bb01733bbb..6485128990 100644 --- a/OpenRA.Mods.Common/Traits/Mobile.cs +++ b/OpenRA.Mods.Common/Traits/Mobile.cs @@ -130,23 +130,24 @@ namespace OpenRA.Mods.Common.Traits yield return new EditorActorSlider("Facing", EditorFacingDisplayOrder, 0, 255, 8, actor => { - var init = actor.Init(); + var init = actor.GetInitOrDefault(this); return init != null ? init.Value : InitialFacing; }, (actor, value) => { // TODO: This can all go away once turrets are properly defined as a relative facing - var turretInit = actor.Init(); - var turretsInit = actor.Init(); - var facingInit = actor.Init(); + var turretsInit = actor.GetInitOrDefault(); + var facingInit = actor.GetInitOrDefault(); var oldFacing = facingInit != null ? facingInit.Value : InitialFacing; var newFacing = (int)value; - if (turretInit != null) + var turretInits = actor.GetInits().ToList(); + actor.RemoveInits(); + foreach (var turretInit in turretInits) { var newTurretFacing = (turretInit.Value + newFacing - oldFacing + 255) % 255; - actor.ReplaceInit(new TurretFacingInit(this, newTurretFacing)); + actor.AddInit(new TurretFacingInit(turretInit.InstanceName, newTurretFacing)); } if (turretsInit != null) diff --git a/OpenRA.Mods.Common/Traits/Turreted.cs b/OpenRA.Mods.Common/Traits/Turreted.cs index c8ffef2252..c0ef9b7108 100644 --- a/OpenRA.Mods.Common/Traits/Turreted.cs +++ b/OpenRA.Mods.Common/Traits/Turreted.cs @@ -53,11 +53,11 @@ namespace OpenRA.Mods.Common.Traits yield return new EditorActorSlider("Turret", EditorTurretFacingDisplayOrder, 0, 255, 8, actor => { - var init = actor.Init(); + var init = actor.GetInitOrDefault(this); if (init != null) return init.Value; - var facingInit = actor.Init(); + var facingInit = actor.GetInitOrDefault(this); if (facingInit != null) return facingInit.Value; @@ -67,8 +67,9 @@ namespace OpenRA.Mods.Common.Traits { actor.RemoveInit(); - // Force a single global turret facing for multi-turret actors by not passing this TraitInfo instance - actor.ReplaceInit(new TurretFacingInit((int)value)); + // Force a single global turret facing for multi-turret actors + actor.RemoveInits(); + actor.AddInit(new TurretFacingInit((int)value)); }); } @@ -274,6 +275,9 @@ namespace OpenRA.Mods.Common.Traits public TurretFacingInit(TraitInfo info, int value) : base(info, value) { } + public TurretFacingInit(string instanceName, int value) + : base(instanceName, value) { } + public TurretFacingInit(int value) : base(value) { } } diff --git a/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs index 26fb30add8..90c44864e4 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs @@ -118,7 +118,7 @@ namespace OpenRA.Mods.Common.Traits public EditorActorPreview Add(string id, ActorReference reference, bool initialSetup = false) { - var owner = Players.Players[reference.InitDict.Get().InternalName]; + var owner = Players.Players[reference.Get().InternalName]; var preview = new EditorActorPreview(worldRenderer, id, reference, owner); Add(preview, initialSetup); @@ -144,7 +144,7 @@ namespace OpenRA.Mods.Common.Traits { UpdateNeighbours(preview.Footprint); - if (preview.Actor.Type == "mpspawn") + if (preview.Type == "mpspawn") SyncMultiplayerCount(); } } diff --git a/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs b/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs index e02e2df9ba..169b4b6763 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs @@ -28,7 +28,6 @@ namespace OpenRA.Mods.Common.Traits public readonly IReadOnlyDictionary Footprint; public readonly Rectangle Bounds; public readonly SelectionBoxAnnotationRenderable SelectionBox; - public readonly ActorReference Actor; public string Tooltip { @@ -39,6 +38,8 @@ namespace OpenRA.Mods.Common.Traits } } + public string Type { get { return reference.Type; } } + public string ID { get; set; } public PlayerReference Owner { get; set; } public SubCell SubCell { get; private set; } @@ -47,30 +48,31 @@ namespace OpenRA.Mods.Common.Traits readonly WorldRenderer worldRenderer; readonly TooltipInfoBase tooltip; IActorPreview[] previews; + readonly ActorReference reference; - public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference actor, PlayerReference owner) + public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference reference, PlayerReference owner) { ID = id; - Actor = actor; + this.reference = reference; Owner = owner; this.worldRenderer = worldRenderer; - if (!actor.InitDict.Contains()) - actor.InitDict.Add(new FactionInit(owner.Faction)); + if (!reference.Contains()) + reference.Add(new FactionInit(owner.Faction)); - if (!actor.InitDict.Contains()) - actor.InitDict.Add(new OwnerInit(owner.Name)); + if (!reference.Contains()) + reference.Add(new OwnerInit(owner.Name)); var world = worldRenderer.World; - if (!world.Map.Rules.Actors.TryGetValue(actor.Type.ToLowerInvariant(), out Info)) - throw new InvalidDataException("Actor {0} of unknown type {1}".F(id, actor.Type.ToLowerInvariant())); + if (!world.Map.Rules.Actors.TryGetValue(reference.Type.ToLowerInvariant(), out Info)) + throw new InvalidDataException("Actor {0} of unknown type {1}".F(id, reference.Type.ToLowerInvariant())); - CenterPosition = PreviewPosition(world, actor.InitDict); + CenterPosition = PreviewPosition(world, reference); - var location = actor.InitDict.Get().Value; + var location = reference.Get().Value; var ios = Info.TraitInfoOrDefault(); - var subCellInit = actor.InitDict.GetOrDefault(); + var subCellInit = reference.GetOrDefault(); var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any; if (ios != null) @@ -124,27 +126,66 @@ namespace OpenRA.Mods.Common.Traits yield return SelectionBox; } - public void ReplaceInit(T init) + public void AddInit(T init) where T : ActorInit { - var original = Actor.InitDict.GetOrDefault(); - if (original != null) - Actor.InitDict.Remove(original); - - Actor.InitDict.Add(init); + reference.Add(init); GeneratePreviews(); } - public void RemoveInit() + public void ReplaceInit(T init, TraitInfo info) where T : ActorInit { - var original = Actor.InitDict.GetOrDefault(); + var original = GetInitOrDefault(info); if (original != null) - Actor.InitDict.Remove(original); + reference.Remove(original); + + reference.Add(init); GeneratePreviews(); } - public T Init() + public void RemoveInit(TraitInfo info) where T : ActorInit { - return Actor.InitDict.GetOrDefault(); + var original = GetInitOrDefault(info); + if (original != null) + reference.Remove(original); + GeneratePreviews(); + } + + public int RemoveInits() where T : ActorInit + { + var removed = reference.RemoveAll(); + GeneratePreviews(); + return removed; + } + + public T GetInitOrDefault(TraitInfo info) where T : ActorInit + { + return reference.GetOrDefault(info); + } + + public IEnumerable GetInits() where T : ActorInit + { + return reference.GetAll(); + } + + public T GetInitOrDefault() where T : ActorInit, ISingleInstanceInit + { + return reference.GetOrDefault(); + } + + public void ReplaceInit(T init) where T : ActorInit, ISingleInstanceInit + { + var original = reference.GetOrDefault(); + if (original != null) + reference.Remove(original); + + reference.Add(init); + GeneratePreviews(); + } + + public void RemoveInit() where T : ActorInit, ISingleInstanceInit + { + reference.RemoveAll(); + GeneratePreviews(); } public MiniYaml Save() @@ -160,20 +201,23 @@ namespace OpenRA.Mods.Common.Traits return true; }; - return Actor.Save(saveInit); + return reference.Save(saveInit); } - WPos PreviewPosition(World world, TypeDictionary init) + WPos PreviewPosition(World world, ActorReference actor) { - if (init.Contains()) - return init.Get().Value; + var centerPositionInit = actor.GetOrDefault(); + if (centerPositionInit != null) + return centerPositionInit.Value; - if (init.Contains()) + var locationInit = actor.GetOrDefault(); + + if (locationInit != null) { - var cell = init.Get().Value; + var cell = locationInit.Value; var offset = WVec.Zero; - var subCellInit = Actor.InitDict.GetOrDefault(); + var subCellInit = reference.GetOrDefault(); var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any; var buildingInfo = Info.TraitInfoOrDefault(); @@ -188,7 +232,7 @@ namespace OpenRA.Mods.Common.Traits void GeneratePreviews() { - var init = new ActorPreviewInitializer(Info, worldRenderer, Actor.InitDict); + var init = new ActorPreviewInitializer(reference, worldRenderer); previews = Info.TraitInfos() .SelectMany(rpi => rpi.RenderPreview(init)) .ToArray(); @@ -196,7 +240,7 @@ namespace OpenRA.Mods.Common.Traits public ActorReference Export() { - return new ActorReference(Actor.Type, Actor.Save().ToDictionary()); + return reference.Clone(); } public override string ToString() diff --git a/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs index 25586e3671..0078e7b7e4 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs @@ -113,8 +113,7 @@ namespace OpenRA.Mods.Common.Traits if (actorLocation != cell) { actorLocation = cell; - Actor.Actor.InitDict.Remove(Actor.Actor.InitDict.Get()); - Actor.Actor.InitDict.Add(new LocationInit(cell)); + Actor.ReplaceInit(new LocationInit(cell)); updated = true; } @@ -122,23 +121,19 @@ namespace OpenRA.Mods.Common.Traits { actorSubCell = subCell; - var subcellInit = Actor.Actor.InitDict.GetOrDefault(); - if (subcellInit != null) - { - Actor.Actor.InitDict.Remove(subcellInit); + if (Actor.RemoveInits() > 0) updated = true; - } var subcell = world.Map.Tiles.Contains(cell) ? editorLayer.FreeSubCellAt(cell) : SubCell.Invalid; if (subcell != SubCell.Invalid) { - Actor.Actor.InitDict.Add(new SubCellInit(subcell)); + Actor.AddInit(new SubCellInit(subcell)); updated = true; } } if (updated) - Actor = new EditorActorPreview(wr, null, Actor.Actor, Actor.Owner); + Actor = new EditorActorPreview(wr, null, Actor.Export(), Actor.Owner); } } @@ -184,25 +179,25 @@ namespace OpenRA.Mods.Common.Traits ownerName = specificOwnerInfo.ValidOwnerNames.First(); var reference = new ActorReference(actor.Name); - reference.InitDict.Add(new OwnerInit(ownerName)); - reference.InitDict.Add(new FactionInit(owner.Faction)); + reference.Add(new OwnerInit(ownerName)); + reference.Add(new FactionInit(owner.Faction)); var worldPx = wr.Viewport.ViewToWorldPx(Viewport.LastMousePos) - wr.ScreenPxOffset(actorCenterOffset); var cell = wr.Viewport.ViewToWorld(wr.Viewport.WorldToViewPx(worldPx)); - reference.InitDict.Add(new LocationInit(cell)); + reference.Add(new LocationInit(cell)); if (ios != null && ios.SharesCell) { actorSubCell = editorLayer.FreeSubCellAt(cell); if (actorSubCell != SubCell.Invalid) - reference.InitDict.Add(new SubCellInit(actorSubCell)); + reference.Add(new SubCellInit(actorSubCell)); } if (actor.HasTraitInfo()) - reference.InitDict.Add(new FacingInit(info.PreviewFacing)); + reference.Add(new FacingInit(info.PreviewFacing)); if (actor.HasTraitInfo()) - reference.InitDict.Add(new TurretFacingInit(info.PreviewFacing)); + reference.Add(new TurretFacingInit(info.PreviewFacing)); Type = EditorCursorType.Actor; Actor = new EditorActorPreview(wr, null, reference, owner); diff --git a/OpenRA.Mods.Common/Traits/World/SpawnMapActors.cs b/OpenRA.Mods.Common/Traits/World/SpawnMapActors.cs index 26eb50e445..a73df3e63f 100644 --- a/OpenRA.Mods.Common/Traits/World/SpawnMapActors.cs +++ b/OpenRA.Mods.Common/Traits/World/SpawnMapActors.cs @@ -35,18 +35,17 @@ namespace OpenRA.Mods.Common.Traits var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); // If there is no real player associated, don't spawn it. - var ownerName = actorReference.InitDict.Get().InternalName; + var ownerName = actorReference.Get().InternalName; if (!world.Players.Any(p => p.InternalName == ownerName)) continue; - var initDict = actorReference.InitDict; - initDict.Add(new SkipMakeAnimsInit()); - initDict.Add(new SpawnedByMapInit(kv.Key)); + actorReference.Add(new SkipMakeAnimsInit()); + actorReference.Add(new SpawnedByMapInit(kv.Key)); if (PreventMapSpawn(world, actorReference, preventMapSpawns)) continue; - var actor = world.CreateActor(actorReference.Type, initDict); + var actor = world.CreateActor(true, actorReference); Actors[kv.Key] = actor; LastMapActorID = actor.ActorID; } diff --git a/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs index e41e86684e..b9338a847d 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs @@ -410,11 +410,10 @@ namespace OpenRA.Mods.Common.UtilityCommands new OwnerInit(parts[0]), }; - var initDict = actor.InitDict; if (health != 100) - initDict.Add(new HealthInit(health)); + actor.Add(new HealthInit(health)); if (facing != 0) - initDict.Add(new FacingInit(255 - facing)); + actor.Add(new FacingInit(255 - facing)); if (section == "INFANTRY") actor.Add(new SubCellInit((SubCell)Exts.ParseByte(parts[4]))); diff --git a/OpenRA.Mods.Common/UtilityCommands/ResizeMapCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ResizeMapCommand.cs index 64e9e28131..20ac5b8922 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ResizeMapCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ResizeMapCommand.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Linq; using OpenRA.FileSystem; namespace OpenRA.Mods.Common.UtilityCommands @@ -57,10 +58,13 @@ namespace OpenRA.Mods.Common.UtilityCommands foreach (var kv in map.ActorDefinitions) { var actor = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); - var location = actor.InitDict.Get().Value; - if (!map.Contains(location)) + var locationInit = actor.GetOrDefault(); + if (locationInit == null) + continue; + + if (!map.Contains(locationInit.Value)) { - Console.WriteLine("Removing actor {0} located at {1} due being outside of the new map boundaries.".F(actor.Type, location)); + Console.WriteLine("Removing actor {0} located at {1} due being outside of the new map boundaries.".F(actor.Type, locationInit.Value)); forRemoval.Add(kv); } }