Replace IActorInit with an abstract class.

A shared ValueActorInit<T> is introduced to reduce duplication
in the most common init cases, and an ActorInitActorReference
allow actors to be referenced by map.yaml name.
This commit is contained in:
Paul Chote
2020-06-02 19:37:18 +01:00
committed by teinarss
parent 4df5ac0385
commit b38018af9c
28 changed files with 365 additions and 306 deletions

View File

@@ -10,77 +10,128 @@
#endregion
using System;
using System.ComponentModel;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Common
{
public class FacingInit : IActorInit<int>
public class FacingInit : ValueActorInit<int>
{
[FieldFromYamlKey]
readonly int value = 128;
public FacingInit() { }
public FacingInit(int init) { value = init; }
public int Value { get { return value; } }
public FacingInit(int value)
: base(value) { }
}
public class CreationActivityDelayInit : IActorInit<int>
public class CreationActivityDelayInit : ValueActorInit<int>
{
[FieldFromYamlKey]
readonly int value = 0;
public CreationActivityDelayInit() { }
public CreationActivityDelayInit(int init) { value = init; }
public int Value { get { return value; } }
public CreationActivityDelayInit(int value)
: base(value) { }
}
public class DynamicFacingInit : IActorInit<Func<int>>
public class DynamicFacingInit : ValueActorInit<Func<int>>
{
readonly Func<int> func;
public DynamicFacingInit(Func<int> func) { this.func = func; }
public Func<int> Value { get { return func; } }
public DynamicFacingInit(Func<int> value)
: base(value) { }
}
public class SubCellInit : IActorInit<SubCell>
public class SubCellInit : ValueActorInit<SubCell>
{
[FieldFromYamlKey]
readonly byte value = (byte)SubCell.FullCell;
public SubCellInit() { }
public SubCellInit(byte init) { value = init; }
public SubCellInit(SubCell init) { value = (byte)init; }
public SubCell Value { get { return (SubCell)value; } }
public SubCellInit(SubCell value)
: base(value) { }
}
public class CenterPositionInit : IActorInit<WPos>
public class CenterPositionInit : ValueActorInit<WPos>
{
[FieldFromYamlKey]
readonly WPos value = WPos.Zero;
public CenterPositionInit() { }
public CenterPositionInit(WPos init) { value = init; }
public WPos Value { get { return value; } }
public CenterPositionInit(WPos value)
: base(value) { }
}
// Allows maps / transformations to specify the faction variant of an actor.
public class FactionInit : IActorInit<string>
public class FactionInit : ValueActorInit<string>
{
[FieldFromYamlKey]
public readonly string Faction;
public FactionInit() { }
public FactionInit(string faction) { Faction = faction; }
public string Value { get { return Faction; } }
public FactionInit(string value)
: base(value) { }
}
public class EffectiveOwnerInit : IActorInit<Player>
public class EffectiveOwnerInit : ValueActorInit<Player>
{
[FieldFromYamlKey]
readonly Player value = null;
public EffectiveOwnerInit(Player value)
: base(value) { }
}
public EffectiveOwnerInit() { }
public EffectiveOwnerInit(Player owner) { value = owner; }
public Player Value { get { return value; } }
internal class ActorInitLoader : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
return new ActorInitActorReference(value as string);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
var reference = value as ActorInitActorReference;
if (reference != null)
return reference.InternalName;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
[TypeConverter(typeof(ActorInitLoader))]
public class ActorInitActorReference
{
public readonly string InternalName;
readonly Actor actor;
public ActorInitActorReference(Actor actor)
{
this.actor = actor;
}
public ActorInitActorReference(string internalName)
{
InternalName = internalName;
}
Actor InnerValue(World world)
{
if (actor != null)
return actor;
var sma = world.WorldActor.Trait<SpawnMapActors>();
return sma.Actors[InternalName];
}
/// <summary>
/// The lazy value may reference other actors that have not been created
/// yet, so must not be resolved from the actor constructor or Created method.
/// Use a FrameEndTask or wait until it is actually needed.
/// </summary>
public Lazy<Actor> Actor(World world)
{
return new Lazy<Actor>(() => InnerValue(world));
}
public static implicit operator ActorInitActorReference(Actor a)
{
return new ActorInitActorReference(a);
}
public static implicit operator ActorInitActorReference(string mapName)
{
return new ActorInitActorReference(mapName);
}
}
}

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
@@ -41,12 +42,12 @@ namespace OpenRA.Mods.Common.Graphics
this.dict = dict;
}
public T GetOrDefault<T>(TraitInfo info) where T : IActorInit
public T GetOrDefault<T>(TraitInfo info) where T : ActorInit
{
return dict.GetOrDefault<T>();
}
public T Get<T>(TraitInfo info) where T : IActorInit
public T Get<T>(TraitInfo info) where T : ActorInit
{
var init = GetOrDefault<T>(info);
if (init == null)
@@ -55,18 +56,18 @@ namespace OpenRA.Mods.Common.Graphics
return init;
}
public U GetValue<T, U>(TraitInfo info) where T : IActorInit<U>
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 : IActorInit<U>
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 : IActorInit { return GetOrDefault<T>(info) != null; }
public bool Contains<T>(TraitInfo info) where T : ActorInit { return GetOrDefault<T>(info) != null; }
public Func<WRot> GetOrientation()
{

View File

@@ -10,7 +10,10 @@
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Eluant;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
@@ -24,6 +27,37 @@ namespace OpenRA.Mods.Common.Scripting
public ActorGlobal(ScriptContext context)
: base(context) { }
ActorInit CreateInit(string initName, LuaValue value)
{
// Find the requested type
var initType = Game.ModData.ObjectCreator.FindType(initName + "Init");
if (initType == null)
throw new LuaException("Unknown initializer type '{0}'".F(initName));
// Construct the ActorInit.
var init = (ActorInit)FormatterServices.GetUninitializedObject(initType);
var initializers = initType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(m => m.Name == "Initialize" && m.GetParameters().Length == 1);
foreach (var initializer in initializers)
{
var parameterType = initializer.GetParameters().First().ParameterType;
var valueType = parameterType.IsEnum ? Enum.GetUnderlyingType(parameterType) : parameterType;
// Try and coerce the table value to the required type
object clrValue;
if (!value.TryGetClrValue(valueType, out clrValue))
continue;
initializer.Invoke(init, new[] { clrValue });
return init;
}
var types = initializers.Select(y => y.GetParameters()[0].ParameterType.Name).JoinWith(", ");
throw new LuaException("Invalid data type for '{0}' (expected one of {1})".F(initName, types));
}
[Desc("Create a new actor. initTable specifies a list of key-value pairs that defines the initial parameters for the actor's traits.")]
public Actor Create(string type, bool addToWorld, LuaTable initTable)
{
@@ -34,35 +68,7 @@ namespace OpenRA.Mods.Common.Scripting
{
using (kv.Key)
using (kv.Value)
{
// Find the requested type
var typeName = kv.Key.ToString();
var initType = Game.ModData.ObjectCreator.FindType(typeName + "Init");
if (initType == null)
throw new LuaException("Unknown initializer type '{0}'".F(typeName));
// HACK: Handle OwnerInit as a special case until ActorInit creation can be rewritten
Type innerType, valueType;
if (initType != typeof(OwnerInit))
{
// Cast it up to an IActorInit<T>
var genericType = initType.GetInterfaces()
.First(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IActorInit<>));
innerType = genericType.GetGenericArguments().First();
valueType = innerType.IsEnum ? Enum.GetUnderlyingType(innerType) : innerType;
}
else
innerType = valueType = typeof(Player);
// Try and coerce the table value to the required type
object value;
if (!kv.Value.TryGetClrValue(valueType, out value))
throw new LuaException("Invalid data type for '{0}' (expected '{1}')".F(typeName, valueType.Name));
// Construct the ActorInit. Phew!
var test = initType.GetConstructor(new[] { innerType }).Invoke(new[] { value });
initDict.Add(test);
}
initDict.Add(CreateInit(kv.Key.ToString(), kv.Value));
}
var owner = initDict.GetOrDefault<OwnerInit>();

View File

@@ -123,7 +123,7 @@ namespace OpenRA.Mods.Common.Traits
var stance = init != null ? init.Value : InitialStance;
return stances[(int)stance];
},
(actor, value) => actor.ReplaceInit(new StanceInit((UnitStance)stances.IndexOf(value))));
(actor, value) => actor.ReplaceInit(new StanceInit(this, (UnitStance)stances.IndexOf(value))));
}
}
@@ -445,13 +445,9 @@ namespace OpenRA.Mods.Common.Traits
}
}
public class StanceInit : IActorInit<UnitStance>
public class StanceInit : ValueActorInit<UnitStance>
{
[FieldFromYamlKey]
readonly UnitStance value = UnitStance.AttackAnything;
public StanceInit() { }
public StanceInit(UnitStance init) { value = init; }
public UnitStance Value { get { return value; } }
public StanceInit(TraitInfo info, UnitStance value)
: base(info, value) { }
}
}

