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
|
||||
{
|
||||
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 names = type.GetCustomAttributes<ScriptGlobalAttribute>(true);
|
||||
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;
|
||||
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
|
||||
|
||||
@@ -43,6 +43,9 @@ namespace OpenRA.Scripting
|
||||
}
|
||||
|
||||
LuaValue Invoke(LuaVararg args)
|
||||
{
|
||||
object[] clrArgs = null;
|
||||
try
|
||||
{
|
||||
if (!IsMethod)
|
||||
throw new LuaException("Trying to invoke a ScriptMemberWrapper that isn't a method!");
|
||||
@@ -50,7 +53,8 @@ namespace OpenRA.Scripting
|
||||
var mi = (MethodInfo)Member;
|
||||
var pi = mi.GetParameters();
|
||||
|
||||
var clrArgs = new object[pi.Length];
|
||||
clrArgs = new object[pi.Length];
|
||||
|
||||
var argCount = args.Count;
|
||||
for (var i = 0; i < pi.Length; i++)
|
||||
{
|
||||
@@ -67,8 +71,27 @@ namespace OpenRA.Scripting
|
||||
throw new LuaException("Unable to convert parameter {0} to {1}".F(i, pi[i].ParameterType.Name));
|
||||
}
|
||||
|
||||
var ret = mi.Invoke(Target, clrArgs);
|
||||
return ret.ToLuaValue(context);
|
||||
return mi.Invoke(Target, clrArgs).ToLuaValue(context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Clean up all the Lua arguments that were given to us.
|
||||
foreach (var arg in args)
|
||||
arg.Dispose();
|
||||
args.Dispose();
|
||||
|
||||
// If we created any arrays of LuaValues to pass around, we need to dispose those too.
|
||||
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)
|
||||
@@ -77,10 +100,7 @@ namespace OpenRA.Scripting
|
||||
return runtime.CreateFunctionFromDelegate((Func<LuaVararg, LuaValue>)Invoke);
|
||||
|
||||
if (IsGetProperty)
|
||||
{
|
||||
var pi = Member as PropertyInfo;
|
||||
return pi.GetValue(Target, null).ToLuaValue(context);
|
||||
}
|
||||
return ((PropertyInfo)Member).GetValue(Target, null).ToLuaValue(context);
|
||||
|
||||
throw new LuaException("The property '{0}' is write-only".F(Member.Name));
|
||||
}
|
||||
@@ -89,7 +109,7 @@ namespace OpenRA.Scripting
|
||||
{
|
||||
if (IsSetProperty)
|
||||
{
|
||||
var pi = Member as PropertyInfo;
|
||||
var pi = (PropertyInfo)Member;
|
||||
object 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));
|
||||
|
||||
@@ -106,15 +106,24 @@ namespace OpenRA.Scripting
|
||||
var i = 0;
|
||||
|
||||
foreach (var kv in table)
|
||||
{
|
||||
using (kv.Key)
|
||||
{
|
||||
object element;
|
||||
if (innerType == typeof(LuaValue))
|
||||
element = kv.Value;
|
||||
else if (!kv.Value.TryGetClrValue(innerType, out element))
|
||||
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++);
|
||||
}
|
||||
}
|
||||
|
||||
clrObject = array;
|
||||
return true;
|
||||
@@ -159,11 +168,13 @@ namespace OpenRA.Scripting
|
||||
|
||||
if (obj is Array)
|
||||
{
|
||||
var array = obj as Array;
|
||||
var array = (Array)obj;
|
||||
var i = 1;
|
||||
var table = context.CreateTable();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
// Convert table entries into ActorInits
|
||||
foreach (var kv in initTable)
|
||||
{
|
||||
using (kv.Key)
|
||||
using (kv.Value)
|
||||
{
|
||||
// Find the requested type
|
||||
var typeName = kv.Key.ToString();
|
||||
@@ -50,6 +53,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
var test = initType.GetConstructor(new[] { innerType }).Invoke(new[] { value });
|
||||
initDict.Add(test);
|
||||
}
|
||||
}
|
||||
|
||||
// The actor must be added to the world at the end of the tick
|
||||
var a = Context.World.CreateActor(false, type, initDict);
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Eluant;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
@@ -34,34 +33,14 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
public Actor[] ActorsInCircle(WPos location, WDist radius, LuaFunction filter = null)
|
||||
{
|
||||
var actors = Context.World.FindActorsInCircle(location, radius);
|
||||
|
||||
if (filter != null)
|
||||
{
|
||||
actors = actors.Where(a =>
|
||||
{
|
||||
using (var f = filter.Call(a.ToLuaValue(Context)))
|
||||
return f.First().ToBoolean();
|
||||
});
|
||||
}
|
||||
|
||||
return actors.ToArray();
|
||||
return FilteredObjects(actors, filter).ToArray();
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
var actors = Context.World.ActorMap.ActorsInBox(topLeft, bottomRight);
|
||||
|
||||
if (filter != null)
|
||||
{
|
||||
actors = actors.Where(a =>
|
||||
{
|
||||
using (var f = filter.Call(a.ToLuaValue(Context)))
|
||||
return f.First().ToBoolean();
|
||||
});
|
||||
}
|
||||
|
||||
return actors.ToArray();
|
||||
return FilteredObjects(actors, filter).ToArray();
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
Action onComplete;
|
||||
[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)
|
||||
{
|
||||
@@ -65,8 +64,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
if (func != null)
|
||||
{
|
||||
var f = func.CopyReference() as LuaFunction;
|
||||
onComplete = () =>
|
||||
var f = (LuaFunction)func.CopyReference();
|
||||
Action onComplete = () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -113,13 +112,13 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
playlist.Stop();
|
||||
}
|
||||
|
||||
Action onCompleteFullscreen;
|
||||
[Desc("Play a VQA video fullscreen. File name has to include the file extension.")]
|
||||
public void PlayMovieFullscreen(string movie, LuaFunction func = null)
|
||||
{
|
||||
Action onCompleteFullscreen;
|
||||
if (func != null)
|
||||
{
|
||||
var f = func.CopyReference() as LuaFunction;
|
||||
var f = (LuaFunction)func.CopyReference();
|
||||
onCompleteFullscreen = () =>
|
||||
{
|
||||
try
|
||||
@@ -139,15 +138,14 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
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. " +
|
||||
"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)
|
||||
{
|
||||
Action onCompleteRadar;
|
||||
if (playComplete != null)
|
||||
{
|
||||
var f = playComplete.CopyReference() as LuaFunction;
|
||||
var f = (LuaFunction)playComplete.CopyReference();
|
||||
onCompleteRadar = () =>
|
||||
{
|
||||
try
|
||||
@@ -178,7 +176,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
AsyncLoader l = new AsyncLoader(Media.LoadVqa);
|
||||
IAsyncResult ar = l.BeginInvoke(s, null, null);
|
||||
onLoadComplete = () =>
|
||||
Action onLoadComplete = () =>
|
||||
{
|
||||
Media.StopFMVInRadar();
|
||||
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.")]
|
||||
public Player[] GetPlayers(LuaFunction filter)
|
||||
{
|
||||
return Context.World.Players
|
||||
.Where(p =>
|
||||
{
|
||||
using (var f = filter.Call(p.ToLuaValue(Context)))
|
||||
return f.First().ToBoolean();
|
||||
}).ToArray();
|
||||
return FilteredObjects(Context.World.Players, filter).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
var actors = new List<Actor>();
|
||||
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);
|
||||
actors.Add(actor);
|
||||
|
||||
@@ -86,8 +86,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
{
|
||||
actor.QueueActivity(new CallFunc(() =>
|
||||
{
|
||||
af.Call(actor.ToLuaValue(Context));
|
||||
af.Dispose();
|
||||
using (af)
|
||||
using (var a = actor.ToLuaValue(Context))
|
||||
af.Call(a);
|
||||
}));
|
||||
}
|
||||
};
|
||||
@@ -128,11 +129,12 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
if (actionFunc != null)
|
||||
{
|
||||
var af = actionFunc.CopyReference() as LuaFunction;
|
||||
var af = (LuaFunction)actionFunc.CopyReference();
|
||||
transport.QueueActivity(new CallFunc(() =>
|
||||
{
|
||||
af.Call(transport.ToLuaValue(Context), passengers.ToArray().ToLuaValue(Context));
|
||||
af.Dispose();
|
||||
using (af)
|
||||
using (LuaValue t = transport.ToLuaValue(Context), p = passengers.ToArray().ToLuaValue(Context))
|
||||
af.Call(t, p);
|
||||
}));
|
||||
}
|
||||
else
|
||||
@@ -164,11 +166,12 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
if (exitFunc != null)
|
||||
{
|
||||
var ef = exitFunc.CopyReference() as LuaFunction;
|
||||
var ef = (LuaFunction)exitFunc.CopyReference();
|
||||
transport.QueueActivity(new CallFunc(() =>
|
||||
{
|
||||
ef.Call(transport.ToLuaValue(Context));
|
||||
ef.Dispose();
|
||||
using (ef)
|
||||
using (var t = transport.ToLuaValue(Context))
|
||||
ef.Call(t);
|
||||
}));
|
||||
}
|
||||
else if (exitPath != null)
|
||||
@@ -180,8 +183,16 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
var ret = Context.CreateTable();
|
||||
ret.Add(1, transport.ToLuaValue(Context));
|
||||
ret.Add(2, passengers.ToArray().ToLuaValue(Context));
|
||||
using (LuaValue
|
||||
tKey = 1,
|
||||
tValue = transport.ToLuaValue(Context),
|
||||
pKey = 2,
|
||||
pValue = passengers.ToArray().ToLuaValue(Context))
|
||||
{
|
||||
ret.Add(tKey, tValue);
|
||||
ret.Add(pKey, pValue);
|
||||
}
|
||||
|
||||
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().")]
|
||||
public void AfterDelay(int delay, LuaFunction func)
|
||||
{
|
||||
var f = func.CopyReference() as LuaFunction;
|
||||
|
||||
var f = (LuaFunction)func.CopyReference();
|
||||
Action doCall = () =>
|
||||
{
|
||||
try
|
||||
@@ -78,17 +77,15 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
public void OnAllKilled(Actor[] actors, LuaFunction func)
|
||||
{
|
||||
var group = actors.ToList();
|
||||
var copy = (LuaFunction)func.CopyReference();
|
||||
var f = (LuaFunction)func.CopyReference();
|
||||
Action<Actor> onMemberKilled = m =>
|
||||
{
|
||||
try
|
||||
{
|
||||
group.Remove(m);
|
||||
if (!group.Any())
|
||||
{
|
||||
copy.Call();
|
||||
copy.Dispose();
|
||||
}
|
||||
using (f)
|
||||
f.Call();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -105,7 +102,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
public void OnAnyKilled(Actor[] actors, LuaFunction func)
|
||||
{
|
||||
var called = false;
|
||||
var copy = (LuaFunction)func.CopyReference();
|
||||
var f = (LuaFunction)func.CopyReference();
|
||||
Action<Actor> onMemberKilled = m =>
|
||||
{
|
||||
try
|
||||
@@ -113,10 +110,10 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
if (called)
|
||||
return;
|
||||
|
||||
using (f)
|
||||
using (var killed = m.ToLuaValue(Context))
|
||||
copy.Call(killed).Dispose();
|
||||
f.Call(killed).Dispose();
|
||||
|
||||
copy.Dispose();
|
||||
called = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -191,7 +188,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
{
|
||||
var group = actors.ToList();
|
||||
|
||||
var copy = (LuaFunction)func.CopyReference();
|
||||
var f = (LuaFunction)func.CopyReference();
|
||||
Action<Actor> onMemberRemoved = m =>
|
||||
{
|
||||
try
|
||||
@@ -200,10 +197,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
return;
|
||||
|
||||
if (!group.Any())
|
||||
{
|
||||
copy.Call().Dispose();
|
||||
copy.Dispose();
|
||||
}
|
||||
using (f)
|
||||
f.Call().Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -228,7 +223,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
{
|
||||
var called = false;
|
||||
|
||||
var copy = (LuaFunction)func.CopyReference();
|
||||
var f = (LuaFunction)func.CopyReference();
|
||||
Action<Actor> onKilledOrCaptured = m =>
|
||||
{
|
||||
try
|
||||
@@ -236,8 +231,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
if (called)
|
||||
return;
|
||||
|
||||
copy.Call().Dispose();
|
||||
copy.Dispose();
|
||||
using (f)
|
||||
f.Call().Dispose();
|
||||
|
||||
called = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -256,7 +252,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
{
|
||||
var group = actors.ToList();
|
||||
|
||||
var copy = (LuaFunction)func.CopyReference();
|
||||
var f = (LuaFunction)func.CopyReference();
|
||||
Action<Actor> onMemberKilledOrCaptured = m =>
|
||||
{
|
||||
try
|
||||
@@ -265,10 +261,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
return;
|
||||
|
||||
if (!group.Any())
|
||||
{
|
||||
copy.Call().Dispose();
|
||||
copy.Dispose();
|
||||
}
|
||||
using (f)
|
||||
f.Call().Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -288,8 +282,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
"The callback function will be called as func(Actor a, int id).")]
|
||||
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 triggerId = 0;
|
||||
Action<Actor> invokeEntry = a =>
|
||||
{
|
||||
try
|
||||
@@ -314,8 +309,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
"The callback function will be called as func(Actor a, int id).")]
|
||||
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 triggerId = 0;
|
||||
Action<Actor> invokeExit = a =>
|
||||
{
|
||||
try
|
||||
@@ -346,8 +342,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
"The callback function will be called as func(Actor a, int id).")]
|
||||
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 triggerId = 0;
|
||||
Action<Actor> invokeEntry = a =>
|
||||
{
|
||||
try
|
||||
@@ -372,8 +369,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
"The callback function will be called as func(Actor a, int id).")]
|
||||
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 triggerId = 0;
|
||||
Action<Actor> invokeExit = a =>
|
||||
{
|
||||
try
|
||||
|
||||
@@ -33,14 +33,10 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
public bool Any(LuaValue[] collection, LuaFunction func)
|
||||
{
|
||||
foreach (var c in collection)
|
||||
{
|
||||
using (var ret = func.Call(c))
|
||||
{
|
||||
var result = ret.FirstOrDefault();
|
||||
using (var result = ret.FirstOrDefault())
|
||||
if (result != null && result.ToBoolean())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -49,14 +45,10 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
public bool All(LuaValue[] collection, LuaFunction func)
|
||||
{
|
||||
foreach (var c in collection)
|
||||
{
|
||||
using (var ret = func.Call(c))
|
||||
{
|
||||
var result = ret.FirstOrDefault();
|
||||
using (var result = ret.FirstOrDefault())
|
||||
if (result == null || !result.ToBoolean())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -64,7 +56,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
[Desc("Returns the first n values from a collection.")]
|
||||
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.")]
|
||||
@@ -73,7 +65,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
var t = Context.CreateTable();
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -81,7 +74,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
[Desc("Returns a random value from a 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.")]
|
||||
|
||||
@@ -28,8 +28,13 @@ namespace OpenRA.Mods.RA.Scripting
|
||||
{
|
||||
Actor actor;
|
||||
CPos cell;
|
||||
if (!kv.Key.TryGetClrValue<Actor>(out actor) || !kv.Value.TryGetClrValue<CPos>(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));
|
||||
using (kv.Key)
|
||||
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>();
|
||||
if (cs != null && cs.CanChronoshiftTo(actor, cell))
|
||||
|
||||
Reference in New Issue
Block a user