Make ActorPreview and EditorActorPreview wrap ActorReference.

This commit is contained in:
Paul Chote
2020-06-12 13:21:09 +01:00
committed by reaperrr
parent ae7cfa56b7
commit c6c3a8c60d
22 changed files with 265 additions and 162 deletions

View File

@@ -145,6 +145,9 @@ namespace OpenRA
protected ValueActorInit(TraitInfo info, T value) protected ValueActorInit(TraitInfo info, T value)
: base(info.InstanceName) { this.value = 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; } protected ValueActorInit(T value) { this.value = value; }
public virtual T Value { get { return value; } } public virtual T Value { get { return value; } }

View File

@@ -13,8 +13,10 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using OpenRA.Primitives; using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA namespace OpenRA
{ {
@@ -23,13 +25,10 @@ namespace OpenRA
public class ActorReference : IEnumerable public class ActorReference : IEnumerable
{ {
public string Type; public string Type;
public TypeDictionary InitDict
{
get { return initDict.Value; }
}
Lazy<TypeDictionary> initDict; Lazy<TypeDictionary> initDict;
internal TypeDictionary InitDict { get { return initDict.Value; } }
public ActorReference(string type) public ActorReference(string type)
: this(type, new Dictionary<string, MiniYaml>()) { } : this(type, new Dictionary<string, MiniYaml>()) { }
@@ -52,6 +51,18 @@ namespace OpenRA
}); });
} }
public ActorReference(string type, TypeDictionary inits)
{
Type = type;
initDict = new Lazy<TypeDictionary>(() =>
{
var dict = new TypeDictionary();
foreach (var i in inits)
dict.Add(i);
return dict;
});
}
static ActorInit LoadInit(string initName, MiniYaml initYaml) static ActorInit LoadInit(string initName, MiniYaml initYaml)
{ {
var initInstance = initName.Split(ActorInfo.TraitInstanceSeparator); var initInstance = initName.Split(ActorInfo.TraitInstanceSeparator);
@@ -74,7 +85,7 @@ namespace OpenRA
public MiniYaml Save(Func<ActorInit, bool> initFilter = null) public MiniYaml Save(Func<ActorInit, bool> initFilter = null)
{ {
var ret = new MiniYaml(Type); var ret = new MiniYaml(Type);
foreach (var o in InitDict) foreach (var o in initDict.Value)
{ {
var init = o as ActorInit; var init = o as ActorInit;
if (init == null || o is ISuppressInitExport) if (init == null || o is ISuppressInitExport)
@@ -94,7 +105,17 @@ namespace OpenRA
return ret; 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) public void Add(ActorInit init)
{ {
if (init is ISingleInstanceInit && InitDict.Contains(init.GetType())) if (init is ISingleInstanceInit && InitDict.Contains(init.GetType()))
@@ -103,15 +124,83 @@ namespace OpenRA
InitDict.Add(init); InitDict.Add(init);
} }
public IEnumerator GetEnumerator() { return InitDict.GetEnumerator(); } public void Remove(ActorInit o) { initDict.Value.Remove(o); }
public ActorReference Clone() public int RemoveAll<T>() where T : ActorInit
{ {
var clone = new ActorReference(Type); var removed = 0;
foreach (var init in InitDict) foreach (var o in initDict.Value.WithInterface<T>().ToList())
clone.InitDict.Add(init); {
removed++;
initDict.Value.Remove(o);
}
return clone; return removed;
} }
public IEnumerable<T> GetAll<T>() where T : ActorInit
{
return initDict.Value.WithInterface<T>();
}
public T GetOrDefault<T>(TraitInfo info) where T : ActorInit
{
var inits = initDict.Value.WithInterface<T>();
// 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<T>(TraitInfo info) where T : ActorInit
{
var init = GetOrDefault<T>(info);
if (init == null)
throw new InvalidOperationException("TypeDictionary does not contain instance of type `{0}`".F(typeof(T)));
return init;
}
public U GetValue<T, U>(TraitInfo info) where T : ValueActorInit<U>
{
return Get<T>(info).Value;
}
public U GetValue<T, U>(TraitInfo info, U fallback) where T : ValueActorInit<U>
{
var init = GetOrDefault<T>(info);
return init != null ? init.Value : fallback;
}
public bool Contains<T>(TraitInfo info) where T : ActorInit { return GetOrDefault<T>(info) != null; }
public T GetOrDefault<T>() where T : ActorInit, ISingleInstanceInit
{
return initDict.Value.GetOrDefault<T>();
}
public T Get<T>() where T : ActorInit, ISingleInstanceInit
{
return initDict.Value.Get<T>();
}
public U GetValue<T, U>() where T : ValueActorInit<U>, ISingleInstanceInit
{
return Get<T>().Value;
}
public U GetValue<T, U>(U fallback) where T : ValueActorInit<U>, ISingleInstanceInit
{
var init = GetOrDefault<T>();
return init != null ? init.Value : fallback;
}
public bool Contains<T>() where T : ActorInit, ISingleInstanceInit { return GetOrDefault<T>() != null; }
} }
} }

View File

@@ -276,7 +276,7 @@ namespace OpenRA
foreach (var kv in actorDefinitions.Nodes.Where(d => d.Value.Value == "mpspawn")) foreach (var kv in actorDefinitions.Nodes.Where(d => d.Value.Value == "mpspawn"))
{ {
var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary());
spawns.Add(s.InitDict.Get<LocationInit>().Value); spawns.Add(s.Get<LocationInit>().Value);
} }
newData.SpawnPoints = spawns.ToArray(); newData.SpawnPoints = spawns.ToArray();

View File

@@ -334,6 +334,11 @@ namespace OpenRA
return CreateActor(true, name, initDict); 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) public Actor CreateActor(bool addToWorld, string name, TypeDictionary initDict)
{ {
var a = new Actor(this, name, initDict); var a = new Actor(this, name, initDict);

View File

@@ -62,7 +62,7 @@ namespace OpenRA.Mods.Common.Widgets
if (!actor.Footprint.All(c => world.Map.Tiles.Contains(c.Key))) if (!actor.Footprint.All(c => world.Map.Tiles.Contains(c.Key)))
return true; return true;
var action = new AddActorAction(editorLayer, actor.Actor); var action = new AddActorAction(editorLayer, actor.Export());
editorActionManager.Add(action); editorActionManager.Add(action);
} }