View File

@@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Traits
},
(actor, value) =>
{
actor.ReplaceInit(new FreeActorInit(value));
actor.ReplaceInit(new FreeActorInit(this, value));
});
}
@@ -87,20 +87,15 @@ namespace OpenRA.Mods.Common.Traits
}
}
public class FreeActorInit : IActorInit<bool>
public class FreeActorInit : ValueActorInit<bool>
{
[FieldFromYamlKey]
public readonly bool ActorValue = true;
public FreeActorInit() { }
public FreeActorInit(bool init) { ActorValue = init; }
public bool Value { get { return ActorValue; } }
public FreeActorInit(TraitInfo info, bool value)
: base(info, value) { }
}
public class ParentActorInit : IActorInit
public class ParentActorInit : ValueActorInit<ActorInitActorReference>
{
readonly Actor value;
public ParentActorInit(Actor init) { value = init; }
public Lazy<Actor> Value(World world) { return new Lazy<Actor>(() => value); }
public ParentActorInit(Actor value)
: base(value) { }
}
}

View File

@@ -33,10 +33,10 @@ namespace OpenRA.Mods.Common.Traits
public LegacyBridgeHut(ActorInitializer init, LegacyBridgeHutInfo info)
{
var bridge = init.GetOrDefault<ParentActorInit>(info);
var bridge = init.Get<ParentActorInit>(info).Value;
init.World.AddFrameEndTask(_ =>
{
Bridge = bridge.Value(init.World).Value.Trait<Bridge>();
Bridge = bridge.Actor(init.World).Value.Trait<Bridge>();
Bridge.AddHut(this);
FirstBridge = Bridge.Enumerate(0, true).Last();
});

View File

@@ -16,33 +16,29 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
public enum LineBuildDirection { Unset, X, Y }
public class LineBuildDirectionInit : IActorInit<LineBuildDirection>
public class LineBuildDirectionInit : ValueActorInit<LineBuildDirection>
{
[FieldFromYamlKey]
readonly LineBuildDirection value = LineBuildDirection.Unset;
public LineBuildDirectionInit() { }
public LineBuildDirectionInit(LineBuildDirection init) { value = init; }
public LineBuildDirection Value { get { return value; } }
public LineBuildDirectionInit(LineBuildDirection value)
: base(value) { }
}
public class LineBuildParentInit : IActorInit<string[]>
public class LineBuildParentInit : ValueActorInit<string[]>
{
[FieldFromYamlKey]
public readonly string[] ParentNames = new string[0];
readonly Actor[] parents = null;
public LineBuildParentInit() { }
public LineBuildParentInit(Actor[] init) { parents = init; }
public string[] Value { get { return ParentNames; } }
public LineBuildParentInit(Actor[] value)
: base(new string[0])
{
parents = value;
}
public Actor[] ActorValue(World world)
{
if (parents != null)
return parents;
var sma = world.WorldActor.Trait<SpawnMapActors>();
return ParentNames.Select(n => sma.Actors[n]).ToArray();
return value.Select(n => sma.Actors[n]).ToArray();
}
}

View File

@@ -479,25 +479,19 @@ namespace OpenRA.Mods.Common.Traits
void ITransformActorInitModifier.ModifyTransformActorInit(Actor self, TypeDictionary init)
{
init.Add(new RuntimeCargoInit(Passengers.ToArray()));
init.Add(new RuntimeCargoInit(Info, Passengers.ToArray()));
}
}
public class RuntimeCargoInit : IActorInit<Actor[]>, ISuppressInitExport
public class RuntimeCargoInit : ValueActorInit<Actor[]>, ISuppressInitExport
{
[FieldFromYamlKey]
readonly Actor[] value = { };
public RuntimeCargoInit() { }
public RuntimeCargoInit(Actor[] init) { value = init; }
public Actor[] Value { get { return value; } }
public RuntimeCargoInit(TraitInfo info, Actor[] value)
: base(info, value) { }
}
public class CargoInit : IActorInit<string[]>
public class CargoInit : ValueActorInit<string[]>
{
[FieldFromYamlKey]
readonly string[] value = { };
public CargoInit() { }
public CargoInit(string[] init) { value = init; }
public string[] Value { get { return value; } }
public CargoInit(TraitInfo info, string[] value)
: base(info, value) { }
}
}

