Add CompositeActorInit and simplify chronoshift inits.
This commit is contained in:
@@ -86,7 +86,7 @@ namespace OpenRA
|
||||
* The object will be allocated directly then the best matching Initialize() method will be called to set valid state.
|
||||
* - ActorReference will always attempt to call Initialize(MiniYaml). ActorGlobal will use whichever one it first
|
||||
* finds with an argument type that matches the given LuaValue.
|
||||
* - Most ActorInits will want to inherit ValueActorInit<T> which hides the low-level plumbing.
|
||||
* - Most ActorInits will want to inherit either ValueActorInit<T> or CompositeActorInit which hide the low-level plumbing.
|
||||
* - Inits that reference actors should use ActorInitActorReference which allows actors to be referenced by name in map.yaml
|
||||
*/
|
||||
public abstract class ActorInit
|
||||
@@ -134,6 +134,54 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class CompositeActorInit : ActorInit
|
||||
{
|
||||
protected CompositeActorInit(TraitInfo info)
|
||||
: base(info.InstanceName) { }
|
||||
|
||||
protected CompositeActorInit()
|
||||
: base() { }
|
||||
|
||||
public virtual void Initialize(MiniYaml yaml)
|
||||
{
|
||||
FieldLoader.Load(this, yaml);
|
||||
}
|
||||
|
||||
public virtual void Initialize(Dictionary<string, object> values)
|
||||
{
|
||||
object value;
|
||||
foreach (var field in GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
|
||||
{
|
||||
var sa = field.GetCustomAttributes<FieldLoader.SerializeAttribute>(false).DefaultIfEmpty(FieldLoader.SerializeAttribute.Default).First();
|
||||
if (!sa.Serialize)
|
||||
continue;
|
||||
|
||||
if (values.TryGetValue(field.Name, out value))
|
||||
field.SetValue(this, value);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Dictionary<string, Type> InitializeArgs()
|
||||
{
|
||||
var dict = new Dictionary<string, Type>();
|
||||
foreach (var field in GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
|
||||
{
|
||||
var sa = field.GetCustomAttributes<FieldLoader.SerializeAttribute>(false).DefaultIfEmpty(FieldLoader.SerializeAttribute.Default).First();
|
||||
if (!sa.Serialize)
|
||||
continue;
|
||||
|
||||
dict[field.Name] = field.FieldType;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
public override MiniYaml Save()
|
||||
{
|
||||
return FieldSaver.Save(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class LocationInit : ValueActorInit<CPos>
|
||||
{
|
||||
public LocationInit(TraitInfo info, CPos value)
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Mods.Cnc.Activities;
|
||||
using OpenRA.Mods.Common;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
@@ -60,14 +59,18 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
: base(info)
|
||||
{
|
||||
self = init.Self;
|
||||
ReturnTicks = init.GetValue<ChronoshiftReturnInit, int>(info, 0);
|
||||
duration = init.GetValue<ChronoshiftDurationInit, int>(info, 0);
|
||||
Origin = init.GetValue<ChronoshiftOriginInit, CPos>(info, CPos.Zero);
|
||||
|
||||
var returnInit = init.GetOrDefault<ChronoshiftReturnInit>(info);
|
||||
if (returnInit != null)
|
||||
{
|
||||
ReturnTicks = returnInit.Ticks;
|
||||
duration = returnInit.Duration;
|
||||
Origin = returnInit.Origin;
|
||||
|
||||
// Defer to the end of tick as the lazy value may reference an actor that hasn't been created yet
|
||||
var chronosphereInit = init.GetOrDefault<ChronoshiftChronosphereInit>(info);
|
||||
if (chronosphereInit != null)
|
||||
init.World.AddFrameEndTask(w => chronosphere = chronosphereInit.Value.Actor(init.World).Value);
|
||||
if (returnInit.Chronosphere != null)
|
||||
init.World.AddFrameEndTask(w => chronosphere = returnInit.Chronosphere.Actor(init.World).Value);
|
||||
}
|
||||
}
|
||||
|
||||
void ITick.Tick(Actor self)
|
||||
@@ -91,7 +94,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
typeof(Actor).GetProperty("CurrentActivity").SetValue(self, null);
|
||||
|
||||
// The actor is killed using Info.DamageTypes if the teleport fails
|
||||
self.QueueActivity(false, new Teleport(chronosphere, Origin, null, true, killCargo, Info.ChronoshiftSound,
|
||||
self.QueueActivity(false, new Teleport(chronosphere ?? self, Origin, null, true, killCargo, Info.ChronoshiftSound,
|
||||
false, true, Info.DamageTypes));
|
||||
}
|
||||
}
|
||||
@@ -166,38 +169,26 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
if (IsTraitDisabled || !Info.ReturnToOrigin || ReturnTicks <= 0)
|
||||
return;
|
||||
|
||||
init.Add(new ChronoshiftOriginInit(Origin));
|
||||
init.Add(new ChronoshiftReturnInit(ReturnTicks));
|
||||
init.Add(new ChronoshiftDurationInit(duration));
|
||||
if (chronosphere != self)
|
||||
init.Add(new ChronoshiftChronosphereInit(chronosphere));
|
||||
init.Add(new ChronoshiftReturnInit(ReturnTicks, duration, Origin, chronosphere));
|
||||
}
|
||||
|
||||
void IDeathActorInitModifier.ModifyDeathActorInit(Actor self, TypeDictionary init) { ModifyActorInit(init); }
|
||||
void ITransformActorInitModifier.ModifyTransformActorInit(Actor self, TypeDictionary init) { ModifyActorInit(init); }
|
||||
}
|
||||
|
||||
public class ChronoshiftReturnInit : ValueActorInit<int>
|
||||
public class ChronoshiftReturnInit : CompositeActorInit
|
||||
{
|
||||
public ChronoshiftReturnInit(int value)
|
||||
: base(value) { }
|
||||
}
|
||||
public readonly int Ticks;
|
||||
public readonly int Duration;
|
||||
public readonly CPos Origin;
|
||||
public readonly ActorInitActorReference Chronosphere;
|
||||
|
||||
public class ChronoshiftDurationInit : ValueActorInit<int>
|
||||
public ChronoshiftReturnInit(int ticks, int duration, CPos origin, Actor chronosphere)
|
||||
{
|
||||
public ChronoshiftDurationInit(int value)
|
||||
: base(value) { }
|
||||
Ticks = ticks;
|
||||
Duration = duration;
|
||||
Origin = origin;
|
||||
Chronosphere = chronosphere;
|
||||
}
|
||||
|
||||
public class ChronoshiftOriginInit : ValueActorInit<CPos>
|
||||
{
|
||||
public ChronoshiftOriginInit(CPos value)
|
||||
: base(value) { }
|
||||
}
|
||||
|
||||
public class ChronoshiftChronosphereInit : ValueActorInit<ActorInitActorReference>
|
||||
{
|
||||
public ChronoshiftChronosphereInit(Actor value)
|
||||
: base(value) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,14 +96,18 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
|
||||
wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body);
|
||||
faction = init.GetValue<FactionInit, string>(info, self.Owner.Faction.InternalName);
|
||||
returnTicks = init.GetValue<ChronoshiftReturnInit, int>(info, 0);
|
||||
duration = init.GetValue<ChronoshiftDurationInit, int>(info, 0);
|
||||
origin = init.GetValue<ChronoshiftOriginInit, CPos>(info, CPos.Zero);
|
||||
|
||||
var returnInit = init.GetOrDefault<ChronoshiftReturnInit>(info);
|
||||
if (returnInit != null)
|
||||
{
|
||||
returnTicks = returnInit.Ticks;
|
||||
duration = returnInit.Duration;
|
||||
origin = returnInit.Origin;
|
||||
|
||||
// Defer to the end of tick as the lazy value may reference an actor that hasn't been created yet
|
||||
var chronosphereInit = init.GetOrDefault<ChronoshiftChronosphereInit>(info);
|
||||
if (chronosphereInit != null)
|
||||
init.World.AddFrameEndTask(w => chronosphere = chronosphereInit.Value.Actor(init.World).Value);
|
||||
if (returnInit.Chronosphere != null)
|
||||
init.World.AddFrameEndTask(w => chronosphere = returnInit.Chronosphere.Actor(init.World).Value);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<VariableObserver> IObservesVariables.GetVariableObservers()
|
||||
@@ -228,11 +232,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
if (returnTicks <= 0)
|
||||
return;
|
||||
|
||||
init.Add(new ChronoshiftOriginInit(origin));
|
||||
init.Add(new ChronoshiftReturnInit(returnTicks));
|
||||
init.Add(new ChronoshiftDurationInit(duration));
|
||||
if (chronosphere != self)
|
||||
init.Add(new ChronoshiftChronosphereInit(chronosphere));
|
||||
init.Add(new ChronoshiftReturnInit(returnTicks, duration, origin, chronosphere));
|
||||
}
|
||||
|
||||
void IDeathActorInitModifier.ModifyDeathActorInit(Actor self, TypeDictionary init) { ModifyActorInit(init); }
|
||||
|
||||
@@ -40,6 +40,41 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
if (initInstance.Length > 1)
|
||||
initType.GetField("InstanceName").SetValue(init, initInstance[1]);
|
||||
|
||||
var compositeInit = init as CompositeActorInit;
|
||||
var tableValue = value as LuaTable;
|
||||
if (tableValue != null && compositeInit != null)
|
||||
{
|
||||
var args = compositeInit.InitializeArgs();
|
||||
var initValues = new Dictionary<string, object>();
|
||||
foreach (var kv in tableValue)
|
||||
{
|
||||
using (kv.Key)
|
||||
using (kv.Value)
|
||||
{
|
||||
var key = kv.Key.ToString();
|
||||
Type type;
|
||||
if (!args.TryGetValue(key, out type))
|
||||
throw new LuaException("Unknown initializer type '{0}.{1}'".F(initInstance[0], key));
|
||||
|
||||
object clrValue;
|
||||
var isActorReference = type == typeof(ActorInitActorReference);
|
||||
if (isActorReference)
|
||||
type = kv.Value is LuaString ? typeof(string) : typeof(Actor);
|
||||
|
||||
if (!kv.Value.TryGetClrValue(type, out clrValue))
|
||||
throw new LuaException("Invalid data type for '{0}.{1}' (expected {2}, got {3})".F(initInstance[0], key, type.Name, kv.Value.WrappedClrType()));
|
||||
|
||||
if (isActorReference)
|
||||
clrValue = type == typeof(string) ? new ActorInitActorReference((string)clrValue) : new ActorInitActorReference((Actor)clrValue);
|
||||
|
||||
initValues[key] = clrValue;
|
||||
}
|
||||
}
|
||||
|
||||
compositeInit.Initialize(initValues);
|
||||
return init;
|
||||
}
|
||||
|
||||
var initializers = initType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
.Where(m => m.Name == "Initialize" && m.GetParameters().Length == 1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user