Update Lua bindings to use array arguments.

This commit is contained in:
Paul Chote
2014-10-04 11:14:14 +13:00
parent 471dc409b7
commit 85b26d1ff8
7 changed files with 70 additions and 164 deletions

View File

@@ -164,14 +164,5 @@ namespace OpenRA.Scripting
throw new InvalidOperationException("Cannot convert type '{0}' to Lua. Class must implement IScriptBindable.".F(obj.GetType())); throw new InvalidOperationException("Cannot convert type '{0}' to Lua. Class must implement IScriptBindable.".F(obj.GetType()));
} }
public static LuaTable ToLuaTable(this IEnumerable collection, ScriptContext context)
{
var i = 1;
var table = context.CreateTable();
foreach (var x in collection)
table.Add(i++, x.ToLuaValue(context));
return table;
}
} }
} }

View File

@@ -29,35 +29,37 @@ namespace OpenRA.Mods.RA.Scripting
} }
[Desc("Returns a table of all actors within the requested region, filtered using the specified function.")] [Desc("Returns a table of all actors within the requested region, filtered using the specified function.")]
public LuaTable ActorsInCircle(WPos location, WRange radius, LuaFunction filter = null) public Actor[] ActorsInCircle(WPos location, WRange radius, LuaFunction filter = null)
{ {
var actors = context.World.FindActorsInCircle(location, radius) var actors = context.World.FindActorsInCircle(location, radius);
.Select(a => a.ToLuaValue(context));
if (filter != null) if (filter != null)
{
actors = actors.Where(a => actors = actors.Where(a =>
{ {
using (var f = filter.Call(a)) using (var f = filter.Call(a.ToLuaValue(context)))
return f.First().ToBoolean(); return f.First().ToBoolean();
}); });
}
return actors.ToLuaTable(context); 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 LuaTable 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);
.Select(a => a.ToLuaValue(context));
if (filter != null) if (filter != null)
{
actors = actors.Where(a => actors = actors.Where(a =>
{ {
using (var f = filter.Call(a)) using (var f = filter.Call(a.ToLuaValue(context)))
return f.First().ToBoolean(); return f.First().ToBoolean();
}); });
}
return actors.ToLuaTable(context); return actors.ToArray();
} }
[Desc("Returns the location of the top-left corner of the map.")] [Desc("Returns the location of the top-left corner of the map.")]
@@ -91,13 +93,7 @@ namespace OpenRA.Mods.RA.Scripting
public string Difficulty { get { return context.World.LobbyInfo.GlobalSettings.Difficulty; } } public string Difficulty { get { return context.World.LobbyInfo.GlobalSettings.Difficulty; } }
[Desc("Returns a table of all the actors that were specified in the map file.")] [Desc("Returns a table of all the actors that were specified in the map file.")]
public LuaTable NamedActors public Actor[] NamedActors { get { return sma.Actors.Values.ToArray(); } }
{
get
{
return sma.Actors.Values.ToLuaTable(context);
}
}
[Desc("Returns the actor that was specified with a given name in " + [Desc("Returns the actor that was specified with a given name in " +
"the map file (or nil, if the actor is dead or not found).")] "the map file (or nil, if the actor is dead or not found).")]

View File

@@ -25,17 +25,14 @@ namespace OpenRA.Scripting
} }
[Desc("Returns a table of players filtered by the specified function.")] [Desc("Returns a table of players filtered by the specified function.")]
public LuaTable GetPlayers(LuaFunction filter) public Player[] GetPlayers(LuaFunction filter)
{ {
var players = context.World.Players return context.World.Players
.Select(p => p.ToLuaValue(context)) .Where(p =>
.Where(a =>
{ {
using (var f = filter.Call(a)) using (var f = filter.Call(p.ToLuaValue(context)))
return f.First().ToBoolean(); return f.First().ToBoolean();
}); }).ToArray();
return players.ToLuaTable(context);
} }
} }
} }

View File