View File

@@ -80,7 +80,7 @@ namespace OpenRA.Mods.Common.Traits
},
(actor, value) =>
{
actor.ReplaceInit(new DeployStateInit(value ? DeployState.Deployed : DeployState.Undeployed));
actor.ReplaceInit(new DeployStateInit(this, value ? DeployState.Deployed : DeployState.Undeployed));
});
}
@@ -337,12 +337,12 @@ namespace OpenRA.Mods.Common.Traits
}
}
public class DeployStateInit : IActorInit<DeployState>
public class DeployStateInit : ValueActorInit<DeployState>
{
[FieldFromYamlKey]
readonly DeployState value = DeployState.Deployed;
public DeployStateInit() { }
public DeployStateInit(DeployState init) { value = init; }
public DeployState Value { get { return value; } }
public DeployStateInit(TraitInfo info, DeployState value)
: base(info, value) { }
public DeployStateInit(DeployState value)
: base(value) { }
}
}

View File

@@ -141,17 +141,13 @@ namespace OpenRA.Mods.Common.Traits
void ITransformActorInitModifier.ModifyTransformActorInit(Actor self, TypeDictionary init)
{
init.Add(new ExperienceInit(experience));
init.Add(new ExperienceInit(info, experience));
}
}
class ExperienceInit : IActorInit<int>
class ExperienceInit : ValueActorInit<int>
{
[FieldFromYamlKey]
readonly int value;
public ExperienceInit() { }
public ExperienceInit(int init) { value = init; }
public int Value { get { return value; } }
public ExperienceInit(TraitInfo info, int value)
: base(info, value) { }
}
}

