Merge pull request #9977 from RoosterDragon/dispose-lua-values
Ensure LuaValues are disposed
This commit is contained in:
@@ -64,7 +64,19 @@ namespace OpenRA.Scripting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For global-level bindings
|
/// <summary>
|
||||||
|
/// Provides global bindings in Lua code.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Instance methods and properties declared in derived classes will be made available in Lua. Use
|
||||||
|
/// <see cref="ScriptGlobalAttribute"/> on your derived class to specify the name exposed in Lua. It is recommended
|
||||||
|
/// to apply <see cref="DescAttribute"/> against each method or property to provide a description of what it does.
|
||||||
|
///
|
||||||
|
/// Any parameters to your method that are <see cref="LuaValue"/>s will be disposed automatically when your method
|
||||||
|
/// completes. If you need to return any of these values, or need them to live longer than your method, you must
|
||||||
|
/// use <see cref="LuaValue.CopyReference"/> to get your own copy of the value. Any copied values you return will
|
||||||
|
/// be disposed automatically, but you assume responsibility for disposing any other copies.
|
||||||
|
/// </remarks>
|
||||||
public abstract class ScriptGlobal : ScriptObjectWrapper
|
public abstract class ScriptGlobal : ScriptObjectWrapper
|
||||||
{
|
{
|
||||||
protected override string DuplicateKeyError(string memberName) { return "Table '{0}' defines multiple members '{1}'".F(Name, memberName); }
|
protected override string DuplicateKeyError(string memberName) { return "Table '{0}' defines multiple members '{1}'".F(Name, memberName); }
|
||||||
@@ -78,11 +90,27 @@ namespace OpenRA.Scripting
|
|||||||
var type = this.GetType();
|
var type = this.GetType();
|
||||||
var names = type.GetCustomAttributes<ScriptGlobalAttribute>(true);
|
var names = type.GetCustomAttributes<ScriptGlobalAttribute>(true);
|
||||||
if (names.Length != 1)
|
if (names.Length != 1)
|
||||||
throw new InvalidOperationException("[LuaGlobal] attribute not found for global table '{0}'".F(type));
|
throw new InvalidOperationException("[ScriptGlobal] attribute not found for global table '{0}'".F(type));
|
||||||
|
|
||||||
Name = names.First().Name;
|
Name = names.First().Name;
|
||||||
Bind(new[] { this });
|
Bind(new[] { this });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected IEnumerable<T> FilteredObjects<T>(IEnumerable<T> objects, LuaFunction filter)
|
||||||
|
{
|
||||||
|
if (filter != null)
|
||||||
|
{
|
||||||
|
objects = objects.Where(a =>
|
||||||
|
{
|
||||||
|
using (var luaObject = a.ToLuaValue(Context))
|
||||||
|
using (var filterResult = filter.Call(luaObject))
|
||||||
|
using (var result = filterResult.First())
|
||||||
|
return result.ToBoolean();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ScriptGlobalAttribute : Attribute
|
public sealed class ScriptGlobalAttribute : Attribute
|
||||||
|
|||||||
@@ -44,31 +44,54 @@ namespace OpenRA.Scripting
|
|||||||
|
|
||||||
LuaValue Invoke(LuaVararg args)
|
LuaValue Invoke(LuaVararg args)
|
||||||
{
|
{
|
||||||
if (!IsMethod)
|
object[] clrArgs = null;
|
||||||
throw new LuaException("Trying to invoke a ScriptMemberWrapper that isn't a method!");
|
try
|
||||||
|
|
||||||
var mi = (MethodInfo)Member;
|
|
||||||
var pi = mi.GetParameters();
|
|
||||||
|
|
||||||
var clrArgs = new object[pi.Length];
|
|
||||||
var argCount = args.Count;
|
|
||||||
for (var i = 0; i < pi.Length; i++)
|
|
||||||
{
|
{
|
||||||
if (i >= argCount)
|
if (!IsMethod)
|
||||||
{
|
throw new LuaException("Trying to invoke a ScriptMemberWrapper that isn't a method!");
|
||||||
if (!pi[i].IsOptional)
|
|
||||||
throw new LuaException("Argument '{0}' of '{1}' is not optional.".F(pi[i].LuaDocString(), Member.LuaDocString()));
|
|
||||||
|
|
||||||
clrArgs[i] = pi[i].DefaultValue;
|
var mi = (MethodInfo)Member;
|
||||||
continue;
|
var pi = mi.GetParameters();
|
||||||
|
|
||||||
|
clrArgs = new object[pi.Length];
|
||||||
|
|
||||||
|
var argCount = args.Count;
|
||||||
|
for (var i = 0; i < pi.Length; i++)
|
||||||
|
{
|
||||||
|
if (i >= argCount)
|
||||||
|
{
|
||||||
|
if (!pi[i].IsOptional)
|
||||||
|
throw new LuaException("Argument '{0}' of '{1}' is not optional.".F(pi[i].LuaDocString(), Member.LuaDocString()));
|
||||||
|
|
||||||
|
clrArgs[i] = pi[i].DefaultValue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args[i].TryGetClrValue(pi[i].ParameterType, out clrArgs[i]))
|
||||||
|
throw new LuaException("Unable to convert parameter {0} to {1}".F(i, pi[i].ParameterType.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args[i].TryGetClrValue(pi[i].ParameterType, out clrArgs[i]))
|
return mi.Invoke(Target, clrArgs).ToLuaValue(context);
|
||||||
throw new LuaException("Unable to convert parameter {0} to {1}".F(i, pi[i].ParameterType.Name));
|
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Clean up all the Lua arguments that were given to us.
|
||||||
|
foreach (var arg in args)
|
||||||
|
arg.Dispose();
|
||||||
|
args.Dispose();
|
||||||
|
|
||||||
var ret = mi.Invoke(Target, clrArgs);
|
// If we created any arrays of LuaValues to pass around, we need to dispose those too.
|
||||||
return ret.ToLuaValue(context);
|
if (clrArgs != null)
|
||||||
|
{
|
||||||
|
foreach (var arg in clrArgs)
|
||||||
|
{
|
||||||
|
if (!(arg is LuaValue[]))
|
||||||
|
continue;
|
||||||
|
foreach (var value in (LuaValue[])arg)
|
||||||
|
value.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LuaValue Get(LuaRuntime runtime)
|
public LuaValue Get(LuaRuntime runtime)
|
||||||
@@ -77,10 +100,7 @@ namespace OpenRA.Scripting
|
|||||||
return runtime.CreateFunctionFromDelegate((Func<LuaVararg, LuaValue>)Invoke);
|
return runtime.CreateFunctionFromDelegate((Func<LuaVararg, LuaValue>)Invoke);
|
||||||
|
|
||||||
if (IsGetProperty)
|
if (IsGetProperty)
|
||||||
{
|
return ((PropertyInfo)Member).GetValue(Target, null).ToLuaValue(context);
|
||||||
var pi = Member as PropertyInfo;
|
|
||||||
return pi.GetValue(Target, null).ToLuaValue(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new LuaException("The property '{0}' is write-only".F(Member.Name));
|
throw new LuaException("The property '{0}' is write-only".F(Member.Name));
|
||||||
}
|
}
|
||||||
@@ -89,7 +109,7 @@ namespace OpenRA.Scripting
|
|||||||
{
|
{
|
||||||
if (IsSetProperty)
|
if (IsSetProperty)
|
||||||
{
|
{
|
||||||
var pi = Member as PropertyInfo;
|
var pi = (PropertyInfo)Member;
|
||||||
object clrValue;
|
object clrValue;
|
||||||
if (!value.TryGetClrValue(pi.PropertyType, out clrValue))
|
if (!value.TryGetClrValue(pi.PropertyType, out clrValue))
|
||||||
throw new LuaException("Unable to convert '{0}' to Clr type '{1}'".F(value.WrappedClrType().Name, pi.PropertyType));
|
throw new LuaException("Unable to convert '{0}' to Clr type '{1}'".F(value.WrappedClrType().Name, pi.PropertyType));
|
||||||
|
|||||||
@@ -107,13 +107,22 @@ namespace OpenRA.Scripting
|
|||||||
|
|
||||||
foreach (var kv in table)
|
foreach (var kv in table)
|
||||||
{
|
{
|
||||||
object element;
|
using (kv.Key)
|
||||||
if (innerType == typeof(LuaValue))
|
{
|
||||||
element = kv.Value;
|
object element;
|
||||||
else if (!kv.Value.TryGetClrValue(innerType, out element))
|
if (innerType == typeof(LuaValue))
|
||||||
throw new LuaException("Unable to convert table value of type {0} to type {1}".F(kv.Value.WrappedClrType(), innerType));
|
element = kv.Value;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var elementHasClrValue = kv.Value.TryGetClrValue(innerType, out element);
|
||||||
|
if (!elementHasClrValue || !(element is LuaValue))
|
||||||
|
kv.Value.Dispose();
|
||||||
|
if (!elementHasClrValue)
|
||||||
|
throw new LuaException("Unable to convert table value of type {0} to type {1}".F(kv.Value.WrappedClrType(), innerType));
|
||||||
|
}
|
||||||
|
|
||||||
array.SetValue(element, i++);
|
array.SetValue(element, i++);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clrObject = array;
|
clrObject = array;
|
||||||
@@ -159,11 +168,13 @@ namespace OpenRA.Scripting
|
|||||||
|
|
||||||
if (obj is Array)
|
if (obj is Array)
|
||||||
{
|
{
|
||||||
var array = obj as Array;
|
var array = (Array)obj;
|
||||||
var i = 1;
|
var i = 1;
|
||||||
var table = context.CreateTable();
|
var table = context.CreateTable();
|
||||||
|
|
||||||
foreach (var x in array)
|
foreach (var x in array)
|
||||||
table.Add(i++, x.ToLuaValue(context));
|
using (LuaValue key = i++, value = x.ToLuaValue(context))
|
||||||
|
table.Add(key, value);
|
||||||
|
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,26 +29,30 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
// Convert table entries into ActorInits
|
// Convert table entries into ActorInits
|
||||||
foreach (var kv in initTable)
|
foreach (var kv in initTable)
|
||||||
{
|
{
|
||||||
// Find the requested type
|
using (kv.Key)
|
||||||
var typeName = kv.Key.ToString();
|
using (kv.Value)
|
||||||
var initType = Game.ModData.ObjectCreator.FindType(typeName + "Init");
|
{
|
||||||
if (initType == null)
|
// Find the requested type
|
||||||
throw new LuaException("Unknown initializer type '{0}'".F(typeName));
|
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));
|
||||||
|
|
||||||
// Cast it up to an IActorInit<T>
|
// Cast it up to an IActorInit<T>
|
||||||
var genericType = initType.GetInterfaces()
|
var genericType = initType.GetInterfaces()
|
||||||
.First(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IActorInit<>));
|
.First(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IActorInit<>));
|
||||||
var innerType = genericType.GetGenericArguments().First();
|
var innerType = genericType.GetGenericArguments().First();
|
||||||
var valueType = innerType.IsEnum ? typeof(int) : innerType;
|
var valueType = innerType.IsEnum ? typeof(int) : innerType;
|
||||||
|
|
||||||
// Try and coerce the table value to the required type
|
// Try and coerce the table value to the required type
|
||||||
object value;
|
object value;
|
||||||
if (!kv.Value.TryGetClrValue(valueType, out value))
|
if (!kv.Value.TryGetClrValue(valueType, out value))
|
||||||
throw new LuaException("Invalid data type for '{0}' (expected '{1}')".F(typeName, valueType.Name));
|
throw new LuaException("Invalid data type for '{0}' (expected '{1}')".F(typeName, valueType.Name));
|
||||||
|
|
||||||
// Construct the ActorInit. Phew!
|
// Construct the ActorInit. Phew!
|
||||||
var test = initType.GetConstructor(new[] { innerType }).Invoke(new[] { value });
|
var test = initType.GetConstructor(new[] { innerType }).Invoke(new[] { value });
|
||||||
initDict.Add(test);
|
initDict.Add(test);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The actor must be added to the world at the end of the tick
|
// The actor must be added to the world at the end of the tick
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Eluant;
|
using Eluant;
|
||||||
using OpenRA.Mods.Common.Traits;
|
using OpenRA.Mods.Common.Traits;
|
||||||
@@ -34,34 +33,14 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
public Actor[] ActorsInCircle(WPos location, WDist radius, LuaFunction filter = null)
|
public Actor[] ActorsInCircle(WPos location, WDist radius, LuaFunction filter = null)
|
||||||
{
|
{
|
||||||
var actors = Context.World.FindActorsInCircle(location, radius);
|
var actors = Context.World.FindActorsInCircle(location, radius);
|
||||||
|
return FilteredObjects(actors, filter).ToArray();
|
||||||
if (filter != null)
|
|
||||||
{
|
|
||||||
actors = actors.Where(a =>
|
|
||||||
{
|
|
||||||
using (var f = filter.Call(a.ToLuaValue(Context)))
|
|
||||||
return f.First().ToBoolean();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return actors.ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Desc("Returns a table of all actors within the requested rectangle, filtered using the specified function.")]
|
[Desc("Returns a table of all actors within the requested rectangle, filtered using the specified function.")]
|
||||||
public Actor[] ActorsInBox(WPos topLeft, WPos bottomRight, LuaFunction filter = null)
|
public Actor[] ActorsInBox(WPos topLeft, WPos bottomRight, LuaFunction filter = null)
|
||||||
{
|
{
|
||||||
var actors = Context.World.ActorMap.ActorsInBox(topLeft, bottomRight);
|
var actors = Context.World.ActorMap.ActorsInBox(topLeft, bottomRight);
|
||||||
|
return FilteredObjects(actors, filter).ToArray();
|
||||||
if (filter != null)
|
|
||||||
{
|
|
||||||
actors = actors.Where(a =>
|
|
||||||
{
|
|
||||||
using (var f = filter.Call(a.ToLuaValue(Context)))
|
|
||||||
return f.First().ToBoolean();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return actors.ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Desc("Returns the location of the top-left corner of the map (assuming zero terrain height).")]
|
[Desc("Returns the location of the top-left corner of the map (assuming zero terrain height).")]
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
Game.Sound.Play(file);
|
Game.Sound.Play(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
Action onComplete;
|
|
||||||
[Desc("Play track defined in music.yaml or map.yaml, or keep track empty for playing a random song.")]
|
[Desc("Play track defined in music.yaml or map.yaml, or keep track empty for playing a random song.")]
|
||||||
public void PlayMusic(string track = null, LuaFunction func = null)
|
public void PlayMusic(string track = null, LuaFunction func = null)
|
||||||
{
|
{
|
||||||
@@ -65,8 +64,8 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
|
|
||||||
if (func != null)
|
if (func != null)
|
||||||
{
|
{
|
||||||
var f = func.CopyReference() as LuaFunction;
|
var f = (LuaFunction)func.CopyReference();
|
||||||
onComplete = () =>
|
Action onComplete = () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -113,13 +112,13 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
playlist.Stop();
|
playlist.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
Action onCompleteFullscreen;
|
|
||||||
[Desc("Play a VQA video fullscreen. File name has to include the file extension.")]
|
[Desc("Play a VQA video fullscreen. File name has to include the file extension.")]
|
||||||
public void PlayMovieFullscreen(string movie, LuaFunction func = null)
|
public void PlayMovieFullscreen(string movie, LuaFunction func = null)
|
||||||
{
|
{
|
||||||
|
Action onCompleteFullscreen;
|
||||||
if (func != null)
|
if (func != null)
|
||||||
{
|
{
|
||||||
var f = func.CopyReference() as LuaFunction;
|
var f = (LuaFunction)func.CopyReference();
|
||||||
onCompleteFullscreen = () =>
|
onCompleteFullscreen = () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -139,15 +138,14 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
Media.PlayFMVFullscreen(world, movie, onCompleteFullscreen);
|
Media.PlayFMVFullscreen(world, movie, onCompleteFullscreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
Action onLoadComplete;
|
|
||||||
Action onCompleteRadar;
|
|
||||||
[Desc("Play a VQA video in the radar window. File name has to include the file extension. " +
|
[Desc("Play a VQA video in the radar window. File name has to include the file extension. " +
|
||||||
"Returns true on success, if the movie wasn't found the function returns false and the callback is executed.")]
|
"Returns true on success, if the movie wasn't found the function returns false and the callback is executed.")]
|
||||||
public bool PlayMovieInRadar(string movie, LuaFunction playComplete = null)
|
public bool PlayMovieInRadar(string movie, LuaFunction playComplete = null)
|
||||||
{
|
{
|
||||||
|
Action onCompleteRadar;
|
||||||
if (playComplete != null)
|
if (playComplete != null)
|
||||||
{
|
{
|
||||||
var f = playComplete.CopyReference() as LuaFunction;
|
var f = (LuaFunction)playComplete.CopyReference();
|
||||||
onCompleteRadar = () =>
|
onCompleteRadar = () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -178,7 +176,7 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
|
|
||||||
AsyncLoader l = new AsyncLoader(Media.LoadVqa);
|
AsyncLoader l = new AsyncLoader(Media.LoadVqa);
|
||||||
IAsyncResult ar = l.BeginInvoke(s, null, null);
|
IAsyncResult ar = l.BeginInvoke(s, null, null);
|
||||||
onLoadComplete = () =>
|
Action onLoadComplete = () =>
|
||||||
{
|
{
|
||||||
Media.StopFMVInRadar();
|
Media.StopFMVInRadar();
|
||||||
world.AddFrameEndTask(_ => Media.PlayFMVInRadar(world, l.EndInvoke(ar), onCompleteRadar));
|
world.AddFrameEndTask(_ => Media.PlayFMVInRadar(world, l.EndInvoke(ar), onCompleteRadar));
|
||||||
|
|||||||
@@ -28,12 +28,7 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
[Desc("Returns a table of players filtered by the specified function.")]
|
[Desc("Returns a table of players filtered by the specified function.")]
|
||||||
public Player[] GetPlayers(LuaFunction filter)
|
public Player[] GetPlayers(LuaFunction filter)
|
||||||
{
|
{
|
||||||
return Context.World.Players
|
return FilteredObjects(Context.World.Players, filter).ToArray();
|
||||||
.Where(p =>
|
|
||||||
{
|
|
||||||
using (var f = filter.Call(p.ToLuaValue(Context)))
|
|
||||||
return f.First().ToBoolean();
|
|
||||||
}).ToArray();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
var actors = new List<Actor>();
|
var actors = new List<Actor>();
|
||||||
for (var i = 0; i < actorTypes.Length; i++)
|
for (var i = 0; i < actorTypes.Length; i++)
|
||||||
{
|
{
|
||||||
var af = actionFunc != null ? actionFunc.CopyReference() as LuaFunction : null;
|
var af = actionFunc != null ? (LuaFunction)actionFunc.CopyReference() : null;
|
||||||
var actor = CreateActor(owner, actorTypes[i], false, entryPath[0], entryPath.Length > 1 ? entryPath[1] : (CPos?)null);
|
var actor = CreateActor(owner, actorTypes[i], false, entryPath[0], entryPath.Length > 1 ? entryPath[1] : (CPos?)null);
|
||||||
actors.Add(actor);
|
actors.Add(actor);
|
||||||
|
|
||||||
@@ -86,8 +86,9 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
{
|
{
|
||||||
actor.QueueActivity(new CallFunc(() =>
|
actor.QueueActivity(new CallFunc(() =>
|
||||||
{
|
{
|
||||||
af.Call(actor.ToLuaValue(Context));
|
using (af)
|
||||||
af.Dispose();
|
using (var a = actor.ToLuaValue(Context))
|
||||||
|
af.Call(a);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -128,11 +129,12 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
|
|
||||||
if (actionFunc != null)
|
if (actionFunc != null)
|
||||||
{
|
{
|
||||||
var af = actionFunc.CopyReference() as LuaFunction;
|
var af = (LuaFunction)actionFunc.CopyReference();
|
||||||
transport.QueueActivity(new CallFunc(() =>
|
transport.QueueActivity(new CallFunc(() =>
|
||||||
{
|
{
|
||||||
af.Call(transport.ToLuaValue(Context), passengers.ToArray().ToLuaValue(Context));
|
using (af)
|
||||||
af.Dispose();
|
using (LuaValue t = transport.ToLuaValue(Context), p = passengers.ToArray().ToLuaValue(Context))
|
||||||
|
af.Call(t, p);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -164,11 +166,12 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
|
|
||||||
if (exitFunc != null)
|
if (exitFunc != null)
|
||||||
{
|
{
|
||||||
var ef = exitFunc.CopyReference() as LuaFunction;
|
var ef = (LuaFunction)exitFunc.CopyReference();
|
||||||
transport.QueueActivity(new CallFunc(() =>
|
transport.QueueActivity(new CallFunc(() =>
|
||||||
{
|
{
|
||||||
ef.Call(transport.ToLuaValue(Context));
|
using (ef)
|
||||||
ef.Dispose();
|
using (var t = transport.ToLuaValue(Context))
|
||||||
|
ef.Call(t);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
else if (exitPath != null)
|
else if (exitPath != null)
|
||||||
@@ -180,8 +183,16 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ret = Context.CreateTable();
|
var ret = Context.CreateTable();
|
||||||
ret.Add(1, transport.ToLuaValue(Context));
|
using (LuaValue
|
||||||
ret.Add(2, passengers.ToArray().ToLuaValue(Context));
|
tKey = 1,
|
||||||
|
tValue = transport.ToLuaValue(Context),
|
||||||
|
pKey = 2,
|
||||||
|
pValue = passengers.ToArray().ToLuaValue(Context))
|
||||||
|
{
|
||||||
|
ret.Add(tKey, tValue);
|
||||||
|
ret.Add(pKey, pValue);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
[Desc("Call a function after a specified delay. The callback function will be called as func().")]
|
[Desc("Call a function after a specified delay. The callback function will be called as func().")]
|
||||||
public void AfterDelay(int delay, LuaFunction func)
|
public void AfterDelay(int delay, LuaFunction func)
|
||||||
{
|
{
|
||||||
var f = func.CopyReference() as LuaFunction;
|
var f = (LuaFunction)func.CopyReference();
|
||||||
|
|
||||||
Action doCall = () =>
|
Action doCall = () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -78,17 +77,15 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
public void OnAllKilled(Actor[] actors, LuaFunction func)
|
public void OnAllKilled(Actor[] actors, LuaFunction func)
|
||||||
{
|
{
|
||||||
var group = actors.ToList();
|
var group = actors.ToList();
|
||||||
var copy = (LuaFunction)func.CopyReference();
|
var f = (LuaFunction)func.CopyReference();
|
||||||
Action<Actor> onMemberKilled = m =>
|
Action<Actor> onMemberKilled = m =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
group.Remove(m);
|
group.Remove(m);
|
||||||
if (!group.Any())
|
if (!group.Any())
|
||||||
{
|
using (f)
|
||||||
copy.Call();
|
f.Call();
|
||||||
copy.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -105,7 +102,7 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
public void OnAnyKilled(Actor[] actors, LuaFunction func)
|
public void OnAnyKilled(Actor[] actors, LuaFunction func)
|
||||||
{
|
{
|
||||||
var called = false;
|
var called = false;
|
||||||
var copy = (LuaFunction)func.CopyReference();
|
var f = (LuaFunction)func.CopyReference();
|
||||||
Action<Actor> onMemberKilled = m =>
|
Action<Actor> onMemberKilled = m =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -113,10 +110,10 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
if (called)
|
if (called)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
using (f)
|
||||||
using (var killed = m.ToLuaValue(Context))
|
using (var killed = m.ToLuaValue(Context))
|
||||||
copy.Call(killed).Dispose();
|
f.Call(killed).Dispose();
|
||||||
|
|
||||||
copy.Dispose();
|
|
||||||
called = true;
|
called = true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -191,7 +188,7 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
{
|
{
|
||||||
var group = actors.ToList();
|
var group = actors.ToList();
|
||||||
|
|
||||||
var copy = (LuaFunction)func.CopyReference();
|
var f = (LuaFunction)func.CopyReference();
|
||||||
Action<Actor> onMemberRemoved = m =>
|
Action<Actor> onMemberRemoved = m =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -200,10 +197,8 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!group.Any())
|
if (!group.Any())
|
||||||
{
|
using (f)
|
||||||
copy.Call().Dispose();
|
f.Call().Dispose();
|
||||||
copy.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -228,7 +223,7 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
{
|
{
|
||||||
var called = false;
|
var called = false;
|
||||||
|
|
||||||
var copy = (LuaFunction)func.CopyReference();
|
var f = (LuaFunction)func.CopyReference();
|
||||||
Action<Actor> onKilledOrCaptured = m =>
|
Action<Actor> onKilledOrCaptured = m =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -236,8 +231,9 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
if (called)
|
if (called)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
copy.Call().Dispose();
|
using (f)
|
||||||
copy.Dispose();
|
f.Call().Dispose();
|
||||||
|
|
||||||
called = true;
|
called = true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -256,7 +252,7 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
{
|
{
|
||||||
var group = actors.ToList();
|
var group = actors.ToList();
|
||||||
|
|
||||||
var copy = (LuaFunction)func.CopyReference();
|
var f = (LuaFunction)func.CopyReference();
|
||||||
Action<Actor> onMemberKilledOrCaptured = m =>
|
Action<Actor> onMemberKilledOrCaptured = m =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -265,10 +261,8 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!group.Any())
|
if (!group.Any())
|
||||||
{
|
using (f)
|
||||||
copy.Call().Dispose();
|
f.Call().Dispose();
|
||||||
copy.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -288,8 +282,9 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
"The callback function will be called as func(Actor a, int id).")]
|
"The callback function will be called as func(Actor a, int id).")]
|
||||||
public int OnEnteredFootprint(CPos[] cells, LuaFunction func)
|
public int OnEnteredFootprint(CPos[] cells, LuaFunction func)
|
||||||
{
|
{
|
||||||
var triggerId = 0;
|
// We can't easily dispose onEntry, so we'll have to rely on finalization for it.
|
||||||
var onEntry = (LuaFunction)func.CopyReference();
|
var onEntry = (LuaFunction)func.CopyReference();
|
||||||
|
var triggerId = 0;
|
||||||
Action<Actor> invokeEntry = a =>
|
Action<Actor> invokeEntry = a =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -314,8 +309,9 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
"The callback function will be called as func(Actor a, int id).")]
|
"The callback function will be called as func(Actor a, int id).")]
|
||||||
public int OnExitedFootprint(CPos[] cells, LuaFunction func)
|
public int OnExitedFootprint(CPos[] cells, LuaFunction func)
|
||||||
{
|
{
|
||||||
var triggerId = 0;
|
// We can't easily dispose onExit, so we'll have to rely on finalization for it.
|
||||||
var onExit = (LuaFunction)func.CopyReference();
|
var onExit = (LuaFunction)func.CopyReference();
|
||||||
|
var triggerId = 0;
|
||||||
Action<Actor> invokeExit = a =>
|
Action<Actor> invokeExit = a =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -346,8 +342,9 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
"The callback function will be called as func(Actor a, int id).")]
|
"The callback function will be called as func(Actor a, int id).")]
|
||||||
public int OnEnteredProximityTrigger(WPos pos, WDist range, LuaFunction func)
|
public int OnEnteredProximityTrigger(WPos pos, WDist range, LuaFunction func)
|
||||||
{
|
{
|
||||||
var triggerId = 0;
|
// We can't easily dispose onEntry, so we'll have to rely on finalization for it.
|
||||||
var onEntry = (LuaFunction)func.CopyReference();
|
var onEntry = (LuaFunction)func.CopyReference();
|
||||||
|
var triggerId = 0;
|
||||||
Action<Actor> invokeEntry = a =>
|
Action<Actor> invokeEntry = a =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -372,8 +369,9 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
"The callback function will be called as func(Actor a, int id).")]
|
"The callback function will be called as func(Actor a, int id).")]
|
||||||
public int OnExitedProximityTrigger(WPos pos, WDist range, LuaFunction func)
|
public int OnExitedProximityTrigger(WPos pos, WDist range, LuaFunction func)
|
||||||
{
|
{
|
||||||
var triggerId = 0;
|
// We can't easily dispose onExit, so we'll have to rely on finalization for it.
|
||||||
var onExit = (LuaFunction)func.CopyReference();
|
var onExit = (LuaFunction)func.CopyReference();
|
||||||
|
var triggerId = 0;
|
||||||
Action<Actor> invokeExit = a =>
|
Action<Actor> invokeExit = a =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -33,14 +33,10 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
public bool Any(LuaValue[] collection, LuaFunction func)
|
public bool Any(LuaValue[] collection, LuaFunction func)
|
||||||
{
|
{
|
||||||
foreach (var c in collection)
|
foreach (var c in collection)
|
||||||
{
|
|
||||||
using (var ret = func.Call(c))
|
using (var ret = func.Call(c))
|
||||||
{
|
using (var result = ret.FirstOrDefault())
|
||||||
var result = ret.FirstOrDefault();
|
|
||||||
if (result != null && result.ToBoolean())
|
if (result != null && result.ToBoolean())
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -49,14 +45,10 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
public bool All(LuaValue[] collection, LuaFunction func)
|
public bool All(LuaValue[] collection, LuaFunction func)
|
||||||
{
|
{
|
||||||
foreach (var c in collection)
|
foreach (var c in collection)
|
||||||
{
|
|
||||||
using (var ret = func.Call(c))
|
using (var ret = func.Call(c))
|
||||||
{
|
using (var result = ret.FirstOrDefault())
|
||||||
var result = ret.FirstOrDefault();
|
|
||||||
if (result == null || !result.ToBoolean())
|
if (result == null || !result.ToBoolean())
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -64,7 +56,7 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
[Desc("Returns the first n values from a collection.")]
|
[Desc("Returns the first n values from a collection.")]
|
||||||
public LuaValue[] Take(int n, LuaValue[] source)
|
public LuaValue[] Take(int n, LuaValue[] source)
|
||||||
{
|
{
|
||||||
return source.Take(n).ToArray();
|
return source.Take(n).Select(v => v.CopyReference()).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Desc("Skips over the first numElements members of a table and return the rest.")]
|
[Desc("Skips over the first numElements members of a table and return the rest.")]
|
||||||
@@ -73,7 +65,8 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
var t = Context.CreateTable();
|
var t = Context.CreateTable();
|
||||||
|
|
||||||
for (var i = numElements; i <= table.Count; i++)
|
for (var i = numElements; i <= table.Count; i++)
|
||||||
t.Add(t.Count + 1, table[i]);
|
using (LuaValue key = t.Count + 1, value = table[i])
|
||||||
|
t.Add(key, value);
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
@@ -81,7 +74,7 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
[Desc("Returns a random value from a collection.")]
|
[Desc("Returns a random value from a collection.")]
|
||||||
public LuaValue Random(LuaValue[] collection)
|
public LuaValue Random(LuaValue[] collection)
|
||||||
{
|
{
|
||||||
return collection.Random(Context.World.SharedRandom);
|
return collection.Random(Context.World.SharedRandom).CopyReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Desc("Expands the given footprint one step along the coordinate axes, and (if requested) diagonals.")]
|
[Desc("Expands the given footprint one step along the coordinate axes, and (if requested) diagonals.")]
|
||||||
|
|||||||
@@ -28,8 +28,13 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
{
|
{
|
||||||
Actor actor;
|
Actor actor;
|
||||||
CPos cell;
|
CPos cell;
|
||||||
if (!kv.Key.TryGetClrValue<Actor>(out actor) || !kv.Value.TryGetClrValue<CPos>(out cell))
|
using (kv.Key)
|
||||||
throw new LuaException("Chronoshift requires a table of Actor,CPos pairs. Received {0},{1}".F(kv.Key.WrappedClrType().Name, kv.Value.WrappedClrType().Name));
|
using (kv.Value)
|
||||||
|
{
|
||||||
|
if (!kv.Key.TryGetClrValue(out actor) || !kv.Value.TryGetClrValue(out cell))
|
||||||
|
throw new LuaException("Chronoshift requires a table of Actor,CPos pairs. Received {0},{1}".F(
|
||||||
|
kv.Key.WrappedClrType().Name, kv.Value.WrappedClrType().Name));
|
||||||
|
}
|
||||||
|
|
||||||
var cs = actor.TraitOrDefault<Chronoshiftable>();
|
var cs = actor.TraitOrDefault<Chronoshiftable>();
|
||||||
if (cs != null && cs.CanChronoshiftTo(actor, cell))
|
if (cs != null && cs.CanChronoshiftTo(actor, cell))
|
||||||
|
|||||||
Reference in New Issue
Block a user