-
-
Notifications
You must be signed in to change notification settings - Fork 3
Invoking C# code from within Lua? #2
Is it possible via Laylua to define a method in Lua or behavior such that, when called, invokes a C# method?
As mentioned in my previous discussion, with the idea being an intermediate scripting language for a Discord bot, I would like the script to be able to, for example, reply or send a message in the context of a custom command.
-- defined in custom ILuaLibrary function send(msg) -- this would...call the C# code below? end -- elsewhere, in a custom command... a = 5 if (a ~= 42) then send("Hello!") end
And what it would call in C#:
// send(msg) should, as a simple example, send text to a user via this method // TODO: Lua doesn't really do async/await, so may need to be a void with .GetAwaiter().GetResult() and hope for the best public async Task SendAsync(string msg) { await discordClient.SendMessageAsync(/*something with msg*/); }
The goal here is to not have to re-invent the wheel by re-defining the entirety of Discord's REST API in Lua here. I could, if it came to it, utilize one of the various Discord Lua libraries, if compatible with 5.4.X, and import it here, but I'd be concerned about security issues with users trying to call functions they shouldn't, etc.
An alternative I'm considering, if this isn't possible, is out of scope for the library, or would be too much work, is expecting users to return a "message" object of sorts, which I would then have to...interpret, somehow. Is this a better alternative, or also possible: Returning a LuaTable from lua.Evaluate()?
All reactions
Yes, any delegate can be marshaled as a Lua function.
Here's an example that sets a global function which, when called, invokes Console.WriteLine(string):
lua.SetGlobal("print", (Action<string>) Console.WriteLine); lua.Execute("print('Hello, World!')");
The goal here is to not have to re-invent the wheel by re-defining the entirety of Discord's REST API in Lua here. I could, if it came to it, utilize one of the various Discord Lua libraries, if compatible with 5.4.X, and import it here, but I'd be concerned about security issues with users trying to call functions they shouldn't, etc.
I suggest creating wrapper functions that handle the necessary tasks. This approach introduces an inte...
Replies: 1 comment 2 replies
Yes, any delegate can be marshaled as a Lua function.
Here's an example that sets a global function which, when called, invokes Console.WriteLine(string):
lua.SetGlobal("print", (Action<string>) Console.WriteLine); lua.Execute("print('Hello, World!')");
The goal here is to not have to re-invent the wheel by re-defining the entirety of Discord's REST API in Lua here. I could, if it came to it, utilize one of the various Discord Lua libraries, if compatible with 5.4.X, and import it here, but I'd be concerned about security issues with users trying to call functions they shouldn't, etc.
I suggest creating wrapper functions that handle the necessary tasks. This approach introduces an intermediary layer between the .NET code and Lua, enabling you to implement features such as rate-limits for the calls and offloading the work to a dedicated worker thread.
Is this a better alternative, or also possible: Returning a LuaTable from lua.Evaluate()?
Regarding the alternative approach, it's up to you. Returning a LuaTable from lua.Evaluate() is indeed possible. Remember to dispose of it once you have finished working with it.
All reactions
Thanks for the followup, I did not know it was that simple to define functions to C# code!
Following up on this, is it possible to, using the method you described above, define methods that accept nil correctly? IE, if I wanted to have a method:
lua.SetGlobal("foo", (Action<long, long?>) Foo); void Foo(long id, long? otherId) { if (otherId.HasValue) { } }
Would it properly map calling foo(id, nil) in Lua? or should I expect users to pass 0 instead of nil and make the second parameter non-nullable? I'm not sure if this questions is more about understanding Lua itself or how Laylua handles it, so I thought I'd ask here just in case.
Edit: Through the power of Try It And See, I was able to determine that nil is properly passed as null where appropriate. Good to go from what I can tell!
All reactions
It's great to hear that you tried it out and it worked as expected!
Note that in addition to accepting nil as a parameter value, you can also make the parameter optional. By defining the parameter as long? otherId = null, it will default to null if no argument is provided for that parameter. This allows users to omit the second argument when calling the foo function in Lua.