@@ -72,51 +72,36 @@ namespace OpenRA.Mods.RA.Scripting
"while the last one will be their destination. If actionFunc is given, " + "while the last one will be their destination. If actionFunc is given, " +
"it will be executed once a unit has reached its destination. actionFunc " + "it will be executed once a unit has reached its destination. actionFunc " +
"will be called as actionFunc(Actor actor)")] "will be called as actionFunc(Actor actor)")]
public LuaTable Reinforce(Player owner, LuaTable actorTypes, LuaTable entryPath, int interval = 25, LuaFunction actionFunc = null) public Actor[] Reinforce(Player owner, string[] actorTypes, CPos[] entryPath, int interval = 25, LuaFunction actionFunc = null)
{ {
var actors = new List<Actor>(); var actors = new List<Actor>();
for (var i = 1; i <= actorTypes.Count; i++) for (var i = 0; i < actorTypes.Length; i++)
{ {
string actorType; var af = actionFunc != null ? actionFunc.CopyReference() as LuaFunction : null;
if (!(actorTypes[i].TryGetClrValue<String>(out actorType))) var actor = CreateActor(owner, actorTypes[i], false, entryPath[0], entryPath.Length > 1 ? entryPath[1] : (CPos?)null);
throw new LuaException("Invalid data in actorTypes array");
CPos entry, next = new CPos();
if (!(entryPath[1].TryGetClrValue<CPos>(out entry)
&& (entryPath.Count < 2 || entryPath[2].TryGetClrValue<CPos>(out next))))
throw new LuaException("Invalid data in entryPath array");
var actor = CreateActor(owner, actorType, false, entry, entryPath.Count > 1 ? next : (CPos?)null);
actors.Add(actor); actors.Add(actor);
var ep = entryPath.CopyReference() as LuaTable; var actionDelay = i * interval;
var af = actionFunc != null ? actionFunc.CopyReference() as LuaFunction : null;
var actionDelay = (i - 1) * interval;
Action actorAction = () => Action actorAction = () =>
{ {
context.World.Add(actor); context.World.Add(actor);
for (var j = 2; j <= ep.Count; j++) for (var j = 1; j < entryPath.Length; j++)
{ Move(actor, entryPath[j]);
CPos wpt;
if (!(ep[j].TryGetClrValue<CPos>(out wpt)))
throw new LuaException("Invalid data in entryPath array");
Move(actor, wpt);
}
ep.Dispose();
if (af != null) if (af != null)
{
actor.QueueActivity(new CallFunc(() => actor.QueueActivity(new CallFunc(() =>
{ {
af.Call(actor.ToLuaValue(context)); af.Call(actor.ToLuaValue(context));
af.Dispose(); af.Dispose();
})); }));
}
}; };
context.World.AddFrameEndTask(w => w.Add(new DelayedAction(actionDelay, actorAction))); context.World.AddFrameEndTask(w => w.Add(new DelayedAction(actionDelay, actorAction)));
} }
return actors.Select(a => a.ToLuaValue(context)).ToLuaTable(context);
return actors.ToArray();
} }
[Desc("Send reinforcements in a transport. A transport can be a ground unit (APC etc.), ships and aircraft. " + [Desc("Send reinforcements in a transport. A transport can be a ground unit (APC etc.), ships and aircraft. " +
@@ -127,48 +112,32 @@ namespace OpenRA.Mods.RA.Scripting
"been supplied. Afterwards, the transport will follow the exitPath and leave the map, " + "been supplied. Afterwards, the transport will follow the exitPath and leave the map, " +
"unless a custom exitFunc has been supplied. actionFunc will be called as " + "unless a custom exitFunc has been supplied. actionFunc will be called as " +
"actionFunc(Actor transport, Actor[] cargo). exitFunc will be called as exitFunc(Actor transport).")] "actionFunc(Actor transport, Actor[] cargo). exitFunc will be called as exitFunc(Actor transport).")]
public LuaTable ReinforceWithTransport(Player owner, string actorType, LuaTable cargoTypes, LuaTable entryPath, LuaTable exitPath = null, public LuaTable ReinforceWithTransport(Player owner, string actorType, string[] cargoTypes, CPos[] entryPath, CPos[] exitPath = null,
LuaFunction actionFunc = null, LuaFunction exitFunc = null) LuaFunction actionFunc = null, LuaFunction exitFunc = null)
{ {
CPos entry, next = new CPos(); var transport = CreateActor(owner, actorType, true, entryPath[0], entryPath.Length > 1 ? entryPath[1] : (CPos?)null);
if (!(entryPath[1].TryGetClrValue<CPos>(out entry)
&& (entryPath.Count < 2 || entryPath[2].TryGetClrValue<CPos>(out next))))
throw new LuaException("Invalid data in entryPath array");
var transport = CreateActor(owner, actorType, true, entry, entryPath.Count > 1 ? next : (CPos?)null);
var cargo = transport.TraitOrDefault<Cargo>(); var cargo = transport.TraitOrDefault<Cargo>();
var passengers = context.CreateTable(); var passengers = new List<Actor>();
if (cargo != null && cargoTypes != null) if (cargo != null && cargoTypes != null)
{ {
for (var i = 1; i <= cargoTypes.Count; i++) foreach (var cargoType in cargoTypes)
{ {
string cargoType;
if (!(cargoTypes [i].TryGetClrValue<String>(out cargoType)))
throw new LuaException("Invalid data in cargoTypes array");
var passenger = CreateActor(owner, cargoType, false); var passenger = CreateActor(owner, cargoType, false);
passengers.Add(passengers.Count + 1, passenger.ToLuaValue(context)); passengers.Add(passenger);
cargo.Load(transport, passenger); cargo.Load(transport, passenger);
} }
} }
for (var i = 2; i <= entryPath.Count; i++) for (var i = 1; i < entryPath.Length; i++)
{ Move(transport, entryPath[i]);
CPos wpt;
if (!(entryPath[i].TryGetClrValue<CPos>(out wpt)))
throw new LuaException("Invalid data in entryPath array");
Move(transport, wpt);
}
if (actionFunc != null) if (actionFunc != null)
{ {
var af = actionFunc.CopyReference() as LuaFunction; var af = actionFunc.CopyReference() as LuaFunction;
transport.QueueActivity(new CallFunc(() => transport.QueueActivity(new CallFunc(() =>
{ {
af.Call(transport.ToLuaValue(context), passengers); af.Call(transport.ToLuaValue(context), passengers.ToArray().ToLuaValue(context));
af.Dispose(); af.Dispose();
})); }));
} }
@@ -181,11 +150,13 @@ namespace OpenRA.Mods.RA.Scripting
transport.QueueActivity(new HeliLand(true)); transport.QueueActivity(new HeliLand(true));
transport.QueueActivity(new Wait(15)); transport.QueueActivity(new Wait(15));
} }
if (cargo != null) if (cargo != null)
{ {
transport.QueueActivity(new UnloadCargo(transport, true)); transport.QueueActivity(new UnloadCargo(transport, true));
transport.QueueActivity(new WaitFor(() => cargo.IsEmpty(transport))); transport.QueueActivity(new WaitFor(() => cargo.IsEmpty(transport)));
} }
transport.QueueActivity(new Wait(heli != null ? 50 : 25)); transport.QueueActivity(new Wait(heli != null ? 50 : 25));
} }
@@ -200,20 +171,15 @@ namespace OpenRA.Mods.RA.Scripting
} }
else if (exitPath != null) else if (exitPath != null)
{ {
for (var i = 1; i <= exitPath.Count; i++) foreach (var wpt in exitPath)
{
CPos wpt;
if (!(exitPath[i].TryGetClrValue<CPos>(out wpt)))
throw new LuaException("Invalid data in exitPath array.");
Move(transport, wpt); Move(transport, wpt);
}
transport.QueueActivity(new RemoveSelf()); transport.QueueActivity(new RemoveSelf());
} }
var ret = context.CreateTable(); var ret = context.CreateTable();
ret.Add(1, transport.ToLuaValue(context)); ret.Add(1, transport.ToLuaValue(context));
ret.Add(2, passengers); ret.Add(2, passengers.ToArray().ToLuaValue(context));
return ret; return ret;
} }
} }