View File

@@ -233,23 +233,17 @@ namespace OpenRA.Mods.Common.Traits
}
}
public class HealthInit : IActorInit<int>
public class HealthInit : ValueActorInit<int>
{
[FieldFromYamlKey]
readonly int value = 100;
readonly bool allowZero;
public HealthInit() { }
public HealthInit(int init)
: this(init, false) { }
public HealthInit(int init, bool allowZero)
{
this.allowZero = allowZero;
value = init;
}
public HealthInit(TraitInfo info, int value, bool allowZero = false)
: base(info, value) { this.allowZero = allowZero; }
public int Value
public HealthInit(int value, bool allowZero = false)
: base(value) { this.allowZero = allowZero; }
public override int Value
{
get
{

View File

@@ -171,13 +171,9 @@ namespace OpenRA.Mods.Common.Traits
Player IEffectiveOwner.Owner { get { return effectiveOwner; } }
}
public class HuskSpeedInit : IActorInit<int>
public class HuskSpeedInit : ValueActorInit<int>
{
[FieldFromYamlKey]
readonly int value = 0;
public HuskSpeedInit() { }
public HuskSpeedInit(int init) { value = init; }
public int Value { get { return value; } }
public HuskSpeedInit(int value)
: base(value) { }
}
}

View File

@@ -146,7 +146,7 @@ namespace OpenRA.Mods.Common.Traits
if (turretInit != null)
{
var newTurretFacing = (turretInit.Value + newFacing - oldFacing + 255) % 255;
actor.ReplaceInit(new TurretFacingInit(newTurretFacing));
actor.ReplaceInit(new TurretFacingInit(this, newTurretFacing));
}
if (turretsInit != null)

View File

@@ -195,5 +195,5 @@ namespace OpenRA.Mods.Common.Traits
}
}
public class HiddenUnderFogInit : IActorInit { }
public class HiddenUnderFogInit : RuntimeFlagInit { }
}

