Skip to content

Navigation Menu

Sign in
Sign up

Invoking C# code from within Lua? #2

Pinned Answered by Quahu
QuantumToasted asked this question in Q&A
Discussion options

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()?

You must be logged in to vote

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

Comment options

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.

You must be logged in to vote
2 replies
Comment options

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!

Comment options

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.

Answer selected by QuantumToasted
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /