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);
}
}
}