Skip to main content

C# calling Lua

Use LuaAppDomain.GetFunction<T> to obtain a bound Delegate by module and method name, then invoke it. The API is the same in Editor and Player.

Canonical: Bootstrap.cs

Basic usage

var main = LuaAppDomain.GetFunction<Action>("app", "main");
main();

var add = LuaAppDomain.GetFunction<Func<int, int, int>>("app", "add");
int sum = add(10, 20);
local function add(a, b)
return a + b
end

return {
main = main,
add = add,
}
RuleNotes
Call Initialize firstOtherwise an exception is thrown
T : MulticastDelegateConcrete Action / Func / custom delegates
module / method"app","add"return { add = ... }
CachingCache yourself on hot paths; same instance is not guaranteed
TimingMust be after Initialize; do not put in a static field initializer on the same type as RuntimeInitializeOnLoadMethod

Module loading

GetFunction("app", …) requires LoadLuaModule("app") to return source.

EnvironmentTypical path
Editor{ProjectRoot}/LuaScripts/app.lua
PlayerStreamingAssets/LuaScripts/app.lua.txt
private static string LoadLuaModule(string module)
{
#if UNITY_EDITOR
string path = Path.Combine(Application.dataPath, "..", "LuaScripts", module + ".lua");
#else
string path = Path.Combine(
Application.streamingAssetsPath, "LuaScripts", module + ".lua.txt");
#endif
return File.Exists(path) ? File.ReadAllText(path, Encoding.UTF8) : null;
}

Key points:

  • Modules must return { key = fn }; the key name = GetFunction’s method
  • Nested paths: module.Replace('.', '/') (e.g. battle.ai)
  • Sync before Player builds; see Build workflow
  • For hot reload / clearing the script world use LuaAppDomain.Reset(loader) (takes effect at EndOfFrame; old GetFunction delegates are invalid and must be rebound); no longer supports “swap loader only” on an already-initialized domain. Note StreamingAssets is read-only on Android

Multiple modules

var appMain = LuaAppDomain.GetFunction<Action>("app", "main");
var battleTick = LuaAppDomain.GetFunction<Action<float>>("battle", "tick");

Compared with “function as a parameter”

ScenarioApproach
C# actively calls a Lua-exported functionGetFunction<T>(module, method)
C# parameter is Action/Func, Lua passes functionImplicit marshal; see Function
Lua already has a function; need a specific delegate typezlua.to_delegate

Common mistakes

SymptomFix
module 'app' not foundEditor/Player paths; whether Sync ran
GetFunction result invalid / call has no effectNot Initialize’d; return-table key mismatch
Old scripts still runningPlayer not re-Synced

Learning path

PreviousLua calling C#
NextValue types