View File

@@ -75,18 +75,9 @@ namespace OpenRA.Mods.RA.Scripting
[Desc("Call a function when all of the actors in a group are killed. The callback " + [Desc("Call a function when all of the actors in a group are killed. The callback " +
"function will be called as func().")] "function will be called as func().")]
public void OnAllKilled(LuaTable actors, LuaFunction func) public void OnAllKilled(Actor[] actors, LuaFunction func)
{ {
var group = new List<Actor>(); var group = actors.ToList();
foreach (var kv in actors)
{
Actor actor;
if (!kv.Value.TryGetClrValue<Actor>(out actor))
throw new LuaException("OnAllKilled requires a table of int,Actor pairs. Recieved {0},{1}".F(kv.Key.GetType().Name, kv.Value.GetType().Name));
group.Add(actor);
}
var copy = (LuaFunction)func.CopyReference(); var copy = (LuaFunction)func.CopyReference();
Action<Actor> OnMemberKilled = m => Action<Actor> OnMemberKilled = m =>
{ {
@@ -104,18 +95,8 @@ namespace OpenRA.Mods.RA.Scripting
[Desc("Call a function when one of the actors in a group is killed. The callback " + [Desc("Call a function when one of the actors in a group is killed. The callback " +
"function will be called as func(Actor killed).")] "function will be called as func(Actor killed).")]
public void OnAnyKilled(LuaTable actors, LuaFunction func) public void OnAnyKilled(Actor[] actors, LuaFunction func)
{ {
var group = new List<Actor>();
foreach (var kv in actors)
{
Actor actor;
if (!kv.Value.TryGetClrValue<Actor>(out actor))
throw new LuaException("OnAnyKilled requires a table of int,Actor pairs. Recieved {0},{1}".F(kv.Key.GetType().Name, kv.Value.GetType().Name));
group.Add(actor);
}
var called = false; var called = false;
var copy = (LuaFunction)func.CopyReference(); var copy = (LuaFunction)func.CopyReference();
Action<Actor> OnMemberKilled = m => Action<Actor> OnMemberKilled = m =>
@@ -130,7 +111,7 @@ namespace OpenRA.Mods.RA.Scripting
called = true; called = true;
}; };
foreach (var a in group) foreach (var a in actors)
GetScriptTriggers(a).OnKilledInternal += OnMemberKilled; GetScriptTriggers(a).OnKilledInternal += OnMemberKilled;
} }
@@ -197,25 +178,10 @@ namespace OpenRA.Mods.RA.Scripting
GetScriptTriggers(a).RegisterCallback(Trigger.OnCapture, func, context); GetScriptTriggers(a).RegisterCallback(Trigger.OnCapture, func, context);
} }
static CPos[] MakeCellFootprint(LuaTable table)
{
var cells = new List<CPos>();
foreach (var kv in table)
{
CPos cell;
if (!kv.Value.TryGetClrValue<CPos>(out cell))
throw new LuaException("Cell footprints must be specified as a table of int,Cell pairs. Recieved {0},{1}".F(kv.Key.GetType().Name, kv.Value.GetType().Name));
cells.Add(cell);
}
return cells.ToArray();
}
[Desc("Call a function when a ground-based actor enters this cell footprint." + [Desc("Call a function when a ground-based actor enters this cell footprint." +
"Returns the trigger id for later removal using RemoveFootprintTrigger(int id)." + "Returns the trigger id for later removal using RemoveFootprintTrigger(int id)." +
"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(LuaTable cells, LuaFunction func) public int OnEnteredFootprint(CPos[] cells, LuaFunction func)
{ {
var triggerId = 0; var triggerId = 0;
var onEntry = (LuaFunction)func.CopyReference(); var onEntry = (LuaFunction)func.CopyReference();
@@ -226,7 +192,7 @@ namespace OpenRA.Mods.RA.Scripting
onEntry.Call(luaActor, id).Dispose(); onEntry.Call(luaActor, id).Dispose();
}; };
triggerId = context.World.ActorMap.AddCellTrigger(MakeCellFootprint(cells), invokeEntry, null); triggerId = context.World.ActorMap.AddCellTrigger(cells, invokeEntry, null);
return triggerId; return triggerId;
} }
@@ -234,7 +200,7 @@ namespace OpenRA.Mods.RA.Scripting
[Desc("Call a function when a ground-based actor leaves this cell footprint." + [Desc("Call a function when a ground-based actor leaves this cell footprint." +
"Returns the trigger id for later removal using RemoveFootprintTrigger(int id)." + "Returns the trigger id for later removal using RemoveFootprintTrigger(int id)." +
"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(LuaTable cells, LuaFunction func) public int OnExitedFootprint(CPos[] cells, LuaFunction func)
{ {
var triggerId = 0; var triggerId = 0;
var onExit = (LuaFunction)func.CopyReference(); var onExit = (LuaFunction)func.CopyReference();
@@ -245,7 +211,7 @@ namespace OpenRA.Mods.RA.Scripting
onExit.Call(luaActor, id).Dispose(); onExit.Call(luaActor, id).Dispose();
}; };
triggerId = context.World.ActorMap.AddCellTrigger(MakeCellFootprint(cells), null, invokeExit); triggerId = context.World.ActorMap.AddCellTrigger(cells, null, invokeExit);
return triggerId; return triggerId;
} }

View File

@@ -19,19 +19,19 @@ namespace OpenRA.Mods.RA.Scripting
{ {
public UtilsGlobal(ScriptContext context) : base(context) { } public UtilsGlobal(ScriptContext context) : base(context) { }
[Desc("Calls a function on every value in table.")] [Desc("Calls a function on every element in a collection.")]
public void Do(LuaTable table, LuaFunction func) public void Do(LuaValue[] collection, LuaFunction func)
{ {
foreach (var kv in table) foreach (var c in collection)
func.Call(kv.Value).Dispose(); func.Call(c).Dispose();
} }
[Desc("Returns true if func returns true for any value in table.")] [Desc("Returns true if func returns true for any element in a collection.")]
public bool Any(LuaTable table, LuaFunction func) public bool Any(LuaValue[] collection, LuaFunction func)
{ {
foreach (var kv in table) foreach (var c in collection)
{ {
using (var ret = func.Call(kv.Value)) using (var ret = func.Call(c))
{ {
var result = ret.FirstOrDefault(); var result = ret.FirstOrDefault();
if (result != null && result.ToBoolean()) if (result != null && result.ToBoolean())
@@ -42,12 +42,12 @@ namespace OpenRA.Mods.RA.Scripting
return false; return false;
} }
[Desc("Returns true if func returns true for all values in table.")] [Desc("Returns true if func returns true for all elements in a collection.")]
public bool All(LuaTable table, LuaFunction func) public bool All(LuaValue[] collection, LuaFunction func)
{ {
foreach (var kv in table) foreach (var c in collection)
{ {
using (var ret = func.Call(kv.Value)) using (var ret = func.Call(c))
{ {
var result = ret.FirstOrDefault(); var result = ret.FirstOrDefault();
if (result == null || !result.ToBoolean()) if (result == null || !result.ToBoolean())
@@ -58,7 +58,7 @@ namespace OpenRA.Mods.RA.Scripting
return true; return true;
} }
[Desc("Skips over the first numElements members of the array and returns the rest.")] [Desc("Skips over the first numElements members of a table and return the rest.")]
public LuaTable Skip(LuaTable table, int numElements) public LuaTable Skip(LuaTable table, int numElements)
{ {
var t = context.CreateTable(); var t = context.CreateTable();
@@ -69,26 +69,16 @@ namespace OpenRA.Mods.RA.Scripting
return t; return t;
} }
[Desc("Returns a random value from table.")] [Desc("Returns a random value from a collection.")]
public LuaValue Random(LuaTable table) public LuaValue Random(LuaValue[] collection)
{ {
return table.Values.Random<LuaValue>(context.World.SharedRandom); return collection.Random(context.World.SharedRandom);
} }
[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.")]
public LuaTable ExpandFootprint(LuaTable cells, bool allowDiagonal) public CPos[] ExpandFootprint(CPos[] footprint, bool allowDiagonal)
{ {
var footprint = cells.Values.Select(c => return Traits.Util.ExpandFootprint(footprint, allowDiagonal).ToArray();
{
CPos cell;
if (!c.TryGetClrValue<CPos>(out cell))
throw new LuaException("ExpandFootprint only accepts a table of CPos");
return cell;
});
var expanded = Traits.Util.ExpandFootprint(footprint, allowDiagonal);
return expanded.ToLuaTable(context);
} }
[Desc("Returns a random integer x in the range low &lt;= x &lt; high.")] [Desc("Returns a random integer x in the range low &lt;= x &lt; high.")]

View File

@@ -26,11 +26,11 @@ namespace OpenRA.Mods.RA.Scripting
public string Name { get { return player.PlayerName; } } public string Name { get { return player.PlayerName; } }
[Desc("Returns an array of actors representing all ground attack units of this player.")] [Desc("Returns an array of actors representing all ground attack units of this player.")]
public LuaTable GetGroundAttackers() public Actor[] GetGroundAttackers()
{ {
return player.World.ActorsWithTrait<AttackBase>().Select(a => a.Actor) return player.World.ActorsWithTrait<AttackBase>().Select(a => a.Actor)
.Where(a => a.Owner == player && !a.IsDead() && a.IsInWorld && a.HasTrait<Mobile>()) .Where(a => a.Owner == player && !a.IsDead() && a.IsInWorld && a.HasTrait<Mobile>())
.Select(a => a.ToLuaValue(context)).ToLuaTable(context); .ToArray();
} }
} }
} }