Improve Lua type documentation and bindings.
The ExtractEmmyLuaAPI utility command, invoked with `--emmy-lua-api`, produces a documentation file that is used by the [OpenRA Lua Language Extension](https://marketplace.visualstudio.com/items?itemName=openra.vscode-openra-lua) to provide documentation and type information is VSCode and VSCode compatible editors when editing the Lua scripts. We improve the documentation and types produced by this utility in a few ways: - Require descriptions to be provided for all items. - Fix the type definitions of the base engine types (cpos, wpos, wangle, wdist, wvec, cvec) to match with the actual bindings on the C# side. Add some extra bindings for these types to increase their utility. - Introduce ScriptEmmyTypeOverrideAttribute to allow the C# side of the bindings to provide a more specific type. The utility command now requires this to be used to avoid accidentally exporting poor type information. - Fix a handful of scripts where the new type information revealed warnings. The ability to ScriptEmmyTypeOverrideAttribute allows parameters and return types to provide a more specific type compared to the previous, weak, type definition. For example LuaValue mapped to `any`, LuaTable mapped to `table`, and LuaFunction mapped to `function`. These types are all non-specific. `any` can be anything, `table` is a table without known types for its keys or values, `function` is a function with an unknown signature. Now, we can provide specific types. , e.g. instead of `table`, ReinforcementsGlobal.ReinforceWithTransport is able to specify `{ [1]: actor, [2]: actor[] }` - a table with keys 1 and 2, whose values are an actor, and a table of actors respectively. The callback functions in MapGlobal now have signatures, e.g. instead of `function` we have `fun(a: actor):boolean`. In UtilsGlobal, we also make use of generic types. These work in a similar fashion to generics in C#. These methods operate on collections, we can introduce a generic parameter named `T` for the type of the items in those collections. Now the return type and callback parameters can also use that generic type. This means the return type or callback functions operate on the same type as whatever type is in the collection you pass in. e.g. Utils.Do accepts a collection typed as `T[]` with a callback function invoked on each item typed as `fun(item: T)`. If you pass in actors, the callback operates on an actor. If you pass in strings, the callback operates on a string, etc. Overall, these changes should result in an improved user experience for those editing OpenRA Lua scripts in a compatible IDE.
This commit is contained in:
@@ -16,7 +16,8 @@ using OpenRA.Scripting;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public readonly struct CPos : IScriptBindable, ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, ILuaTableBinding, IEquatable<CPos>
|
||||
public readonly struct CPos : IEquatable<CPos>, IScriptBindable,
|
||||
ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, ILuaTableBinding, ILuaToStringBinding
|
||||
{
|
||||
// Coordinates are packed in a 32 bit signed int
|
||||
// X and Y are 12 bits (signed): -2048...2047
|
||||
@@ -96,7 +97,8 @@ namespace OpenRA
|
||||
public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out CPos a) || !right.TryGetClrValue(out CVec b))
|
||||
throw new LuaException($"Attempted to call CPos.Add(CPos, CVec) with invalid arguments ({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
throw new LuaException("Attempted to call CPos.Add(CPos, CVec) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
|
||||
return new LuaCustomClrObject(a + b);
|
||||
}
|
||||
@@ -105,7 +107,8 @@ namespace OpenRA
|
||||
{
|
||||
var rightType = right.WrappedClrType();
|
||||
if (!left.TryGetClrValue(out CPos a))
|
||||
throw new LuaException($"Attempted to call CPos.Subtract(CPos, (CPos|CVec)) with invalid arguments ({left.WrappedClrType().Name}, {rightType.Name})");
|
||||
throw new LuaException("Attempted to call CPos.Subtract(CPos, (CPos|CVec)) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {rightType.Name})");
|
||||
|
||||
if (rightType == typeof(CPos))
|
||||
{
|
||||
@@ -118,7 +121,8 @@ namespace OpenRA
|
||||
return new LuaCustomClrObject(a - b);
|
||||
}
|
||||
|
||||
throw new LuaException($"Attempted to call CPos.Subtract(CPos, (CPos|CVec)) with invalid arguments ({left.WrappedClrType().Name}, {rightType.Name})");
|
||||
throw new LuaException("Attempted to call CPos.Subtract(CPos, (CPos|CVec)) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {rightType.Name})");
|
||||
}
|
||||
|
||||
public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
@@ -145,6 +149,8 @@ namespace OpenRA
|
||||
set => throw new LuaException("CPos is read-only. Use CPos.New to create a new value");
|
||||
}
|
||||
|
||||
public LuaValue ToString(LuaRuntime runtime) => ToString();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,9 @@ using OpenRA.Scripting;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public readonly struct CVec : IScriptBindable,
|
||||
ILuaAdditionBinding, ILuaSubtractionBinding, ILuaUnaryMinusBinding, ILuaEqualityBinding, ILuaTableBinding, IEquatable<CVec>
|
||||
public readonly struct CVec : IEquatable<CVec>, IScriptBindable,
|
||||
ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, ILuaUnaryMinusBinding,
|
||||
ILuaMultiplicationBinding, ILuaDivisionBinding, ILuaTableBinding, ILuaToStringBinding
|
||||
{
|
||||
public readonly int X, Y;
|
||||
|
||||
@@ -77,7 +78,8 @@ namespace OpenRA
|
||||
public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out CVec a) || !right.TryGetClrValue(out CVec b))
|
||||
throw new LuaException($"Attempted to call CVec.Add(CVec, CVec) with invalid arguments ({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
throw new LuaException("Attempted to call CVec.Add(CVec, CVec) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
|
||||
return new LuaCustomClrObject(a + b);
|
||||
}
|
||||
@@ -85,16 +87,12 @@ namespace OpenRA
|
||||
public LuaValue Subtract(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out CVec a) || !right.TryGetClrValue(out CVec b))
|
||||
throw new LuaException($"Attempted to call CVec.Subtract(CVec, CVec) with invalid arguments ({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
throw new LuaException("Attempted to call CVec.Subtract(CVec, CVec) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
|
||||
return new LuaCustomClrObject(a - b);
|
||||
}
|
||||
|
||||
public LuaValue Minus(LuaRuntime runtime)
|
||||
{
|
||||
return new LuaCustomClrObject(-this);
|
||||
}
|
||||
|
||||
public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out CVec a) || !right.TryGetClrValue(out CVec b))
|
||||
@@ -103,6 +101,29 @@ namespace OpenRA
|
||||
return a == b;
|
||||
}
|
||||
|
||||
public LuaValue Minus(LuaRuntime runtime)
|
||||
{
|
||||
return new LuaCustomClrObject(-this);
|
||||
}
|
||||
|
||||
public LuaValue Multiply(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out CVec a) || !right.TryGetClrValue(out int b))
|
||||
throw new LuaException("Attempted to call CVec.Multiply(CVec, integer) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
|
||||
return new LuaCustomClrObject(a * b);
|
||||
}
|
||||
|
||||
public LuaValue Divide(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out CVec a) || !right.TryGetClrValue(out int b))
|
||||
throw new LuaException("Attempted to call CVec.Multiply(CVec, integer) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
|
||||
return new LuaCustomClrObject(a / b);
|
||||
}
|
||||
|
||||
public LuaValue this[LuaRuntime runtime, LuaValue key]
|
||||
{
|
||||
get
|
||||
@@ -111,6 +132,7 @@ namespace OpenRA
|
||||
{
|
||||
case "X": return X;
|
||||
case "Y": return Y;
|
||||
case "Length": return Length;
|
||||
default: throw new LuaException($"CVec does not define a member '{key}'");
|
||||
}
|
||||
}
|
||||
@@ -118,6 +140,8 @@ namespace OpenRA
|
||||
set => throw new LuaException("CVec is read-only. Use CVec.New to create a new value");
|
||||
}
|
||||
|
||||
public LuaValue ToString(LuaRuntime runtime) => ToString();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ namespace OpenRA
|
||||
/// <summary>
|
||||
/// 1D angle - 1024 units = 360 degrees.
|
||||
/// </summary>
|
||||
public readonly struct WAngle : IScriptBindable, ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, IEquatable<WAngle>
|
||||
public readonly struct WAngle : IEquatable<WAngle>, IScriptBindable,
|
||||
ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, ILuaTableBinding, ILuaToStringBinding
|
||||
{
|
||||
public readonly int Angle;
|
||||
public int AngleSquared => Angle * Angle;
|
||||
@@ -257,6 +258,22 @@ namespace OpenRA
|
||||
return a == b;
|
||||
}
|
||||
|
||||
public LuaValue this[LuaRuntime runtime, LuaValue key]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (key.ToString())
|
||||
{
|
||||
case "Angle": return Angle;
|
||||
default: throw new LuaException($"WAngle does not define a member '{key}'");
|
||||
}
|
||||
}
|
||||
|
||||
set => throw new LuaException("WAngle is read-only. Use Angle.New to create a new value");
|
||||
}
|
||||
|
||||
public LuaValue ToString(LuaRuntime runtime) => ToString();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,10 @@ namespace OpenRA
|
||||
/// <summary>
|
||||
/// 1d world distance - 1024 units = 1 cell.
|
||||
/// </summary>
|
||||
public readonly struct WDist : IComparable, IComparable<WDist>, IEquatable<WDist>,
|
||||
IScriptBindable, ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, ILuaTableBinding
|
||||
public readonly struct WDist : IComparable, IComparable<WDist>, IEquatable<WDist>, IScriptBindable,
|
||||
ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, ILuaUnaryMinusBinding,
|
||||
ILuaMultiplicationBinding, ILuaDivisionBinding, ILuaLessThanBinding, ILuaLessThanOrEqualToBinding,
|
||||
ILuaTableBinding, ILuaToStringBinding
|
||||
{
|
||||
public readonly int Length;
|
||||
public long LengthSquared => (long)Length * Length;
|
||||
@@ -137,6 +139,40 @@ namespace OpenRA
|
||||
return a == b;
|
||||
}
|
||||
|
||||
public LuaValue Minus(LuaRuntime runtime) => new LuaCustomClrObject(-this);
|
||||
|
||||
public LuaValue Multiply(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out WDist a) || !right.TryGetClrValue(out int b))
|
||||
throw new LuaException("Attempted to call WDist.Multiply(WDist, integer) with invalid arguments.");
|
||||
|
||||
return new LuaCustomClrObject(a * b);
|
||||
}
|
||||
|
||||
public LuaValue Divide(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out WDist a) || !right.TryGetClrValue(out int b))
|
||||
throw new LuaException("Attempted to call WDist.Divide(WDist, integer) with invalid arguments.");
|
||||
|
||||
return new LuaCustomClrObject(a / b);
|
||||
}
|
||||
|
||||
public LuaValue LessThan(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out WDist a) || !right.TryGetClrValue(out WDist b))
|
||||
throw new LuaException("Attempted to call WDist.LessThan(WDist, WDist) with invalid arguments.");
|
||||
|
||||
return a < b;
|
||||
}
|
||||
|
||||
public LuaValue LessThanOrEqualTo(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out WDist a) || !right.TryGetClrValue(out WDist b))
|
||||
throw new LuaException("Attempted to call WDist.LessThanOrEqualTo(WDist, WDist) with invalid arguments.");
|
||||
|
||||
return a <= b;
|
||||
}
|
||||
|
||||
public LuaValue this[LuaRuntime runtime, LuaValue key]
|
||||
{
|
||||
get
|
||||
@@ -150,6 +186,9 @@ namespace OpenRA
|
||||
|
||||
set => throw new LuaException("WDist is read-only. Use WDist.New to create a new value");
|
||||
}
|
||||
|
||||
public LuaValue ToString(LuaRuntime runtime) => ToString();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ using OpenRA.Scripting;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public readonly struct WPos : IScriptBindable, ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, ILuaTableBinding, IEquatable<WPos>
|
||||
public readonly struct WPos : IEquatable<WPos>, IScriptBindable,
|
||||
ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, ILuaTableBinding, ILuaToStringBinding
|
||||
{
|
||||
public readonly int X, Y, Z;
|
||||
|
||||
@@ -82,7 +83,8 @@ namespace OpenRA
|
||||
public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out WPos a) || !right.TryGetClrValue(out WVec b))
|
||||
throw new LuaException($"Attempted to call WPos.Add(WPos, WVec) with invalid arguments ({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
throw new LuaException("Attempted to call WPos.Add(WPos, WVec) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
|
||||
return new LuaCustomClrObject(a + b);
|
||||
}
|
||||
@@ -91,7 +93,8 @@ namespace OpenRA
|
||||
{
|
||||
var rightType = right.WrappedClrType();
|
||||
if (!left.TryGetClrValue(out WPos a))
|
||||
throw new LuaException($"Attempted to call WPos.Subtract(WPos, (WPos|WVec)) with invalid arguments ({left.WrappedClrType().Name}, {rightType.Name})");
|
||||
throw new LuaException("Attempted to call WPos.Subtract(WPos, (WPos|WVec)) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {rightType.Name})");
|
||||
|
||||
if (rightType == typeof(WPos))
|
||||
{
|
||||
@@ -104,7 +107,8 @@ namespace OpenRA
|
||||
return new LuaCustomClrObject(a - b);
|
||||
}
|
||||
|
||||
throw new LuaException($"Attempted to call WPos.Subtract(WPos, (WPos|WVec)) with invalid arguments ({left.WrappedClrType().Name}, {rightType.Name})");
|
||||
throw new LuaException("Attempted to call WPos.Subtract(WPos, (WPos|WVec)) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {rightType.Name})");
|
||||
}
|
||||
|
||||
public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
@@ -131,6 +135,8 @@ namespace OpenRA
|
||||
set => throw new LuaException("WPos is read-only. Use WPos.New to create a new value");
|
||||
}
|
||||
|
||||
public LuaValue ToString(LuaRuntime runtime) => ToString();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,9 @@ using OpenRA.Support;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public readonly struct WVec : IScriptBindable,
|
||||
ILuaAdditionBinding, ILuaSubtractionBinding, ILuaUnaryMinusBinding, ILuaEqualityBinding, ILuaTableBinding, IEquatable<WVec>
|
||||
public readonly struct WVec : IEquatable<WVec>, IScriptBindable,
|
||||
ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, ILuaUnaryMinusBinding,
|
||||
ILuaMultiplicationBinding, ILuaDivisionBinding, ILuaTableBinding, ILuaToStringBinding
|
||||
{
|
||||
public readonly int X, Y, Z;
|
||||
|
||||
@@ -112,7 +113,8 @@ namespace OpenRA
|
||||
public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out WVec a) || !right.TryGetClrValue(out WVec b))
|
||||
throw new LuaException($"Attempted to call WVec.Add(WVec, WVec) with invalid arguments ({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
throw new LuaException("Attempted to call WVec.Add(WVec, WVec) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
|
||||
return new LuaCustomClrObject(a + b);
|
||||
}
|
||||
@@ -120,16 +122,12 @@ namespace OpenRA
|
||||
public LuaValue Subtract(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out WVec a) || !right.TryGetClrValue(out WVec b))
|
||||
throw new LuaException($"Attempted to call WVec.Subtract(WVec, WVec) with invalid arguments ({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
throw new LuaException("Attempted to call WVec.Subtract(WVec, WVec) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
|
||||
return new LuaCustomClrObject(a - b);
|
||||
}
|
||||
|
||||
public LuaValue Minus(LuaRuntime runtime)
|
||||
{
|
||||
return new LuaCustomClrObject(-this);
|
||||
}
|
||||
|
||||
public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out WVec a) || !right.TryGetClrValue(out WVec b))
|
||||
@@ -138,6 +136,29 @@ namespace OpenRA
|
||||
return a == b;
|
||||
}
|
||||
|
||||
public LuaValue Minus(LuaRuntime runtime)
|
||||
{
|
||||
return new LuaCustomClrObject(-this);
|
||||
}
|
||||
|
||||
public LuaValue Multiply(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out WVec a) || !right.TryGetClrValue(out int b))
|
||||
throw new LuaException("Attempted to call WVec.Multiply(WVec, integer) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
|
||||
return new LuaCustomClrObject(a * b);
|
||||
}
|
||||
|
||||
public LuaValue Divide(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
if (!left.TryGetClrValue(out WVec a) || !right.TryGetClrValue(out int b))
|
||||
throw new LuaException("Attempted to call WVec.Divide(WVec, integer) with invalid arguments " +
|
||||
$"({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
|
||||
|
||||
return new LuaCustomClrObject(a / b);
|
||||
}
|
||||
|
||||
public LuaValue this[LuaRuntime runtime, LuaValue key]
|
||||
{
|
||||
get
|
||||
@@ -155,6 +176,8 @@ namespace OpenRA
|
||||
set => throw new LuaException("WVec is read-only. Use WVec.New to create a new value");
|
||||
}
|
||||
|
||||
public LuaValue ToString(LuaRuntime runtime) => ToString();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
using Eluant;
|
||||
using OpenRA.Mods.Cnc.Traits;
|
||||
using OpenRA.Mods.Common.Scripting;
|
||||
using OpenRA.Scripting;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -23,7 +24,7 @@ namespace OpenRA.Mods.Cnc.Scripting
|
||||
: base(context, self) { }
|
||||
|
||||
[Desc("Chronoshift a group of actors. A duration of 0 will teleport the actors permanently.")]
|
||||
public void Chronoshift(LuaTable unitLocationPairs, int duration = 0, bool killCargo = false)
|
||||
public void Chronoshift([ScriptEmmyTypeOverride("{ [actor]: cpos }")] LuaTable unitLocationPairs, int duration = 0, bool killCargo = false)
|
||||
{
|
||||
foreach (var kv in unitLocationPairs)
|
||||
{
|
||||
@@ -33,7 +34,7 @@ namespace OpenRA.Mods.Cnc.Scripting
|
||||
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 {kv.Key.WrappedClrType().Name},{kv.Value.WrappedClrType().Name}");
|
||||
throw new LuaException($"Chronoshift requires a table of actor,cpos pairs. Received {kv.Key.WrappedClrType().Name},{kv.Value.WrappedClrType().Name}");
|
||||
}
|
||||
|
||||
var cs = actor.TraitsImplementing<Chronoshiftable>()
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace OpenRA.Mods.Common
|
||||
: base(value) { }
|
||||
}
|
||||
|
||||
public class TerrainOrientationInit : ValueActorInit<WRot>, ISingleInstanceInit
|
||||
public class TerrainOrientationInit : ValueActorInit<WRot>, ISingleInstanceInit, ISuppressInitExport
|
||||
{
|
||||
public TerrainOrientationInit(WRot value)
|
||||
: base(value) { }
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[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)
|
||||
public Actor Create(string type, bool addToWorld, [ScriptEmmyTypeOverride("initTable")] LuaTable initTable)
|
||||
{
|
||||
var initDict = new TypeDictionary();
|
||||
|
||||
@@ -176,6 +176,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
return pi != null ? pi.GetCruiseAltitude().Length : 0;
|
||||
}
|
||||
|
||||
[Desc("Returns the cost of the requested unit given by the Valued trait.")]
|
||||
public int Cost(string type)
|
||||
{
|
||||
if (!Context.World.Map.Rules.Actors.TryGetValue(type, out var ai))
|
||||
|
||||
@@ -19,16 +19,25 @@ namespace OpenRA.Mods.Common.Scripting.Global
|
||||
public AngleGlobal(ScriptContext context)
|
||||
: base(context) { }
|
||||
|
||||
[Desc("0/1024 units = 0/360 degrees")]
|
||||
public WAngle North => WAngle.Zero;
|
||||
[Desc("128 units = 315 degrees")]
|
||||
public WAngle NorthWest => new(128);
|
||||
[Desc("256 units = 270 degrees")]
|
||||
public WAngle West => new(256);
|
||||
[Desc("384 units = 225 degrees")]
|
||||
public WAngle SouthWest => new(384);
|
||||
[Desc("512 units = 180 degrees")]
|
||||
public WAngle South => new(512);
|
||||
[Desc("640 units = 135 degrees")]
|
||||
public WAngle SouthEast => new(640);
|
||||
[Desc("768 units = 90 degrees")]
|
||||
public WAngle East => new(768);
|
||||
[Desc("896 units = 45 degrees")]
|
||||
public WAngle NorthEast => new(896);
|
||||
|
||||
[Desc("Create an arbitrary angle.")]
|
||||
[Desc("Create an arbitrary angle. 1024 units = 360 degrees. North is 0. " +
|
||||
"Units increase *counter* clockwise. Comparison given to degrees increasing clockwise.")]
|
||||
public WAngle New(int a) { return new WAngle(a); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,41 +51,77 @@ namespace OpenRA.Mods.Common.Scripting.Global
|
||||
throw new LuaException("Invalid rrggbb[aa] hex string.");
|
||||
}
|
||||
|
||||
[Desc("FromHex(\"00FFFF\")")]
|
||||
public Color Aqua => Color.Aqua;
|
||||
[Desc("FromHex(\"000000\")")]
|
||||
public Color Black => Color.Black;
|
||||
[Desc("FromHex(\"0000FF\")")]
|
||||
public Color Blue => Color.Blue;
|
||||
[Desc("FromHex(\"A52A2A\")")]
|
||||
public Color Brown => Color.Brown;
|
||||
[Desc("FromHex(\"00FFFF\")")]
|
||||
public Color Cyan => Color.Cyan;
|
||||
[Desc("FromHex(\"00008B\")")]
|
||||
public Color DarkBlue => Color.DarkBlue;
|
||||
[Desc("FromHex(\"008B8B\")")]
|
||||
public Color DarkCyan => Color.DarkCyan;
|
||||
[Desc("FromHex(\"A9A9A9\")")]
|
||||
public Color DarkGray => Color.DarkGray;
|
||||
[Desc("FromHex(\"006400\")")]
|
||||
public Color DarkGreen => Color.DarkGreen;
|
||||
[Desc("FromHex(\"FF8C00\")")]
|
||||
public Color DarkOrange => Color.DarkOrange;
|
||||
[Desc("FromHex(\"8B0000\")")]
|
||||
public Color DarkRed => Color.DarkRed;
|
||||
[Desc("FromHex(\"FF00FF\")")]
|
||||
public Color Fuchsia => Color.Fuchsia;
|
||||
[Desc("FromHex(\"FFD700\")")]
|
||||
public Color Gold => Color.Gold;
|
||||
[Desc("FromHex(\"808080\")")]
|
||||
public Color Gray => Color.Gray;
|
||||
[Desc("FromHex(\"008000\")")]
|
||||
public Color Green => Color.Green;
|
||||
[Desc("FromHex(\"7CFC00\")")]
|
||||
public Color LawnGreen => Color.LawnGreen;
|
||||
[Desc("FromHex(\"ADD8E6\")")]
|
||||
public Color LightBlue => Color.LightBlue;
|
||||
[Desc("FromHex(\"E0FFFF\")")]
|
||||
public Color LightCyan => Color.LightCyan;
|
||||
[Desc("FromHex(\"D3D3D3\")")]
|
||||
public Color LightGray => Color.LightGray;
|
||||
[Desc("FromHex(\"90EE90\")")]
|
||||
public Color LightGreen => Color.LightGreen;
|
||||
[Desc("FromHex(\"FFFFE0\")")]
|
||||
public Color LightYellow => Color.LightYellow;
|
||||
[Desc("FromHex(\"00FF00\")")]
|
||||
public Color Lime => Color.Lime;
|
||||
[Desc("FromHex(\"32CD32\")")]
|
||||
public Color LimeGreen => Color.LimeGreen;
|
||||
[Desc("FromHex(\"FF00FF\")")]
|
||||
public Color Magenta => Color.Magenta;
|
||||
[Desc("FromHex(\"800000\")")]
|
||||
public Color Maroon => Color.Maroon;
|
||||
[Desc("FromHex(\"000080\")")]
|
||||
public Color Navy => Color.Navy;
|
||||
[Desc("FromHex(\"808000\")")]
|
||||
public Color Olive => Color.Olive;
|
||||
[Desc("FromHex(\"FFA500\")")]
|
||||
public Color Orange => Color.Orange;
|
||||
[Desc("FromHex(\"FF4500\")")]
|
||||
public Color OrangeRed => Color.OrangeRed;
|
||||
[Desc("FromHex(\"800080\")")]
|
||||
public Color Purple => Color.Purple;
|
||||
[Desc("FromHex(\"FF0000\")")]
|
||||
public Color Red => Color.Red;
|
||||
[Desc("FromHex(\"FA8072\")")]
|
||||
public Color Salmon => Color.Salmon;
|
||||
[Desc("FromHex(\"87CEEB\")")]
|
||||
public Color SkyBlue => Color.SkyBlue;
|
||||
[Desc("FromHex(\"008080\")")]
|
||||
public Color Teal => Color.Teal;
|
||||
[Desc("FromHex(\"FFFF00\")")]
|
||||
public Color Yellow => Color.Yellow;
|
||||
[Desc("FromHex(\"FFFFFF\")")]
|
||||
public Color White => Color.White;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
using System.Linq;
|
||||
using Eluant;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Scripting;
|
||||
|
||||
namespace OpenRA.Mods.Common.Scripting
|
||||
@@ -18,9 +21,34 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
public CPosGlobal(ScriptContext context)
|
||||
: base(context) { }
|
||||
|
||||
[Desc("Create a new CPos with the specified coordinates.")]
|
||||
[Desc("Create a new CPos with the specified coordinates on the ground (layer = 0).")]
|
||||
public CPos New(int x, int y) { return new CPos(x, y); }
|
||||
|
||||
[Desc("Create a new CPos with the specified coordinates on the specified layer. " +
|
||||
"The ground is layer 0, other layers have a unique ID. Examples include tunnels, underground, and elevated bridges.")]
|
||||
public CPos NewWithLayer(int x, int y, byte layer)
|
||||
{
|
||||
if (layer != 0)
|
||||
{
|
||||
var worldCmls = Context.World.GetCustomMovementLayers();
|
||||
if (layer >= worldCmls.Length || worldCmls[layer] == null)
|
||||
{
|
||||
var layerNames = typeof(CustomMovementLayerType)
|
||||
.GetFields()
|
||||
.Select(f => (Index: (byte)f.GetRawConstantValue(), f.Name))
|
||||
.ToArray();
|
||||
var validLayers = new[] { (Index: (byte)0, Name: "Ground") }
|
||||
.Concat(worldCmls
|
||||
.Where(cml => cml != null)
|
||||
.Select(cml => layerNames.Single(ln => ln.Index == cml.Index)));
|
||||
throw new LuaException($"Layer {layer} does not exist on this map. " +
|
||||
$"Valid layers on this map are: {string.Join(", ", validLayers.Select(x => $"{x.Index} ({x.Name})"))}");
|
||||
}
|
||||
}
|
||||
|
||||
return new CPos(x, y, layer);
|
||||
}
|
||||
|
||||
[Desc("The cell coordinate origin.")]
|
||||
public CPos Zero => CPos.Zero;
|
||||
}
|
||||
|
||||
@@ -44,11 +44,17 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
return seconds * ticksPerSecond;
|
||||
}
|
||||
|
||||
[Desc("Get the current year (1-9999).")]
|
||||
public int CurrentYear => DateTime.Now.Year;
|
||||
[Desc("Get the current month (1-12).")]
|
||||
public int CurrentMonth => DateTime.Now.Month;
|
||||
[Desc("Get the current day (1-31).")]
|
||||
public int CurrentDay => DateTime.Now.Day;
|
||||
[Desc("Get the current hour (0-23).")]
|
||||
public int CurrentHour => DateTime.Now.Hour;
|
||||
[Desc("Get the current minute (0-59).")]
|
||||
public int CurrentMinute => DateTime.Now.Minute;
|
||||
[Desc("Get the current second (0-59).")]
|
||||
public int CurrentSecond => DateTime.Now.Second;
|
||||
|
||||
[Desc("Converts the number of minutes into game time (ticks).")]
|
||||
|
||||
@@ -36,24 +36,28 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
effect.Enable(ticks);
|
||||
}
|
||||
|
||||
[Desc("Red component (0-1).")]
|
||||
public double Red
|
||||
{
|
||||
get => tintEffect?.Red ?? 1;
|
||||
set { if (tintEffect != null) tintEffect.Red = (float)value; }
|
||||
}
|
||||
|
||||
[Desc("Green component (0-1).")]
|
||||
public double Green
|
||||
{
|
||||
get => tintEffect?.Green ?? 1;
|
||||
set { if (tintEffect != null) tintEffect.Green = (float)value; }
|
||||
}
|
||||
|
||||
[Desc("Blue component (0-1).")]
|
||||
public double Blue
|
||||
{
|
||||
get => tintEffect?.Blue ?? 1;
|
||||
set { if (tintEffect != null) tintEffect.Blue = (float)value; }
|
||||
}
|
||||
|
||||
[Desc("Strength of the lighting (0-1).")]
|
||||
public double Ambient
|
||||
{
|
||||
get => tintEffect?.Ambient ?? 1;
|
||||
|
||||
@@ -37,14 +37,14 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Returns a table of all actors within the requested region, filtered using the specified function.")]
|
||||
public Actor[] ActorsInCircle(WPos location, WDist radius, LuaFunction filter = null)
|
||||
public Actor[] ActorsInCircle(WPos location, WDist radius, [ScriptEmmyTypeOverride("fun(a: actor):boolean")] LuaFunction filter = null)
|
||||
{
|
||||
var actors = Context.World.FindActorsInCircle(location, radius);
|
||||
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)
|
||||
public Actor[] ActorsInBox(WPos topLeft, WPos bottomRight, [ScriptEmmyTypeOverride("fun(a: actor):boolean")] LuaFunction filter = null)
|
||||
{
|
||||
var actors = Context.World.ActorMap.ActorsInBox(topLeft, bottomRight);
|
||||
return FilteredObjects(actors, filter).ToArray();
|
||||
@@ -81,8 +81,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Returns the first cell on the visible border of the map from the given cell,",
|
||||
"matching the filter function called as function(CPos cell).")]
|
||||
public CPos ClosestMatchingEdgeCell(CPos givenCell, LuaFunction filter)
|
||||
"matching the filter function called as function(cell: cpos):boolean.")]
|
||||
public CPos ClosestMatchingEdgeCell(CPos givenCell, [ScriptEmmyTypeOverride("fun(cell: cpos):boolean")] LuaFunction filter)
|
||||
{
|
||||
return FilteredObjects(Context.World.Map.AllEdgeCells.OrderBy(c => (givenCell - c).Length), filter).FirstOrDefault();
|
||||
}
|
||||
@@ -106,7 +106,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
public bool IsPausedShellmap => Context.World.Type == WorldType.Shellmap && gameSettings.PauseShellmap;
|
||||
|
||||
[Desc("Returns the value of a `" + nameof(ScriptLobbyDropdown) + "` selected in the game lobby.")]
|
||||
public LuaValue LobbyOption(string id)
|
||||
public string LobbyOption(string id)
|
||||
{
|
||||
var option = Context.World.WorldActor.TraitsImplementing<ScriptLobbyDropdown>()
|
||||
.FirstOrDefault(sld => sld.Info.ID == id);
|
||||
@@ -120,8 +120,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
return option.Value;
|
||||
}
|
||||
|
||||
[Desc("Returns the value of a `ScriptLobbyDropdown` selected in the game lobby or fallback to a default value.")]
|
||||
public LuaValue LobbyOptionOrDefault(string id, string fallback)
|
||||
[Desc("Returns the value of a `" + nameof(ScriptLobbyDropdown) + "` selected in the game lobby or fallback to a default value.")]
|
||||
public string LobbyOptionOrDefault(string id, string fallback)
|
||||
{
|
||||
var option = Context.World.WorldActor.TraitsImplementing<ScriptLobbyDropdown>()
|
||||
.FirstOrDefault(sld => sld.Info.ID == id);
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[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 onPlayComplete = null)
|
||||
public void PlayMusic(string track = null, [ScriptEmmyTypeOverride("fun()")] LuaFunction onPlayComplete = null)
|
||||
{
|
||||
if (!playlist.IsMusicAvailable)
|
||||
return;
|
||||
@@ -94,14 +94,14 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Play a video fullscreen. File name has to include the file extension.")]
|
||||
public void PlayMovieFullscreen(string videoFileName, LuaFunction onPlayComplete = null)
|
||||
public void PlayMovieFullscreen(string videoFileName, [ScriptEmmyTypeOverride("fun()")] LuaFunction onPlayComplete = null)
|
||||
{
|
||||
var onComplete = WrapOnPlayComplete(onPlayComplete);
|
||||
Media.PlayFMVFullscreen(world, videoFileName, onComplete);
|
||||
}
|
||||
|
||||
[Desc("Play a video in the radar window. File name has to include the file extension.")]
|
||||
public void PlayMovieInRadar(string videoFileName, LuaFunction onPlayComplete = null)
|
||||
public void PlayMovieInRadar(string videoFileName, [ScriptEmmyTypeOverride("fun()")] LuaFunction onPlayComplete = null)
|
||||
{
|
||||
var onComplete = WrapOnPlayComplete(onPlayComplete);
|
||||
Media.PlayFMVInRadar(videoFileName, onComplete);
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Returns a table of players filtered by the specified function.")]
|
||||
public Player[] GetPlayers(LuaFunction filter)
|
||||
public Player[] GetPlayers([ScriptEmmyTypeOverride("fun(p: player):boolean")] LuaFunction filter)
|
||||
{
|
||||
return FilteredObjects(Context.World.Players, filter).ToArray();
|
||||
}
|
||||
|
||||
@@ -76,9 +76,10 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
"The first member of the entryPath array will be the units' spawnpoint, " +
|
||||
"while the last one will be their destination. If actionFunc is given, " +
|
||||
"it will be executed once a unit has reached its destination. actionFunc " +
|
||||
"will be called as actionFunc(Actor actor). " +
|
||||
"will be called as actionFunc(a: actor). " +
|
||||
"Returns a table containing the deployed units.")]
|
||||
public Actor[] Reinforce(Player owner, string[] actorTypes, CPos[] entryPath, int interval = 25, LuaFunction actionFunc = null)
|
||||
public Actor[] Reinforce(Player owner, string[] actorTypes, CPos[] entryPath, int interval = 25,
|
||||
[ScriptEmmyTypeOverride("fun(a: actor)")] LuaFunction actionFunc = null)
|
||||
{
|
||||
var actors = new List<Actor>();
|
||||
for (var i = 0; i < actorTypes.Length; i++)
|
||||
@@ -115,13 +116,18 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
"has reached the destination, it will unload its cargo unless a custom actionFunc has " +
|
||||
"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 " +
|
||||
"actionFunc(Actor transport, Actor[] cargo). exitFunc will be called as exitFunc(Actor transport). " +
|
||||
"actionFunc(transport: actor, cargo: actor[]). exitFunc will be called as exitFunc(transport: actor). " +
|
||||
"dropRange determines how many cells away the transport will try to land " +
|
||||
"if the actual destination is blocked (if the transport is an aircraft). " +
|
||||
"Returns a table in which the first value is the transport, " +
|
||||
"and the second a table containing the deployed units.")]
|
||||
public LuaTable ReinforceWithTransport(Player owner, string actorType, string[] cargoTypes, CPos[] entryPath, CPos[] exitPath = null,
|
||||
LuaFunction actionFunc = null, LuaFunction exitFunc = null, int dropRange = 3)
|
||||
[return: ScriptEmmyTypeOverride("{ [1]: actor, [2]: actor[] }")]
|
||||
public LuaTable ReinforceWithTransport(Player owner, string actorType,
|
||||
[ScriptEmmyTypeOverride("string[]|nil")] string[] cargoTypes,
|
||||
CPos[] entryPath, CPos[] exitPath = null,
|
||||
[ScriptEmmyTypeOverride("fun(transport: actor, cargo: actor[])")] LuaFunction actionFunc = null,
|
||||
[ScriptEmmyTypeOverride("fun(transport: actor)")] LuaFunction exitFunc = null,
|
||||
int dropRange = 3)
|
||||
{
|
||||
var transport = CreateActor(owner, actorType, true, entryPath[0], entryPath.Length > 1 ? entryPath[1] : null);
|
||||
var cargo = transport.TraitOrDefault<Cargo>();
|
||||
|
||||
@@ -33,7 +33,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)
|
||||
public void AfterDelay(int delay, [ScriptEmmyTypeOverride("fun()")] LuaFunction func)
|
||||
{
|
||||
var f = (LuaFunction)func.CopyReference();
|
||||
void DoCall()
|
||||
@@ -53,8 +53,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function for each passenger when it enters a transport. " +
|
||||
"The callback function will be called as func(Actor transport, Actor passenger).")]
|
||||
public void OnPassengerEntered(Actor actor, LuaFunction func)
|
||||
"The callback function will be called as func(transport: actor, passenger: actor).")]
|
||||
public void OnPassengerEntered(Actor actor, [ScriptEmmyTypeOverride("fun(transport: actor, passenger: actor)")] LuaFunction func)
|
||||
{
|
||||
if (actor == null)
|
||||
throw new NullReferenceException(nameof(actor));
|
||||
@@ -63,8 +63,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function for each passenger when it exits a transport. " +
|
||||
"The callback function will be called as func(Actor transport, Actor passenger).")]
|
||||
public void OnPassengerExited(Actor actor, LuaFunction func)
|
||||
"The callback function will be called as func(transport: actor, passenger: actor).")]
|
||||
public void OnPassengerExited(Actor actor, [ScriptEmmyTypeOverride("fun(transport: actor, passenger: actor)")] LuaFunction func)
|
||||
{
|
||||
if (actor == null)
|
||||
throw new NullReferenceException(nameof(actor));
|
||||
@@ -73,8 +73,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function each tick that the actor is idle. " +
|
||||
"The callback function will be called as func(Actor self).")]
|
||||
public void OnIdle(Actor actor, LuaFunction func)
|
||||
"The callback function will be called as func(self: actor).")]
|
||||
public void OnIdle(Actor actor, [ScriptEmmyTypeOverride("fun(self: actor)")] LuaFunction func)
|
||||
{
|
||||
if (actor == null)
|
||||
throw new NullReferenceException(nameof(actor));
|
||||
@@ -83,8 +83,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when the actor is damaged. The callback " +
|
||||
"function will be called as func(Actor self, Actor attacker, int damage).")]
|
||||
public void OnDamaged(Actor actor, LuaFunction func)
|
||||
"function will be called as func(self: actor, attacker: actor, damage: integer).")]
|
||||
public void OnDamaged(Actor actor, [ScriptEmmyTypeOverride("fun(self: actor, attacker: actor, damage: integer)")] LuaFunction func)
|
||||
{
|
||||
if (actor == null)
|
||||
throw new NullReferenceException(nameof(actor));
|
||||
@@ -93,8 +93,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when the actor is killed. The callback " +
|
||||
"function will be called as func(Actor self, Actor killer).")]
|
||||
public void OnKilled(Actor actor, LuaFunction func)
|
||||
"function will be called as func(self: actor, killer: actor).")]
|
||||
public void OnKilled(Actor actor, [ScriptEmmyTypeOverride("fun(self: actor, killer: actor)")] LuaFunction func)
|
||||
{
|
||||
if (actor == null)
|
||||
throw new NullReferenceException(nameof(actor));
|
||||
@@ -104,7 +104,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
[Desc("Call a function when all of the actors in a group are killed. The callback " +
|
||||
"function will be called as func().")]
|
||||
public void OnAllKilled(Actor[] actors, LuaFunction func)
|
||||
public void OnAllKilled(Actor[] actors, [ScriptEmmyTypeOverride("fun()")] LuaFunction func)
|
||||
{
|
||||
if (actors == null)
|
||||
throw new NullReferenceException(nameof(actors));
|
||||
@@ -131,8 +131,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when one of the actors in a group is killed. The callback " +
|
||||
"function will be called as func(Actor killed).")]
|
||||
public void OnAnyKilled(Actor[] actors, LuaFunction func)
|
||||
"function will be called as func(killed: actor).")]
|
||||
public void OnAnyKilled(Actor[] actors, [ScriptEmmyTypeOverride("fun(killed: actor)")] LuaFunction func)
|
||||
{
|
||||
var called = false;
|
||||
var f = (LuaFunction)func.CopyReference();
|
||||
@@ -163,8 +163,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when this actor produces another actor. " +
|
||||
"The callback function will be called as func(Actor producer, Actor produced).")]
|
||||
public void OnProduction(Actor actors, LuaFunction func)
|
||||
"The callback function will be called as func(producer: actor, produced: actor).")]
|
||||
public void OnProduction(Actor actors, [ScriptEmmyTypeOverride("fun(producer: actor, produced: actor)")] LuaFunction func)
|
||||
{
|
||||
if (actors == null)
|
||||
throw new NullReferenceException(nameof(actors));
|
||||
@@ -173,15 +173,15 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when any actor produces another actor. The callback " +
|
||||
"function will be called as func(Actor producer, Actor produced, string productionType).")]
|
||||
public void OnAnyProduction(LuaFunction func)
|
||||
"function will be called as func(producer: actor, produced: actor, productionType: string).")]
|
||||
public void OnAnyProduction([ScriptEmmyTypeOverride("fun(producer: actor, produced: actor, productionType: string)")] LuaFunction func)
|
||||
{
|
||||
GetScriptTriggers(Context.World.WorldActor).RegisterCallback(Trigger.OnOtherProduction, func, Context);
|
||||
}
|
||||
|
||||
[Desc("Call a function when this player completes all primary objectives. " +
|
||||
"The callback function will be called as func(Player player).")]
|
||||
public void OnPlayerWon(Player player, LuaFunction func)
|
||||
"The callback function will be called as func(p: player).")]
|
||||
public void OnPlayerWon(Player player, [ScriptEmmyTypeOverride("fun(p: player)")] LuaFunction func)
|
||||
{
|
||||
if (player == null)
|
||||
throw new NullReferenceException(nameof(player));
|
||||
@@ -190,8 +190,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when this player fails any primary objective. " +
|
||||
"The callback function will be called as func(Player player).")]
|
||||
public void OnPlayerLost(Player player, LuaFunction func)
|
||||
"The callback function will be called as func(p: player).")]
|
||||
public void OnPlayerLost(Player player, [ScriptEmmyTypeOverride("fun(p: player)")] LuaFunction func)
|
||||
{
|
||||
if (player == null)
|
||||
throw new NullReferenceException(nameof(player));
|
||||
@@ -200,8 +200,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when this player is assigned a new objective. " +
|
||||
"The callback function will be called as func(Player player, int objectiveID).")]
|
||||
public void OnObjectiveAdded(Player player, LuaFunction func)
|
||||
"The callback function will be called as func(p: player, objectiveId: integer).")]
|
||||
public void OnObjectiveAdded(Player player, [ScriptEmmyTypeOverride("fun(p: player, objectiveId: integer)")] LuaFunction func)
|
||||
{
|
||||
if (player == null)
|
||||
throw new NullReferenceException(nameof(player));
|
||||
@@ -210,8 +210,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when this player completes an objective. " +
|
||||
"The callback function will be called as func(Player player, int objectiveID).")]
|
||||
public void OnObjectiveCompleted(Player player, LuaFunction func)
|
||||
"The callback function will be called as func(p: player, objectiveId: integer).")]
|
||||
public void OnObjectiveCompleted(Player player, [ScriptEmmyTypeOverride("fun(p: player, objectiveId: integer)")] LuaFunction func)
|
||||
{
|
||||
if (player == null)
|
||||
throw new NullReferenceException(nameof(player));
|
||||
@@ -220,8 +220,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when this player fails an objective. " +
|
||||
"The callback function will be called as func(Player player, int objectiveID).")]
|
||||
public void OnObjectiveFailed(Player player, LuaFunction func)
|
||||
"The callback function will be called as func(p: player, objectiveId: integer).")]
|
||||
public void OnObjectiveFailed(Player player, [ScriptEmmyTypeOverride("fun(p: player, objectiveId: integer)")] LuaFunction func)
|
||||
{
|
||||
if (player == null)
|
||||
throw new NullReferenceException(nameof(player));
|
||||
@@ -230,8 +230,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when this actor is added to the world. " +
|
||||
"The callback function will be called as func(Actor self).")]
|
||||
public void OnAddedToWorld(Actor actor, LuaFunction func)
|
||||
"The callback function will be called as func(self: actor).")]
|
||||
public void OnAddedToWorld(Actor actor, [ScriptEmmyTypeOverride("fun(self: actor)")] LuaFunction func)
|
||||
{
|
||||
if (actor == null)
|
||||
throw new NullReferenceException(nameof(actor));
|
||||
@@ -240,8 +240,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when this actor is removed from the world. " +
|
||||
"The callback function will be called as func(Actor self).")]
|
||||
public void OnRemovedFromWorld(Actor actor, LuaFunction func)
|
||||
"The callback function will be called as func(self: actor).")]
|
||||
public void OnRemovedFromWorld(Actor actor, [ScriptEmmyTypeOverride("fun(self: actor)")] LuaFunction func)
|
||||
{
|
||||
if (actor == null)
|
||||
throw new NullReferenceException(nameof(actor));
|
||||
@@ -251,7 +251,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
[Desc("Call a function when all of the actors in a group have been removed from the world. " +
|
||||
"The callback function will be called as func().")]
|
||||
public void OnAllRemovedFromWorld(Actor[] actors, LuaFunction func)
|
||||
public void OnAllRemovedFromWorld(Actor[] actors, [ScriptEmmyTypeOverride("fun()")] LuaFunction func)
|
||||
{
|
||||
if (actors == null)
|
||||
throw new NullReferenceException(nameof(actors));
|
||||
@@ -303,8 +303,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when this actor is captured. The callback function " +
|
||||
"will be called as func(Actor self, Actor captor, Player oldOwner, Player newOwner).")]
|
||||
public void OnCapture(Actor actors, LuaFunction func)
|
||||
"will be called as func(self: actor, captor: actor, oldOwner: player, newOwner: player).")]
|
||||
public void OnCapture(Actor actors, [ScriptEmmyTypeOverride("fun(self: actor, captor: actor, oldOwner: player, newOwner: player)")] LuaFunction func)
|
||||
{
|
||||
if (actors == null)
|
||||
throw new NullReferenceException(nameof(actors));
|
||||
@@ -314,7 +314,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
[Desc("Call a function when this actor is killed or captured. " +
|
||||
"The callback function will be called as func().")]
|
||||
public void OnKilledOrCaptured(Actor actor, LuaFunction func)
|
||||
public void OnKilledOrCaptured(Actor actor, [ScriptEmmyTypeOverride("fun()")] LuaFunction func)
|
||||
{
|
||||
var called = false;
|
||||
|
||||
@@ -346,7 +346,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
[Desc("Call a function when all of the actors in a group have been killed or captured. " +
|
||||
"The callback function will be called as func().")]
|
||||
public void OnAllKilledOrCaptured(Actor[] actors, LuaFunction func)
|
||||
public void OnAllKilledOrCaptured(Actor[] actors, [ScriptEmmyTypeOverride("fun()")] LuaFunction func)
|
||||
{
|
||||
if (actors == null)
|
||||
throw new NullReferenceException(nameof(actors));
|
||||
@@ -379,9 +379,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when a ground-based actor enters this cell footprint. " +
|
||||
"Returns the trigger id for later removal using RemoveFootprintTrigger(int id). " +
|
||||
"The callback function will be called as func(Actor a, int id).")]
|
||||
public int OnEnteredFootprint(CPos[] cells, LuaFunction func)
|
||||
"Returns the trigger ID for later removal using RemoveFootprintTrigger(id: integer). " +
|
||||
"The callback function will be called as func(a: actor, id: integer).")]
|
||||
public int OnEnteredFootprint(CPos[] cells, [ScriptEmmyTypeOverride("fun(a: actor, id: integer)")] LuaFunction func)
|
||||
{
|
||||
// We can't easily dispose onEntry, so we'll have to rely on finalization for it.
|
||||
var onEntry = (LuaFunction)func.CopyReference();
|
||||
@@ -406,9 +406,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when a ground-based actor leaves this cell footprint. " +
|
||||
"Returns the trigger id for later removal using RemoveFootprintTrigger(int id). " +
|
||||
"The callback function will be called as func(Actor a, int id).")]
|
||||
public int OnExitedFootprint(CPos[] cells, LuaFunction func)
|
||||
"Returns the trigger ID for later removal using RemoveFootprintTrigger(id: integer). " +
|
||||
"The callback function will be called as func(a: actor, id: integer).")]
|
||||
public int OnExitedFootprint(CPos[] cells, [ScriptEmmyTypeOverride("fun(a: actor, id: integer)")] LuaFunction func)
|
||||
{
|
||||
// We can't easily dispose onExit, so we'll have to rely on finalization for it.
|
||||
var onExit = (LuaFunction)func.CopyReference();
|
||||
@@ -439,9 +439,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when an actor enters this range. " +
|
||||
"Returns the trigger id for later removal using RemoveProximityTrigger(int id). " +
|
||||
"The callback function will be called as func(Actor a, int id).")]
|
||||
public int OnEnteredProximityTrigger(WPos pos, WDist range, LuaFunction func)
|
||||
"Returns the trigger ID for later removal using RemoveProximityTrigger(id: integer). " +
|
||||
"The callback function will be called as func(a: actor, id: integer).")]
|
||||
public int OnEnteredProximityTrigger(WPos pos, WDist range, [ScriptEmmyTypeOverride("fun(a: actor, id: integer)")] LuaFunction func)
|
||||
{
|
||||
// We can't easily dispose onEntry, so we'll have to rely on finalization for it.
|
||||
var onEntry = (LuaFunction)func.CopyReference();
|
||||
@@ -466,9 +466,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when an actor leaves this range. " +
|
||||
"Returns the trigger id for later removal using RemoveProximityTrigger(int id). " +
|
||||
"The callback function will be called as func(Actor a, int id).")]
|
||||
public int OnExitedProximityTrigger(WPos pos, WDist range, LuaFunction func)
|
||||
"Returns the trigger ID for later removal using RemoveProximityTrigger(id: integer). " +
|
||||
"The callback function will be called as func(a: actor, id: integer).")]
|
||||
public int OnExitedProximityTrigger(WPos pos, WDist range, [ScriptEmmyTypeOverride("fun(a: actor, id: integer)")] LuaFunction func)
|
||||
{
|
||||
// We can't easily dispose onExit, so we'll have to rely on finalization for it.
|
||||
var onExit = (LuaFunction)func.CopyReference();
|
||||
@@ -499,8 +499,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when this actor is infiltrated. The callback function " +
|
||||
"will be called as func(Actor self, Actor infiltrator).")]
|
||||
public void OnInfiltrated(Actor actor, LuaFunction func)
|
||||
"will be called as func(self: actor, infiltrator: actor).")]
|
||||
public void OnInfiltrated(Actor actor, [ScriptEmmyTypeOverride("fun(self: actor, infiltrator: actor)")] LuaFunction func)
|
||||
{
|
||||
if (actor == null)
|
||||
throw new NullReferenceException(nameof(actor));
|
||||
@@ -509,9 +509,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when this actor is discovered by an enemy or a player with a Neutral stance. " +
|
||||
"The callback function will be called as func(Actor discovered, Player discoverer). " +
|
||||
"The callback function will be called as func(discovered: actor, discoverer: player). " +
|
||||
"The player actor needs the 'EnemyWatcher' trait. The actors to discover need the 'AnnounceOnSeen' trait.")]
|
||||
public void OnDiscovered(Actor actor, LuaFunction func)
|
||||
public void OnDiscovered(Actor actor, [ScriptEmmyTypeOverride("fun(discovered: actor, discoverer: player)")] LuaFunction func)
|
||||
{
|
||||
if (actor == null)
|
||||
throw new NullReferenceException(nameof(actor));
|
||||
@@ -520,9 +520,10 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when this player is discovered by an enemy or neutral player. " +
|
||||
"The callback function will be called as func(Player discovered, Player discoverer, Actor discoveredActor)." +
|
||||
"The callback function will be called as func(discovered: player, discoverer: player, discoveredActor: actor)." +
|
||||
"The player actor needs the 'EnemyWatcher' trait. The actors to discover need the 'AnnounceOnSeen' trait.")]
|
||||
public void OnPlayerDiscovered(Player discovered, LuaFunction func)
|
||||
public void OnPlayerDiscovered(
|
||||
Player discovered, [ScriptEmmyTypeOverride("fun(discovered: player, discoverer: player, discoveredActor: actor)")] LuaFunction func)
|
||||
{
|
||||
if (discovered == null)
|
||||
throw new NullReferenceException(nameof(discovered));
|
||||
@@ -531,8 +532,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when this actor is sold. The callback function " +
|
||||
"will be called as func(Actor self).")]
|
||||
public void OnSold(Actor actor, LuaFunction func)
|
||||
"will be called as func(self: actor).")]
|
||||
public void OnSold(Actor actor, [ScriptEmmyTypeOverride("fun(self: actor)")] LuaFunction func)
|
||||
{
|
||||
if (actor == null)
|
||||
throw new NullReferenceException(nameof(actor));
|
||||
@@ -541,7 +542,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Call a function when the game timer expires. The callback function will be called as func().")]
|
||||
public void OnTimerExpired(LuaFunction func)
|
||||
public void OnTimerExpired([ScriptEmmyTypeOverride("fun()")] LuaFunction func)
|
||||
{
|
||||
GetScriptTriggers(Context.World.WorldActor).RegisterCallback(Trigger.OnTimerExpired, func, Context);
|
||||
}
|
||||
|
||||
@@ -34,12 +34,14 @@ namespace OpenRA.Mods.Common.Scripting.Global
|
||||
luaLabel.GetColor = () => c;
|
||||
}
|
||||
|
||||
public string Translate(string text, LuaTable table = null)
|
||||
[Desc("Translates text into the users language. The translation key must be added to the language files (*.ftl). " +
|
||||
"Args can be passed to be substituted into the resulting message.")]
|
||||
public string Translate(string translationKey, [ScriptEmmyTypeOverride("{ string: any }")] LuaTable args = null)
|
||||
{
|
||||
if (table != null)
|
||||
if (args != null)
|
||||
{
|
||||
var argumentDictionary = new Dictionary<string, object>();
|
||||
foreach (var kv in table)
|
||||
foreach (var kv in args)
|
||||
{
|
||||
using (kv.Key)
|
||||
using (kv.Value)
|
||||
@@ -53,10 +55,10 @@ namespace OpenRA.Mods.Common.Scripting.Global
|
||||
}
|
||||
}
|
||||
|
||||
return TranslationProvider.GetString(text, argumentDictionary);
|
||||
return TranslationProvider.GetString(translationKey, argumentDictionary);
|
||||
}
|
||||
|
||||
return TranslationProvider.GetString(text);
|
||||
return TranslationProvider.GetString(translationKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,14 +23,18 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
: base(context) { }
|
||||
|
||||
[Desc("Calls a function on every element in a collection.")]
|
||||
public void Do(LuaValue[] collection, LuaFunction func)
|
||||
public void Do(
|
||||
[ScriptEmmyTypeOverride("T[]", "T")] LuaValue[] collection,
|
||||
[ScriptEmmyTypeOverride("fun(item: T)", "T")] LuaFunction func)
|
||||
{
|
||||
foreach (var c in collection)
|
||||
func.Call(c).Dispose();
|
||||
}
|
||||
|
||||
[Desc("Returns true if func returns true for any element in a collection.")]
|
||||
public bool Any(LuaValue[] collection, LuaFunction func)
|
||||
public bool Any(
|
||||
[ScriptEmmyTypeOverride("T[]", "T")] LuaValue[] collection,
|
||||
[ScriptEmmyTypeOverride("fun(item: T):boolean?", "T")] LuaFunction func)
|
||||
{
|
||||
foreach (var c in collection)
|
||||
using (var ret = func.Call(c))
|
||||
@@ -42,7 +46,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Returns true if func returns true for all elements in a collection.")]
|
||||
public bool All(LuaValue[] collection, LuaFunction func)
|
||||
public bool All(
|
||||
[ScriptEmmyTypeOverride("T[]", "T")] LuaValue[] collection,
|
||||
[ScriptEmmyTypeOverride("fun(item: T):boolean?", "T")] LuaFunction func)
|
||||
{
|
||||
foreach (var c in collection)
|
||||
using (var ret = func.Call(c))
|
||||
@@ -54,7 +60,10 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Returns the original collection filtered with the func.")]
|
||||
public LuaTable Where(LuaValue[] collection, LuaFunction func)
|
||||
[return: ScriptEmmyTypeOverride("T[]", "T")]
|
||||
public LuaTable Where(
|
||||
[ScriptEmmyTypeOverride("T[]", "T")] LuaValue[] collection,
|
||||
[ScriptEmmyTypeOverride("fun(item: T):boolean?", "T")] LuaFunction func)
|
||||
{
|
||||
var t = Context.CreateTable();
|
||||
|
||||
@@ -68,13 +77,19 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Returns the first n values from a collection.")]
|
||||
public LuaValue[] Take(int n, LuaValue[] source)
|
||||
[return: ScriptEmmyTypeOverride("T[]", "T")]
|
||||
public LuaValue[] Take(
|
||||
int n,
|
||||
[ScriptEmmyTypeOverride("T[]", "T")] LuaValue[] source)
|
||||
{
|
||||
return source.Take(n).Select(v => v.CopyReference()).ToArray();
|
||||
}
|
||||
|
||||
[Desc("Skips over the first numElements members of a table and return the rest.")]
|
||||
public LuaTable Skip(LuaTable table, int numElements)
|
||||
[return: ScriptEmmyTypeOverride("T[]", "T")]
|
||||
public LuaTable Skip(
|
||||
[ScriptEmmyTypeOverride("T[]", "T")] LuaTable table,
|
||||
int numElements)
|
||||
{
|
||||
var t = Context.CreateTable();
|
||||
|
||||
@@ -86,7 +101,10 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Concatenates two Lua tables into a single table.")]
|
||||
public LuaTable Concat(LuaValue[] firstCollection, LuaValue[] secondCollection)
|
||||
[return: ScriptEmmyTypeOverride("T[]", "T")]
|
||||
public LuaTable Concat(
|
||||
[ScriptEmmyTypeOverride("T[]", "T")] LuaValue[] firstCollection,
|
||||
[ScriptEmmyTypeOverride("T[]", "T")] LuaValue[] secondCollection)
|
||||
{
|
||||
var t = Context.CreateTable();
|
||||
|
||||
@@ -100,13 +118,15 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
}
|
||||
|
||||
[Desc("Returns a random value from a collection.")]
|
||||
public LuaValue Random(LuaValue[] collection)
|
||||
[return: ScriptEmmyTypeOverride("T", "T")]
|
||||
public LuaValue Random([ScriptEmmyTypeOverride("T[]", "T")] LuaValue[] collection)
|
||||
{
|
||||
return collection.Random(Context.World.SharedRandom).CopyReference();
|
||||
}
|
||||
|
||||
[Desc("Returns the collection in a random order.")]
|
||||
public LuaValue[] Shuffle(LuaValue[] collection)
|
||||
[return: ScriptEmmyTypeOverride("T[]", "T")]
|
||||
public LuaValue[] Shuffle([ScriptEmmyTypeOverride("T[]", "T")] LuaValue[] collection)
|
||||
{
|
||||
return collection.Shuffle(Context.World.SharedRandom).ToArray();
|
||||
}
|
||||
|
||||
@@ -63,8 +63,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
[ScriptActorPropertyActivity]
|
||||
[Desc("Patrol along a set of given waypoints until a condition becomes true. " +
|
||||
"The actor will wait for `wait` ticks at each waypoint.")]
|
||||
public void PatrolUntil(CPos[] waypoints, LuaFunction func, int wait = 0)
|
||||
"The actor will wait for `wait` ticks at each waypoint. " +
|
||||
"The callback function will be called as func(self: actor):boolean.")]
|
||||
public void PatrolUntil(CPos[] waypoints, [ScriptEmmyTypeOverride("fun(self: actor):boolean")] LuaFunction func, int wait = 0)
|
||||
{
|
||||
Patrol(waypoints, false, wait);
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
[ScriptActorPropertyActivity]
|
||||
[Desc("Run an arbitrary Lua function.")]
|
||||
public void CallFunc(LuaFunction func)
|
||||
public void CallFunc([ScriptEmmyTypeOverride("fun()")] LuaFunction func)
|
||||
{
|
||||
Self.QueueActivity(new CallLuaFunc(func, Context));
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
public int MaxHealth => health.MaxHP;
|
||||
|
||||
[Desc("Kill the actor. damageTypes may be omitted, specified as a string, or as table of strings.")]
|
||||
public void Kill(object damageTypes = null)
|
||||
public void Kill([ScriptEmmyTypeOverride("string|{ [unknown]: string }")] object damageTypes = null)
|
||||
{
|
||||
Damage damage;
|
||||
if (damageTypes is string d)
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
exp = player.PlayerActor.Trait<PlayerExperience>();
|
||||
}
|
||||
|
||||
[Desc("Get or set the current experience.")]
|
||||
public int Experience
|
||||
{
|
||||
get => exp.Experience;
|
||||
|
||||
@@ -130,10 +130,10 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
[Desc("Build the specified set of actors using a TD-style (per building) production queue. " +
|
||||
"The function will return true if production could be started, false otherwise. " +
|
||||
"If an actionFunc is given, it will be called as actionFunc(Actor[] actors) once " +
|
||||
"If an actionFunc is given, it will be called as actionFunc(actors: actor[]) once " +
|
||||
"production of all actors has been completed. The actors array is guaranteed to " +
|
||||
"only contain alive actors.")]
|
||||
public bool Build(string[] actorTypes, LuaFunction actionFunc = null)
|
||||
public bool Build(string[] actorTypes, [ScriptEmmyTypeOverride("fun(actors: actor[])")] LuaFunction actionFunc = null)
|
||||
{
|
||||
if (triggers.HasAnyCallbacksFor(Trigger.OnProduction))
|
||||
return false;
|
||||
@@ -234,11 +234,11 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
[Desc("Build the specified set of actors using classic (RA-style) production queues. " +
|
||||
"The function will return true if production could be started, false otherwise. " +
|
||||
"If an actionFunc is given, it will be called as actionFunc(Actor[] actors) once " +
|
||||
"If an actionFunc is given, it will be called as actionFunc(actors: actor[]) once " +
|
||||
"production of all actors has been completed. The actors array is guaranteed to " +
|
||||
"only contain alive actors. Note: This function will fail to work when called " +
|
||||
"during the first tick.")]
|
||||
public bool Build(string[] actorTypes, LuaFunction actionFunc = null)
|
||||
public bool Build(string[] actorTypes, [ScriptEmmyTypeOverride("fun(actors: actor[])")] LuaFunction actionFunc = null)
|
||||
{
|
||||
var typeToQueueMap = new Dictionary<string, string>();
|
||||
foreach (var actorType in actorTypes.Distinct())
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Mods.Common.UtilityCommands;
|
||||
|
||||
namespace OpenRA.Mods.Common.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to override the Emmy Lua type generated by the <see cref="ExtractEmmyLuaAPI"/> utility command.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
|
||||
public sealed class ScriptEmmyTypeOverrideAttribute : Attribute
|
||||
{
|
||||
public readonly string TypeDeclaration;
|
||||
public readonly string GenericTypeDeclaration;
|
||||
|
||||
public ScriptEmmyTypeOverrideAttribute(string typeDeclaration, string genericTypeDeclaration = null)
|
||||
{
|
||||
TypeDeclaration = typeDeclaration;
|
||||
GenericTypeDeclaration = genericTypeDeclaration;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using OpenRA.Mods.Common.Scripting;
|
||||
using OpenRA.Scripting;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -35,7 +36,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
var version = utility.ModData.Manifest.Metadata.Version;
|
||||
Console.WriteLine($"-- This is an automatically generated Lua API definition generated for {version} of OpenRA.");
|
||||
Console.WriteLine("-- https://wiki.openra.net/Utility was used with the --emmy-lua-api parameter.");
|
||||
Console.WriteLine("-- See https://docs.openra.net/en/latest/release/lua/ for human readable documentation.");
|
||||
Console.WriteLine("-- See https://docs.openra.net/en/release/lua/ for human readable documentation.");
|
||||
|
||||
Console.WriteLine();
|
||||
WriteDiagnosticsDisabling();
|
||||
@@ -87,11 +88,14 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("--- Base engine types.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("---@class cpos");
|
||||
Console.WriteLine("---@field X integer");
|
||||
Console.WriteLine("---@field Y integer");
|
||||
Console.WriteLine("---@field Layer integer");
|
||||
Console.WriteLine("---@operator add(cvec): cpos");
|
||||
Console.WriteLine("---@operator sub(cvec): cpos");
|
||||
Console.WriteLine("---@operator sub(cpos): cvec");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("---@class wpos");
|
||||
Console.WriteLine("---@field X integer");
|
||||
@@ -99,6 +103,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
Console.WriteLine("---@field Z integer");
|
||||
Console.WriteLine("---@operator add(wvec): wpos");
|
||||
Console.WriteLine("---@operator sub(wvec): wpos");
|
||||
Console.WriteLine("---@operator sub(wpos): wvec");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("---@class wangle");
|
||||
Console.WriteLine("---@field Angle integer");
|
||||
@@ -107,19 +112,32 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("---@class wdist");
|
||||
Console.WriteLine("---@field Length integer");
|
||||
Console.WriteLine("---@operator add(wdist): wdist");
|
||||
Console.WriteLine("---@operator sub(wdist): wdist");
|
||||
Console.WriteLine("---@operator unm(wdist): wdist");
|
||||
Console.WriteLine("---@operator mul(integer): wdist");
|
||||
Console.WriteLine("---@operator div(integer): wdist");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("---@class wvec");
|
||||
Console.WriteLine("---@field X integer");
|
||||
Console.WriteLine("---@field Y integer");
|
||||
Console.WriteLine("---@field Z integer");
|
||||
Console.WriteLine("---@field Facing wangle");
|
||||
Console.WriteLine("---@operator add(wvec): wvec");
|
||||
Console.WriteLine("---@operator sub(wvec): wvec");
|
||||
Console.WriteLine("---@operator unm(wvec): wvec");
|
||||
Console.WriteLine("---@operator mul(integer): wvec");
|
||||
Console.WriteLine("---@operator div(integer): wvec");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("---@class cvec");
|
||||
Console.WriteLine("---@field X integer");
|
||||
Console.WriteLine("---@field Y integer");
|
||||
Console.WriteLine("---@field Length integer");
|
||||
Console.WriteLine("---@operator add(cvec): cvec");
|
||||
Console.WriteLine("---@operator sub(cvec): cvec");
|
||||
Console.WriteLine("---@operator unm(cvec): cvec");
|
||||
Console.WriteLine("---@operator mul(integer): cvec");
|
||||
Console.WriteLine("---@operator div(integer): cvec");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("---@class color");
|
||||
Console.WriteLine("local color = { };");
|
||||
@@ -146,7 +164,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
if (p.ParameterType.IsEnum)
|
||||
localEnums.Add(p.ParameterType);
|
||||
|
||||
return p.ParameterType.EmmyLuaString();
|
||||
return p.EmmyLuaString($"{init.Name}").TypeDeclaration;
|
||||
})))
|
||||
.Where(s => !s.Contains(", "))
|
||||
.Distinct());
|
||||
@@ -207,6 +225,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
foreach (var line in lines)
|
||||
Console.WriteLine($" --- {line}");
|
||||
}
|
||||
else
|
||||
throw new NotSupportedException($"Missing {nameof(DescAttribute)} on {t.Name} {member.Name}");
|
||||
|
||||
if (member is PropertyInfo propertyInfo)
|
||||
{
|
||||
@@ -214,15 +234,20 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
foreach (var obsolete in attributes.OfType<ObsoleteAttribute>())
|
||||
Console.WriteLine($" ---@deprecated {obsolete.Message}");
|
||||
|
||||
Console.WriteLine($" ---@type {propertyInfo.PropertyType.EmmyLuaString()}");
|
||||
Console.WriteLine($" ---@type {propertyInfo.PropertyType.EmmyLuaString($"{t.Name} {member.Name}")}");
|
||||
body = propertyInfo.Name + " = nil;";
|
||||
}
|
||||
|
||||
if (member is MethodInfo methodInfo)
|
||||
{
|
||||
var parameters = methodInfo.GetParameters();
|
||||
foreach (var parameter in parameters)
|
||||
Console.WriteLine($" ---@param {parameter.EmmyLuaString()}");
|
||||
var luaParameters = parameters
|
||||
.Select(parameter => parameter.NameAndEmmyLuaString($"{t.Name} {member.Name}"))
|
||||
.ToArray();
|
||||
foreach (var generic in luaParameters.Select(p => p.Generic).Where(g => !string.IsNullOrEmpty(g)).Distinct())
|
||||
Console.WriteLine($" ---@generic {generic}");
|
||||
foreach (var nameAndType in luaParameters.Select(p => p.NameAndType))
|
||||
Console.WriteLine($" ---@param {nameAndType}");
|
||||
|
||||
var parameterString = parameters.Select(p => p.Name).JoinWith(", ");
|
||||
|
||||
@@ -230,9 +255,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
foreach (var obsolete in attributes.OfType<ObsoleteAttribute>())
|
||||
Console.WriteLine($" ---@deprecated {obsolete.Message}");
|
||||
|
||||
var returnType = methodInfo.ReturnType.EmmyLuaString();
|
||||
if (returnType != "Void")
|
||||
Console.WriteLine($" ---@return {returnType}");
|
||||
if (methodInfo.ReturnType != typeof(void))
|
||||
Console.WriteLine($" ---@return {methodInfo.ReturnTypeEmmyLuaString($"{t.Name} {member.Name}")}");
|
||||
|
||||
body = member.Name + $" = function({parameterString}) end;";
|
||||
}
|
||||
@@ -274,7 +298,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
if (duplicateMembers.Contains(memberInfo.Name))
|
||||
Console.WriteLine(" ---@diagnostic disable-next-line: duplicate-index");
|
||||
|
||||
Console.WriteLine($"---@field {propertyInfo.Name} {propertyInfo.PropertyType.EmmyLuaString()}");
|
||||
Console.WriteLine($"---@field {propertyInfo.Name} {propertyInfo.PropertyType.EmmyLuaString($"{memberInfo.DeclaringType.Name} {memberInfo.Name}")}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +316,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
if (duplicateMembers.Contains(memberInfo.Name))
|
||||
Console.WriteLine(" ---@diagnostic disable-next-line: duplicate-index");
|
||||
|
||||
Console.WriteLine($" ---@type {propertyInfo.PropertyType.EmmyLuaString()}");
|
||||
Console.WriteLine($" ---@type {propertyInfo.PropertyType.EmmyLuaString($"{memberInfo.DeclaringType.Name} {memberInfo.Name}")}");
|
||||
Console.WriteLine($" {propertyInfo.Name} = nil;");
|
||||
}
|
||||
|
||||
@@ -307,14 +331,18 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
Console.WriteLine($" ---@deprecated {obsolete.Message}");
|
||||
|
||||
var parameters = methodInfo.GetParameters();
|
||||
foreach (var parameter in parameters)
|
||||
Console.WriteLine($" ---@param {parameter.EmmyLuaString()}");
|
||||
var luaParameters = parameters
|
||||
.Select(parameter => parameter.NameAndEmmyLuaString($"{memberInfo.DeclaringType.Name} {memberInfo.Name}"))
|
||||
.ToArray();
|
||||
foreach (var generic in luaParameters.Select(p => p.Generic).Where(g => !string.IsNullOrEmpty(g)).Distinct())
|
||||
Console.WriteLine($" ---@generic {generic}");
|
||||
foreach (var nameAndType in luaParameters.Select(p => p.NameAndType))
|
||||
Console.WriteLine($" ---@param {nameAndType}");
|
||||
|
||||
var parameterString = parameters.Select(p => p.Name).JoinWith(", ");
|
||||
|
||||
var returnType = methodInfo.ReturnType.EmmyLuaString();
|
||||
if (returnType != "Void")
|
||||
Console.WriteLine($" ---@return {returnType}");
|
||||
if (methodInfo.ReturnType != typeof(void))
|
||||
Console.WriteLine($" ---@return {methodInfo.ReturnTypeEmmyLuaString($"{memberInfo.DeclaringType.Name} {memberInfo.Name}")}");
|
||||
|
||||
if (duplicateMembers.Contains(methodInfo.Name))
|
||||
Console.WriteLine(" ---@diagnostic disable-next-line: duplicate-index");
|
||||
@@ -336,6 +364,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
foreach (var line in lines)
|
||||
Console.WriteLine($"{new string(' ', indentation * 4)}--- {line}");
|
||||
}
|
||||
else
|
||||
throw new NotSupportedException($"Missing {nameof(DescAttribute)} on {memberInfo.DeclaringType.Name} {memberInfo.Name}");
|
||||
|
||||
if (isActivity)
|
||||
Console.WriteLine(
|
||||
@@ -358,65 +388,90 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
{
|
||||
static readonly Dictionary<string, string> LuaTypeNameReplacements = new()
|
||||
{
|
||||
// These are weak type mappings, don't add these.
|
||||
// Instead, use ScriptEmmyTypeOverrideAttribute to provide a specific type.
|
||||
////{ "Object", "any" },
|
||||
////{ "LuaValue", "any" },
|
||||
////{ "LuaTable", "table" },
|
||||
////{ "LuaFunction", "function" },
|
||||
{ "Byte", "integer" },
|
||||
{ "UInt32", "integer" },
|
||||
{ "Int32", "integer" },
|
||||
{ "String", "string" },
|
||||
{ "String[]", "string[]" },
|
||||
{ "Boolean", "boolean" },
|
||||
{ "Double", "number" },
|
||||
{ "Object", "any" },
|
||||
{ "LuaTable", "table" },
|
||||
{ "LuaValue", "any" },
|
||||
{ "LuaValue[]", "table" },
|
||||
{ "LuaFunction", "function" },
|
||||
{ "WVec", "wvec" },
|
||||
{ "CVec", "cvec" },
|
||||
{ "CPos", "cpos" },
|
||||
{ "CPos[]", "cpos[]" },
|
||||
{ "WPos", "wpos" },
|
||||
{ "WAngle", "wangle" },
|
||||
{ "WAngle[]", "wangle[]" },
|
||||
{ "WDist", "wdist" },
|
||||
{ "Color", "color" },
|
||||
{ "Actor", "actor" },
|
||||
{ "Actor[]", "actor[]" },
|
||||
{ "Player", "player" },
|
||||
{ "Player[]", "player[]" },
|
||||
};
|
||||
|
||||
public static string EmmyLuaString(this Type type)
|
||||
public static string EmmyLuaString(this Type type, string notSupportedExceptionContext)
|
||||
{
|
||||
if (!LuaTypeNameReplacements.TryGetValue(type.Name, out var replacement))
|
||||
replacement = type.Name;
|
||||
if (type.IsArray)
|
||||
return EmmaLuaStringInner(type.GetElementType(), notSupportedExceptionContext) + "[]";
|
||||
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
return EmmaLuaStringInner(type, notSupportedExceptionContext);
|
||||
|
||||
static string EmmaLuaStringInner(Type type, string context)
|
||||
{
|
||||
var argument = type.GetGenericArguments().Select(p => p.Name).First();
|
||||
if (LuaTypeNameReplacements.TryGetValue(argument, out var genericReplacement))
|
||||
replacement = $"{genericReplacement}?";
|
||||
else
|
||||
replacement = $"{type.GetGenericArguments().Select(p => p.Name).First()}?";
|
||||
}
|
||||
if (LuaTypeNameReplacements.TryGetValue(type.Name, out var replacement))
|
||||
return replacement;
|
||||
|
||||
return replacement;
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
{
|
||||
var argument = type.GetGenericArguments()[0].Name;
|
||||
if (LuaTypeNameReplacements.TryGetValue(argument, out var genericReplacement))
|
||||
return $"{genericReplacement}?";
|
||||
}
|
||||
|
||||
if (type.IsEnum)
|
||||
return type.Name;
|
||||
|
||||
// This may indicate we are trying to export a type we have not added support for yet.
|
||||
// Consider adding support for this type.
|
||||
// This may mean updating WriteManual and adding IScriptBindable to the type.
|
||||
// Or adding an entry to LuaTypeNameReplacements.
|
||||
// Or use ScriptEmmyTypeOverride to provide a custom type for a parameter.
|
||||
// Or consider using ISuppressInitExport if the parameter is coming from an init we don't want to expose to Lua.
|
||||
// Or, it may need a different approach than the ones listed above.
|
||||
throw new NotSupportedException(
|
||||
$"Command lacks support for exposing type to Lua: `{type}` required by `{context}`. " +
|
||||
$"Consider applying {nameof(ScriptEmmyTypeOverrideAttribute)} or {nameof(ISuppressInitExport)}");
|
||||
}
|
||||
}
|
||||
|
||||
public static string EmmyLuaString(this ParameterInfo parameterInfo)
|
||||
public static string ReturnTypeEmmyLuaString(this MethodInfo methodInfo, string notSupportedExceptionContext)
|
||||
{
|
||||
var overrideAttr = methodInfo.ReturnTypeCustomAttributes
|
||||
.GetCustomAttributes(typeof(ScriptEmmyTypeOverrideAttribute), false)
|
||||
.Cast<ScriptEmmyTypeOverrideAttribute>()
|
||||
.SingleOrDefault();
|
||||
if (overrideAttr != null)
|
||||
return overrideAttr.TypeDeclaration;
|
||||
|
||||
return methodInfo.ReturnType.EmmyLuaString(notSupportedExceptionContext);
|
||||
}
|
||||
|
||||
public static (string TypeDeclaration, string GenericTypeDeclaration) EmmyLuaString(this ParameterInfo parameterInfo, string notSupportedExceptionContext)
|
||||
{
|
||||
var overrideAttr = parameterInfo.GetCustomAttribute<ScriptEmmyTypeOverrideAttribute>();
|
||||
if (overrideAttr != null)
|
||||
return (overrideAttr.TypeDeclaration, overrideAttr.GenericTypeDeclaration);
|
||||
|
||||
return (parameterInfo.ParameterType.EmmyLuaString(notSupportedExceptionContext), null);
|
||||
}
|
||||
|
||||
public static (string NameAndType, string Generic) NameAndEmmyLuaString(this ParameterInfo parameterInfo, string notSupportedExceptionContext)
|
||||
{
|
||||
var optional = parameterInfo.IsOptional ? "?" : "";
|
||||
|
||||
var parameterType = parameterInfo.ParameterType.EmmyLuaString();
|
||||
|
||||
// A hack for ActorGlobal.Create().
|
||||
if (parameterInfo.Name == "initTable")
|
||||
parameterType = "initTable";
|
||||
|
||||
return $"{parameterInfo.Name}{optional} {parameterType}";
|
||||
}
|
||||
|
||||
public static string EmmyLuaString(this PropertyInfo propertyInfo)
|
||||
{
|
||||
return $"{propertyInfo.Name} {propertyInfo.PropertyType.EmmyLuaString()}";
|
||||
var (typeDeclaration, genericTypeDeclaration) = parameterInfo.EmmyLuaString(notSupportedExceptionContext);
|
||||
return ($"{parameterInfo.Name}{optional} {typeDeclaration}", genericTypeDeclaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,8 +113,6 @@ WorldLoaded = function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(3), function()
|
||||
Harkonnen.MarkCompletedObjective(KillAtreides)
|
||||
end)
|
||||
|
||||
return true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -113,8 +113,6 @@ WorldLoaded = function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(3), function()
|
||||
Harkonnen.MarkCompletedObjective(KillAtreides)
|
||||
end)
|
||||
|
||||
return true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -138,8 +138,6 @@ WorldLoaded = function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(3), function()
|
||||
Ordos.MarkCompletedObjective(KillAtreides)
|
||||
end)
|
||||
|
||||
return true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -138,8 +138,6 @@ WorldLoaded = function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(3), function()
|
||||
Ordos.MarkCompletedObjective(KillAtreides)
|
||||
end)
|
||||
|
||||
return true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -113,8 +113,6 @@ WorldLoaded = function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(3), function()
|
||||
Harkonnen.MarkCompletedObjective(KillAtreides)
|
||||
end)
|
||||
|
||||
return true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -113,8 +113,6 @@ WorldLoaded = function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(3), function()
|
||||
Harkonnen.MarkCompletedObjective(KillAtreides)
|
||||
end)
|
||||
|
||||
return true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -113,8 +113,6 @@ WorldLoaded = function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(3), function()
|
||||
Harkonnen.MarkCompletedObjective(KillAtreides)
|
||||
end)
|
||||
|
||||
return true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -113,8 +113,6 @@ WorldLoaded = function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(3), function()
|
||||
Harkonnen.MarkCompletedObjective(KillOrdos)
|
||||
end)
|
||||
|
||||
return true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user