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:
@@ -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>();
|
||||
|
||||
Reference in New Issue
Block a user