View File

@@ -16,7 +16,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
// Allows third party mods to detect whether an actor was created by PlaceBuilding.
public class PlaceBuildingInit : IActorInit { }
public class PlaceBuildingInit : RuntimeFlagInit { }
[Desc("Allows the player to execute build orders.", " Attach this to the player actor.")]
public class PlaceBuildingInfo : TraitInfo

View File

@@ -120,12 +120,9 @@ namespace OpenRA.Mods.Common.Traits
}
}
public class PlugsInit : IActorInit<Dictionary<CVec, string>>
public class PlugsInit : ValueActorInit<Dictionary<CVec, string>>
{
[DictionaryFromYamlKey]
readonly Dictionary<CVec, string> value = new Dictionary<CVec, string>();
public PlugsInit() { }
public PlugsInit(Dictionary<CVec, string> init) { value = init; }
public Dictionary<CVec, string> Value { get { return value; } }
public PlugsInit(Dictionary<CVec, string> value)
: base(value) { }
}
}

View File

@@ -110,13 +110,9 @@ namespace OpenRA.Mods.Common.Traits
}
}
public class ProductionSpawnLocationInit : IActorInit<CPos>
public class ProductionSpawnLocationInit : ValueActorInit<CPos>
{
[FieldFromYamlKey]
readonly CPos value = CPos.Zero;
public ProductionSpawnLocationInit() { }
public ProductionSpawnLocationInit(CPos init) { value = init; }
public CPos Value { get { return value; } }
public ProductionSpawnLocationInit(TraitInfo info, CPos value)
: base(info, value) { }
}
}

View File

@@ -168,13 +168,9 @@ namespace OpenRA.Mods.Common.Traits.Render
}
}
public class RuntimeNeighbourInit : IActorInit<Dictionary<CPos, string[]>>, ISuppressInitExport
public class RuntimeNeighbourInit : ValueActorInit<Dictionary<CPos, string[]>>, ISuppressInitExport
{
[FieldFromYamlKey]
readonly Dictionary<CPos, string[]> value = null;
public RuntimeNeighbourInit() { }
public RuntimeNeighbourInit(Dictionary<CPos, string[]> init) { value = init; }
public Dictionary<CPos, string[]> Value { get { return value; } }
public RuntimeNeighbourInit(Dictionary<CPos, string[]> value)
: base(value) { }
}
}

View File

@@ -49,13 +49,9 @@ namespace OpenRA.Mods.Common.Traits
}
/// <summary>Allows mappers to 'tag' actors with arbitrary strings that may have meaning in their scripts.</summary>
public class ScriptTagsInit : IActorInit<string[]>
public class ScriptTagsInit : ValueActorInit<string[]>
{
[FieldFromYamlKey]
readonly string[] value = new string[0];
public ScriptTagsInit() { }
public ScriptTagsInit(string[] init) { value = init; }
public string[] Value { get { return value; } }
public ScriptTagsInit(string[] value)
: base(value) { }
}
}

View File