View File

@@ -134,11 +134,11 @@ namespace OpenRA.Mods.Common.Widgets
continue; continue;
var copy = preview.Export(); var copy = preview.Export();
if (copy.InitDict.Contains<LocationInit>()) var locationInit = copy.GetOrDefault<LocationInit>();
if (locationInit != null)
{ {
var location = copy.InitDict.Get<LocationInit>(); copy.RemoveAll<LocationInit>();
copy.InitDict.Remove(location); copy.Add(new LocationInit(locationInit.Value + offset));
copy.InitDict.Add(new LocationInit(location.Value + offset));
} }
previews.Add(preview.ID, copy); previews.Add(preview.ID, copy);

View File

@@ -33,74 +33,34 @@ namespace OpenRA.Mods.Common.Graphics
public readonly WorldRenderer WorldRenderer; public readonly WorldRenderer WorldRenderer;
public World World { get { return WorldRenderer.World; } } public World World { get { return WorldRenderer.World; } }
readonly TypeDictionary dict; readonly ActorReference reference;
public ActorPreviewInitializer(ActorInfo actor, WorldRenderer worldRenderer, TypeDictionary dict) public ActorPreviewInitializer(ActorInfo actor, WorldRenderer worldRenderer, TypeDictionary dict)
{ {
Actor = actor; Actor = actor;
WorldRenderer = worldRenderer; WorldRenderer = worldRenderer;
this.dict = dict; reference = new ActorReference(actor.Name, dict);
} }
public T GetOrDefault<T>(TraitInfo info) where T : ActorInit public ActorPreviewInitializer(ActorReference actor, WorldRenderer worldRenderer)
{ {
var inits = dict.WithInterface<T>(); Actor = worldRenderer.World.Map.Rules.Actors[actor.Type];
reference = actor;
// Traits tagged with an instance name prefer inits with the same name. WorldRenderer = worldRenderer;
// 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<T>(TraitInfo info) where T : ActorInit // Forward IActorInitializer queries to the actor reference
{ // ActorReference can't reference a World instance, which prevents it from implementing this directly.
var init = GetOrDefault<T>(info); public T GetOrDefault<T>(TraitInfo info) where T : ActorInit { return reference.GetOrDefault<T>(info); }
if (init == null) public T Get<T>(TraitInfo info) where T : ActorInit { return reference.Get<T>(info); }
throw new InvalidOperationException("TypeDictionary does not contain instance of type `{0}`".F(typeof(T))); public U GetValue<T, U>(TraitInfo info) where T : ValueActorInit<U> { return reference.GetValue<T, U>(info); }
public U GetValue<T, U>(TraitInfo info, U fallback) where T : ValueActorInit<U> { return reference.GetValue<T, U>(info, fallback); }
return init; public bool Contains<T>(TraitInfo info) where T : ActorInit { return reference.Contains<T>(info); }
} public T GetOrDefault<T>() where T : ActorInit, ISingleInstanceInit { return reference.GetOrDefault<T>(); }
public T Get<T>() where T : ActorInit, ISingleInstanceInit { return reference.Get<T>(); }
public U GetValue<T, U>(TraitInfo info) where T : ValueActorInit<U> public U GetValue<T, U>() where T : ValueActorInit<U>, ISingleInstanceInit { return reference.GetValue<T, U>(); }
{ public U GetValue<T, U>(U fallback) where T : ValueActorInit<U>, ISingleInstanceInit { return reference.GetValue<T, U>(fallback); }
return Get<T>(info).Value; public bool Contains<T>() where T : ActorInit, ISingleInstanceInit { return reference.Contains<T>(); }
}
public U GetValue<T, U>(TraitInfo info, U fallback) where T : ValueActorInit<U>
{
var init = GetOrDefault<T>(info);
return init != null ? init.Value : fallback;
}
public bool Contains<T>() where T : ActorInit, ISingleInstanceInit { return GetOrDefault<T>() != null; }
public T GetOrDefault<T>() where T : ActorInit, ISingleInstanceInit
{
return dict.GetOrDefault<T>();
}
public T Get<T>() where T : ActorInit, ISingleInstanceInit
{
return dict.Get<T>();
}
public U GetValue<T, U>() where T : ValueActorInit<U>, ISingleInstanceInit
{
return Get<T>().Value;
}
public U GetValue<T, U>(U fallback) where T : ValueActorInit<U>, ISingleInstanceInit
{
var init = GetOrDefault<T>();
return init != null ? init.Value : fallback;
}
public bool Contains<T>(TraitInfo info) where T : ActorInit { return GetOrDefault<T>(info) != null; }
public Func<WRot> GetOrientation() public Func<WRot> GetOrientation()
{ {
@@ -109,7 +69,7 @@ namespace OpenRA.Mods.Common.Graphics
return () => WRot.Zero; return () => WRot.Zero;
// Dynamic facing takes priority // Dynamic facing takes priority
var dynamicInit = dict.GetOrDefault<DynamicFacingInit>(); var dynamicInit = reference.GetOrDefault<DynamicFacingInit>();
if (dynamicInit != null) if (dynamicInit != null)
{ {
// TODO: Account for terrain slope // 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 // Fall back to initial actor facing if an Init isn't available
var facingInit = dict.GetOrDefault<FacingInit>(); var facingInit = reference.GetOrDefault<FacingInit>();
var facing = facingInit != null ? facingInit.Value : facingInfo.GetInitialFacing(); var facing = facingInit != null ? facingInit.Value : facingInfo.GetInitialFacing();
var orientation = WRot.FromFacing(facing); var orientation = WRot.FromFacing(facing);
return () => orientation; return () => orientation;
@@ -131,7 +91,7 @@ namespace OpenRA.Mods.Common.Graphics
return () => WAngle.Zero; return () => WAngle.Zero;
// Dynamic facing takes priority // Dynamic facing takes priority
var dynamicInit = dict.GetOrDefault<DynamicFacingInit>(); var dynamicInit = reference.GetOrDefault<DynamicFacingInit>();
if (dynamicInit != null) if (dynamicInit != null)
{ {
var getFacing = dynamicInit.Value; 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 // Fall back to initial actor facing if an Init isn't available
var facingInit = dict.GetOrDefault<FacingInit>(); var facingInit = reference.GetOrDefault<FacingInit>();
var facing = WAngle.FromFacing(facingInit != null ? facingInit.Value : facingInfo.GetInitialFacing()); var facing = WAngle.FromFacing(facingInit != null ? facingInit.Value : facingInfo.GetInitialFacing());
return () => facing; return () => facing;
} }
public DamageState GetDamageState() public DamageState GetDamageState()
{ {
var health = dict.GetOrDefault<HealthInit>(); var health = reference.GetOrDefault<HealthInit>();
if (health == null) if (health == null)
return DamageState.Undamaged; return DamageState.Undamaged;

View File

@@ -70,7 +70,7 @@ namespace OpenRA.Mods.Common.Lint
foreach (var kv in map.ActorDefinitions.Where(d => d.Value.Value == "mpspawn")) foreach (var kv in map.ActorDefinitions.Where(d => d.Value.Value == "mpspawn"))
{ {
var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary());
spawns.Add(s.InitDict.Get<LocationInit>().Value); spawns.Add(s.Get<LocationInit>().Value);
} }
if (playerCount > spawns.Count) if (playerCount > spawns.Count)
@@ -88,7 +88,7 @@ namespace OpenRA.Mods.Common.Lint
foreach (var kv in map.ActorDefinitions) foreach (var kv in map.ActorDefinitions)
{ {
var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary());
var ownerInit = actorReference.InitDict.GetOrDefault<OwnerInit>(); var ownerInit = actorReference.GetOrDefault<OwnerInit>();
if (ownerInit == null) if (ownerInit == null)
emitError("Actor {0} is not owned by any player.".F(kv.Key)); emitError("Actor {0} is not owned by any player.".F(kv.Key));
else else

View File

@@ -184,7 +184,7 @@ namespace OpenRA.Mods.Common.Traits
yield return new EditorActorSlider("Facing", EditorFacingDisplayOrder, 0, 255, 8, yield return new EditorActorSlider("Facing", EditorFacingDisplayOrder, 0, 255, 8,
actor => actor =>
{ {
var init = actor.Init<FacingInit>(); var init = actor.GetInitOrDefault<FacingInit>(this);
return init != null ? init.Value : InitialFacing; return init != null ? init.Value : InitialFacing;
}, },
(actor, value) => actor.ReplaceInit(new FacingInit((int)value))); (actor, value) => actor.ReplaceInit(new FacingInit((int)value)));

View File

@@ -42,14 +42,14 @@ namespace OpenRA.Mods.Common.Traits
} }
else else
{ {
var owner = map.PlayerDefinitions.Single(p => s.InitDict.Get<OwnerInit>().InternalName == p.Value.Nodes.Last(k => k.Key == "Name").Value.Value); var owner = map.PlayerDefinitions.Single(p => s.Get<OwnerInit>().InternalName == p.Value.Nodes.Last(k => k.Key == "Name").Value.Value);
var colorValue = owner.Value.Nodes.Where(n => n.Key == "Color"); var colorValue = owner.Value.Nodes.Where(n => n.Key == "Color");
var ownerColor = colorValue.Any() ? colorValue.First().Value.Value : "FFFFFF"; var ownerColor = colorValue.Any() ? colorValue.First().Value.Value : "FFFFFF";
Color.TryParse(ownerColor, out color); Color.TryParse(ownerColor, out color);
} }
var ios = ai.TraitInfo<IOccupySpaceInfo>(); var ios = ai.TraitInfo<IOccupySpaceInfo>();
var cells = ios.OccupiedCells(ai, s.InitDict.Get<LocationInit>().Value); var cells = ios.OccupiedCells(ai, s.Get<LocationInit>().Value);
foreach (var cell in cells) foreach (var cell in cells)
destinationBuffer.Add(new Pair<MPos, Color>(cell.Key.ToMPos(map), color)); destinationBuffer.Add(new Pair<MPos, Color>(cell.Key.ToMPos(map), color));
} }

View File

@@ -119,7 +119,7 @@ namespace OpenRA.Mods.Common.Traits
yield return new EditorActorDropdown("Stance", EditorStanceDisplayOrder, labels, yield return new EditorActorDropdown("Stance", EditorStanceDisplayOrder, labels,
actor => actor =>
{ {
var init = actor.Init<StanceInit>(); var init = actor.GetInitOrDefault<StanceInit>(this);
var stance = init != null ? init.Value : InitialStance; var stance = init != null ? init.Value : InitialStance;
return stances[(int)stance]; return stances[(int)stance];
}, },

View File

@@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Traits
yield return new EditorActorCheckbox("Spawn Child Actor", EditorFreeActorDisplayOrder, yield return new EditorActorCheckbox("Spawn Child Actor", EditorFreeActorDisplayOrder,
actor => actor =>
{ {
var init = actor.Init<FreeActorInit>(); var init = actor.GetInitOrDefault<FreeActorInit>(this);
if (init != null) if (init != null)
return init.Value; return init.Value;
@@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Traits
}, },
(actor, value) => (actor, value) =>
{ {
actor.ReplaceInit(new FreeActorInit(this, value)); actor.ReplaceInit(new FreeActorInit(this, value), this);
}); });
} }

View File

@@ -72,7 +72,7 @@ namespace OpenRA.Mods.Common.Traits
yield return new EditorActorCheckbox("Deployed", EditorDeployedDisplayOrder, yield return new EditorActorCheckbox("Deployed", EditorDeployedDisplayOrder,
actor => actor =>
{ {
var init = actor.Init<DeployStateInit>(); var init = actor.GetInitOrDefault<DeployStateInit>();
if (init != null) if (init != null)
return init.Value == DeployState.Deployed; return init.Value == DeployState.Deployed;

View File

@@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Traits
yield return new EditorActorSlider("Health", EditorHealthDisplayOrder, 0, 100, 5, yield return new EditorActorSlider("Health", EditorHealthDisplayOrder, 0, 100, 5,
actor => actor =>
{ {
var init = actor.Init<HealthInit>(); var init = actor.GetInitOrDefault<HealthInit>();
return init != null ? init.Value : 100; return init != null ? init.Value : 100;
}, },
(actor, value) => actor.ReplaceInit(new HealthInit((int)value))); (actor, value) => actor.ReplaceInit(new HealthInit((int)value)));

View File

@@ -130,23 +130,24 @@ namespace OpenRA.Mods.Common.Traits
yield return new EditorActorSlider("Facing", EditorFacingDisplayOrder, 0, 255, 8, yield return new EditorActorSlider("Facing", EditorFacingDisplayOrder, 0, 255, 8,
actor => actor =>
{ {
var init = actor.Init<FacingInit>(); var init = actor.GetInitOrDefault<FacingInit>(this);
return init != null ? init.Value : InitialFacing; return init != null ? init.Value : InitialFacing;
}, },
(actor, value) => (actor, value) =>
{ {
// TODO: This can all go away once turrets are properly defined as a relative facing // TODO: This can all go away once turrets are properly defined as a relative facing
var turretInit = actor.Init<TurretFacingInit>(); var turretsInit = actor.GetInitOrDefault<TurretFacingsInit>();
var turretsInit = actor.Init<TurretFacingsInit>(); var facingInit = actor.GetInitOrDefault<FacingInit>();
var facingInit = actor.Init<FacingInit>();
var oldFacing = facingInit != null ? facingInit.Value : InitialFacing; var oldFacing = facingInit != null ? facingInit.Value : InitialFacing;
var newFacing = (int)value; var newFacing = (int)value;
if (turretInit != null) var turretInits = actor.GetInits<TurretFacingInit>().ToList();
actor.RemoveInits<TurretFacingInit>();
foreach (var turretInit in turretInits)
{ {
var newTurretFacing = (turretInit.Value + newFacing - oldFacing + 255) % 255; var newTurretFacing = (turretInit.Value + newFacing - oldFacing + 255) % 255;
actor.ReplaceInit(new TurretFacingInit(this, newTurretFacing)); actor.AddInit(new TurretFacingInit(turretInit.InstanceName, newTurretFacing));
} }
if (turretsInit != null) if (turretsInit != null)

View File

@@ -53,11 +53,11 @@ namespace OpenRA.Mods.Common.Traits
yield return new EditorActorSlider("Turret", EditorTurretFacingDisplayOrder, 0, 255, 8, yield return new EditorActorSlider("Turret", EditorTurretFacingDisplayOrder, 0, 255, 8,
actor => actor =>
{ {
var init = actor.Init<TurretFacingInit>(); var init = actor.GetInitOrDefault<TurretFacingInit>(this);
if (init != null) if (init != null)
return init.Value; return init.Value;
var facingInit = actor.Init<FacingInit>(); var facingInit = actor.GetInitOrDefault<FacingInit>(this);
if (facingInit != null) if (facingInit != null)
return facingInit.Value; return facingInit.Value;
@@ -67,8 +67,9 @@ namespace OpenRA.Mods.Common.Traits
{ {
actor.RemoveInit<TurretFacingsInit>(); actor.RemoveInit<TurretFacingsInit>();
// Force a single global turret facing for multi-turret actors by not passing this TraitInfo instance // Force a single global turret facing for multi-turret actors
actor.ReplaceInit(new TurretFacingInit((int)value)); actor.RemoveInits<TurretFacingInit>();
actor.AddInit(new TurretFacingInit((int)value));
}); });
} }
@@ -274,6 +275,9 @@ namespace OpenRA.Mods.Common.Traits
public TurretFacingInit(TraitInfo info, int value) public TurretFacingInit(TraitInfo info, int value)
: base(info, value) { } : base(info, value) { }
public TurretFacingInit(string instanceName, int value)
: base(instanceName, value) { }
public TurretFacingInit(int value) public TurretFacingInit(int value)
: base(value) { } : base(value) { }
} }

View File

@@ -118,7 +118,7 @@ namespace OpenRA.Mods.Common.Traits
public EditorActorPreview Add(string id, ActorReference reference, bool initialSetup = false) public EditorActorPreview Add(string id, ActorReference reference, bool initialSetup = false)
{ {
var owner = Players.Players[reference.InitDict.Get<OwnerInit>().InternalName]; var owner = Players.Players[reference.Get<OwnerInit>().InternalName];
var preview = new EditorActorPreview(worldRenderer, id, reference, owner); var preview = new EditorActorPreview(worldRenderer, id, reference, owner);
Add(preview, initialSetup); Add(preview, initialSetup);
@@ -144,7 +144,7 @@ namespace OpenRA.Mods.Common.Traits
{ {
UpdateNeighbours(preview.Footprint); UpdateNeighbours(preview.Footprint);
if (preview.Actor.Type == "mpspawn") if (preview.Type == "mpspawn")
SyncMultiplayerCount(); SyncMultiplayerCount();
} }
} }

View File

@@ -28,7 +28,6 @@ namespace OpenRA.Mods.Common.Traits
public readonly IReadOnlyDictionary<CPos, SubCell> Footprint; public readonly IReadOnlyDictionary<CPos, SubCell> Footprint;
public readonly Rectangle Bounds; public readonly Rectangle Bounds;
public readonly SelectionBoxAnnotationRenderable SelectionBox; public readonly SelectionBoxAnnotationRenderable SelectionBox;
public readonly ActorReference Actor;
public string Tooltip 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 string ID { get; set; }
public PlayerReference Owner { get; set; } public PlayerReference Owner { get; set; }
public SubCell SubCell { get; private set; } public SubCell SubCell { get; private set; }
@@ -47,30 +48,31 @@ namespace OpenRA.Mods.Common.Traits
readonly WorldRenderer worldRenderer; readonly WorldRenderer worldRenderer;
readonly TooltipInfoBase tooltip; readonly TooltipInfoBase tooltip;
IActorPreview[] previews; 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; ID = id;
Actor = actor; this.reference = reference;
Owner = owner; Owner = owner;
this.worldRenderer = worldRenderer; this.worldRenderer = worldRenderer;
if (!actor.InitDict.Contains<FactionInit>()) if (!reference.Contains<FactionInit>())
actor.InitDict.Add(new FactionInit(owner.Faction)); reference.Add(new FactionInit(owner.Faction));
if (!actor.InitDict.Contains<OwnerInit>()) if (!reference.Contains<OwnerInit>())
actor.InitDict.Add(new OwnerInit(owner.Name)); reference.Add(new OwnerInit(owner.Name));
var world = worldRenderer.World; var world = worldRenderer.World;
if (!world.Map.Rules.Actors.TryGetValue(actor.Type.ToLowerInvariant(), out Info)) if (!world.Map.Rules.Actors.TryGetValue(reference.Type.ToLowerInvariant(), out Info))
throw new InvalidDataException("Actor {0} of unknown type {1}".F(id, actor.Type.ToLowerInvariant())); 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<LocationInit>().Value; var location = reference.Get<LocationInit>().Value;
var ios = Info.TraitInfoOrDefault<IOccupySpaceInfo>(); var ios = Info.TraitInfoOrDefault<IOccupySpaceInfo>();
var subCellInit = actor.InitDict.GetOrDefault<SubCellInit>(); var subCellInit = reference.GetOrDefault<SubCellInit>();
var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any; var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any;
if (ios != null) if (ios != null)
@@ -124,27 +126,66 @@ namespace OpenRA.Mods.Common.Traits
yield return SelectionBox; yield return SelectionBox;
} }
public void ReplaceInit<T>(T init) public void AddInit<T>(T init) where T : ActorInit
{ {
var original = Actor.InitDict.GetOrDefault<T>(); reference.Add(init);
if (original != null)
Actor.InitDict.Remove(original);
Actor.InitDict.Add(init);
GeneratePreviews(); GeneratePreviews();
} }
public void RemoveInit<T>() public void ReplaceInit<T>(T init, TraitInfo info) where T : ActorInit
{ {
var original = Actor.InitDict.GetOrDefault<T>(); var original = GetInitOrDefault<T>(info);
if (original != null) if (original != null)
Actor.InitDict.Remove(original); reference.Remove(original);
reference.Add(init);
GeneratePreviews(); GeneratePreviews();
} }
public T Init<T>() public void RemoveInit<T>(TraitInfo info) where T : ActorInit
{ {
return Actor.InitDict.GetOrDefault<T>(); var original = GetInitOrDefault<T>(info);
if (original != null)
reference.Remove(original);
GeneratePreviews();
}
public int RemoveInits<T>() where T : ActorInit
{
var removed = reference.RemoveAll<T>();
GeneratePreviews();
return removed;
}
public T GetInitOrDefault<T>(TraitInfo info) where T : ActorInit
{
return reference.GetOrDefault<T>(info);
}
public IEnumerable<T> GetInits<T>() where T : ActorInit
{
return reference.GetAll<T>();
}
public T GetInitOrDefault<T>() where T : ActorInit, ISingleInstanceInit
{
return reference.GetOrDefault<T>();
}
public void ReplaceInit<T>(T init) where T : ActorInit, ISingleInstanceInit
{
var original = reference.GetOrDefault<T>();
if (original != null)
reference.Remove(original);
reference.Add(init);
GeneratePreviews();
}
public void RemoveInit<T>() where T : ActorInit, ISingleInstanceInit
{
reference.RemoveAll<T>();
GeneratePreviews();
} }
public MiniYaml Save() public MiniYaml Save()
@@ -160,20 +201,23 @@ namespace OpenRA.Mods.Common.Traits
return true; 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<CenterPositionInit>()) var centerPositionInit = actor.GetOrDefault<CenterPositionInit>();
return init.Get<CenterPositionInit>().Value; if (centerPositionInit != null)
return centerPositionInit.Value;
if (init.Contains<LocationInit>()) var locationInit = actor.GetOrDefault<LocationInit>();
if (locationInit != null)
{ {
var cell = init.Get<LocationInit>().Value; var cell = locationInit.Value;
var offset = WVec.Zero; var offset = WVec.Zero;
var subCellInit = Actor.InitDict.GetOrDefault<SubCellInit>(); var subCellInit = reference.GetOrDefault<SubCellInit>();
var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any; var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any;
var buildingInfo = Info.TraitInfoOrDefault<BuildingInfo>(); var buildingInfo = Info.TraitInfoOrDefault<BuildingInfo>();
@@ -188,7 +232,7 @@ namespace OpenRA.Mods.Common.Traits
void GeneratePreviews() void GeneratePreviews()
{ {
var init = new ActorPreviewInitializer(Info, worldRenderer, Actor.InitDict); var init = new ActorPreviewInitializer(reference, worldRenderer);
previews = Info.TraitInfos<IRenderActorPreviewInfo>() previews = Info.TraitInfos<IRenderActorPreviewInfo>()
.SelectMany(rpi => rpi.RenderPreview(init)) .SelectMany(rpi => rpi.RenderPreview(init))
.ToArray(); .ToArray();
@@ -196,7 +240,7 @@ namespace OpenRA.Mods.Common.Traits
public ActorReference Export() public ActorReference Export()
{ {
return new ActorReference(Actor.Type, Actor.Save().ToDictionary()); return reference.Clone();
} }
public override string ToString() public override string ToString()

View File

@@ -113,8 +113,7 @@ namespace OpenRA.Mods.Common.Traits
if (actorLocation != cell) if (actorLocation != cell)
{ {
actorLocation = cell; actorLocation = cell;
Actor.Actor.InitDict.Remove(Actor.Actor.InitDict.Get<LocationInit>()); Actor.ReplaceInit(new LocationInit(cell));
Actor.Actor.InitDict.Add(new LocationInit(cell));
updated = true; updated = true;
} }
@@ -122,23 +121,19 @@ namespace OpenRA.Mods.Common.Traits
{ {
actorSubCell = subCell; actorSubCell = subCell;
var subcellInit = Actor.Actor.InitDict.GetOrDefault<SubCellInit>(); if (Actor.RemoveInits<SubCellInit>() > 0)
if (subcellInit != null)
{
Actor.Actor.InitDict.Remove(subcellInit);
updated = true; updated = true;
}
var subcell = world.Map.Tiles.Contains(cell) ? editorLayer.FreeSubCellAt(cell) : SubCell.Invalid; var subcell = world.Map.Tiles.Contains(cell) ? editorLayer.FreeSubCellAt(cell) : SubCell.Invalid;
if (subcell != SubCell.Invalid) if (subcell != SubCell.Invalid)
{ {
Actor.Actor.InitDict.Add(new SubCellInit(subcell)); Actor.AddInit(new SubCellInit(subcell));
updated = true; updated = true;
} }
} }
if (updated) 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(); ownerName = specificOwnerInfo.ValidOwnerNames.First();
var reference = new ActorReference(actor.Name); var reference = new ActorReference(actor.Name);
reference.InitDict.Add(new OwnerInit(ownerName)); reference.Add(new OwnerInit(ownerName));
reference.InitDict.Add(new FactionInit(owner.Faction)); reference.Add(new FactionInit(owner.Faction));
var worldPx = wr.Viewport.ViewToWorldPx(Viewport.LastMousePos) - wr.ScreenPxOffset(actorCenterOffset); var worldPx = wr.Viewport.ViewToWorldPx(Viewport.LastMousePos) - wr.ScreenPxOffset(actorCenterOffset);
var cell = wr.Viewport.ViewToWorld(wr.Viewport.WorldToViewPx(worldPx)); 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) if (ios != null && ios.SharesCell)
{ {
actorSubCell = editorLayer.FreeSubCellAt(cell); actorSubCell = editorLayer.FreeSubCellAt(cell);
if (actorSubCell != SubCell.Invalid) if (actorSubCell != SubCell.Invalid)
reference.InitDict.Add(new SubCellInit(actorSubCell)); reference.Add(new SubCellInit(actorSubCell));
} }
if (actor.HasTraitInfo<IFacingInfo>()) if (actor.HasTraitInfo<IFacingInfo>())
reference.InitDict.Add(new FacingInit(info.PreviewFacing)); reference.Add(new FacingInit(info.PreviewFacing));
if (actor.HasTraitInfo<TurretedInfo>()) if (actor.HasTraitInfo<TurretedInfo>())
reference.InitDict.Add(new TurretFacingInit(info.PreviewFacing)); reference.Add(new TurretFacingInit(info.PreviewFacing));
Type = EditorCursorType.Actor; Type = EditorCursorType.Actor;
Actor = new EditorActorPreview(wr, null, reference, owner); Actor = new EditorActorPreview(wr, null, reference, owner);

View File

@@ -35,18 +35,17 @@ namespace OpenRA.Mods.Common.Traits
var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary());
// If there is no real player associated, don't spawn it. // If there is no real player associated, don't spawn it.
var ownerName = actorReference.InitDict.Get<OwnerInit>().InternalName; var ownerName = actorReference.Get<OwnerInit>().InternalName;
if (!world.Players.Any(p => p.InternalName == ownerName)) if (!world.Players.Any(p => p.InternalName == ownerName))
continue; continue;
var initDict = actorReference.InitDict; actorReference.Add(new SkipMakeAnimsInit());
initDict.Add(new SkipMakeAnimsInit()); actorReference.Add(new SpawnedByMapInit(kv.Key));
initDict.Add(new SpawnedByMapInit(kv.Key));
if (PreventMapSpawn(world, actorReference, preventMapSpawns)) if (PreventMapSpawn(world, actorReference, preventMapSpawns))
continue; continue;
var actor = world.CreateActor(actorReference.Type, initDict); var actor = world.CreateActor(true, actorReference);
Actors[kv.Key] = actor; Actors[kv.Key] = actor;
LastMapActorID = actor.ActorID; LastMapActorID = actor.ActorID;
} }

View File

@@ -410,11 +410,10 @@ namespace OpenRA.Mods.Common.UtilityCommands
new OwnerInit(parts[0]), new OwnerInit(parts[0]),
}; };
var initDict = actor.InitDict;
if (health != 100) if (health != 100)
initDict.Add(new HealthInit(health)); actor.Add(new HealthInit(health));
if (facing != 0) if (facing != 0)
initDict.Add(new FacingInit(255 - facing)); actor.Add(new FacingInit(255 - facing));
if (section == "INFANTRY") if (section == "INFANTRY")
actor.Add(new SubCellInit((SubCell)Exts.ParseByte(parts[4]))); actor.Add(new SubCellInit((SubCell)Exts.ParseByte(parts[4])));

View File

@@ -11,6 +11,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using OpenRA.FileSystem; using OpenRA.FileSystem;
namespace OpenRA.Mods.Common.UtilityCommands namespace OpenRA.Mods.Common.UtilityCommands
@@ -57,10 +58,13 @@ namespace OpenRA.Mods.Common.UtilityCommands
foreach (var kv in map.ActorDefinitions) foreach (var kv in map.ActorDefinitions)
{ {
var actor = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); var actor = new ActorReference(kv.Value.Value, kv.Value.ToDictionary());
var location = actor.InitDict.Get<LocationInit>().Value; var locationInit = actor.GetOrDefault<LocationInit>();
if (!map.Contains(location)) 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); forRemoval.Add(kv);
} }
} }