Lua interop
Lua packages share values through Package.Export, which writes a global that every package can read. Exports is the
C# side of it.
Calling Lua from C#
Lua package
Package.Export("Leaderboard", {
Add = function(name, points) ... end,
Top = function(count) ... end,
})
Exports.Call("Leaderboard.Add", "DasDarki", 10);
var top = Exports.Call<string[]>("Leaderboard.Top", 3);
var table = Exports.Get("Leaderboard") as IDictionary;
Get converts the whole value, so keep a ScriptFunction for hot paths:
var add = Exports.Get<ScriptFunction>("Leaderboard.Add")!;
add.Invoke("DasDarki", 10);
C# callbacks passed to Lua functions are wrapped with ScriptCallback.From:
Exports.Call("Leaderboard.OnChange", ScriptCallback.From((string name) => Log.Info($"{name} changed")));
Calling C# from Lua
Mark a static class or a static method with [Export]:
[Export("MathLibrary")]
public static class MathLibrary
{
public static int Multiply(int first, int second) => first * second;
}
public static class Shouting
{
[Export]
public static string Shout(string text) => text.ToUpperInvariant();
}
print(MathLibrary.Multiply(6, 7))
print(Shout("hi"))
A static class becomes a table of its public static methods, a method a single global function. Values and delegates can also be exported by code:
Exports.Set("ServerStartedAt", DateTime.UtcNow.ToString("O"));
Exports.Set("Greet", (Func<string, string>)(name => $"hello {name}"));
Exports are removed when their package unloads. Lua packages should look them up when they need them instead of keeping a reference across a hot reload. Call exported functions with a dot, not a colon.