@@ -41,7 +41,7 @@ namespace OpenRA.Mods.Common.Traits
// HACK: The ActorInit system does not support multiple instances of the same type
// Make sure that we only return one TurretFacingInit, even for actors with multiple turrets
if (ai.TraitInfos<TurretedInfo>().FirstOrDefault() == this)
yield return new TurretFacingInit(PreviewFacing);
yield return new TurretFacingInit(this, PreviewFacing);
}
IEnumerable<EditorActorOption> IEditorActorOptions.ActorOptions(ActorInfo ai, World world)
@@ -66,6 +66,8 @@ namespace OpenRA.Mods.Common.Traits
(actor, value) =>
{
actor.RemoveInit<TurretFacingsInit>();
// Force a single global turret facing for multi-turret actors by not passing this TraitInfo instance
actor.ReplaceInit(new TurretFacingInit((int)value));
});
}
@@ -230,7 +232,7 @@ namespace OpenRA.Mods.Common.Traits
var facings = init.GetOrDefault<TurretFacingsInit>();
if (facings == null)
{
facings = new TurretFacingsInit();
facings = new TurretFacingsInit(new Dictionary<string, int>());
init.Add(facings);
}
@@ -243,7 +245,7 @@ namespace OpenRA.Mods.Common.Traits
var facings = inits.GetOrDefault<DynamicTurretFacingsInit>();
if (facings == null)
{
facings = new DynamicTurretFacingsInit();
facings = new DynamicTurretFacingsInit(Info, new Dictionary<string, Func<int>>());
inits.Add(facings);
}
@@ -267,31 +269,24 @@ namespace OpenRA.Mods.Common.Traits
}
}
public class TurretFacingInit : IActorInit<int>
public class TurretFacingInit : ValueActorInit<int>
{
[FieldFromYamlKey]
readonly int value = 128;
public TurretFacingInit(TraitInfo info, int value)
: base(info, value) { }
public TurretFacingInit() { }
public TurretFacingInit(int init) { value = init; }
public int Value { get { return value; } }
public TurretFacingInit(int value)
: base(value) { }
}
public class TurretFacingsInit : IActorInit<Dictionary<string, int>>
public class TurretFacingsInit : ValueActorInit<Dictionary<string, int>>
{
[DictionaryFromYamlKey]
readonly Dictionary<string, int> value = new Dictionary<string, int>();
public TurretFacingsInit() { }
public TurretFacingsInit(Dictionary<string, int> init) { value = init; }
public Dictionary<string, int> Value { get { return value; } }
public TurretFacingsInit(Dictionary<string, int> value)
: base(value) { }
}
public class DynamicTurretFacingsInit : IActorInit<Dictionary<string, Func<int>>>
public class DynamicTurretFacingsInit : ValueActorInit<Dictionary<string, Func<int>>>
{
readonly Dictionary<string, Func<int>> value = new Dictionary<string, Func<int>>();
public DynamicTurretFacingsInit() { }
public DynamicTurretFacingsInit(Dictionary<string, Func<int>> init) { value = init; }
public Dictionary<string, Func<int>> Value { get { return value; } }
public DynamicTurretFacingsInit(TraitInfo info, Dictionary<string, Func<int>> value)
: base(info, value) { }
}
}

View File

@@ -62,12 +62,10 @@ namespace OpenRA.Mods.Common.Traits
}
}
public class SkipMakeAnimsInit : IActorInit, ISuppressInitExport { }
public class SpawnedByMapInit : IActorInit<string>, ISuppressInitExport
public class SkipMakeAnimsInit : RuntimeFlagInit { }
public class SpawnedByMapInit : ValueActorInit<string>, ISuppressInitExport
{
public readonly string Name;
public SpawnedByMapInit(string name) { Name = name; }
public string Value { get { return Name; } }
public SpawnedByMapInit(string value)
: base(value) { }
}
}

View File

@@ -19,6 +19,7 @@ using OpenRA.Graphics;
using OpenRA.Mods.Common.FileFormats;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.UtilityCommands
{
@@ -416,7 +417,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
initDict.Add(new FacingInit(255 - facing));
if (section == "INFANTRY")
actor.Add(new SubCellInit(Exts.ParseByte(parts[4])));
actor.Add(new SubCellInit((SubCell)Exts.ParseByte(parts[4])));
var actorCount = map.ActorDefinitions.Count;