Lua is a scripting language most famously known for powering Blizzard’s World of Warcraft but was designed to be a general-purpose means of building robust, efficient, and lightweight solutions. Lua was created in 1993 (30 years ago!) and has since been popular among developers across all ecosystems. Lua is an excellent choice for folks because it is fast, portable, embeddable, small, and Free under an MIT license.
If you’ve ever dreamed about building extensibility into your applications, Lua is an excellent choice, as you can allow consumers to build scripts that work within your .NET host application. In this post, we’ll walk through the straightforward steps to add Lua support to your .NET applications, how you might invoke Lua scripts, and how you might let Lua scripts call your .NET methods.
Getting Started with MoonSharp
In a .NET console application, start by installing the MoonSharp
NuGet package.
dotnet add package MoonSharp
You can also add the following ItemGroup
to your .NET project file.
<ItemGroup>
<PackageReference Include="MoonSharp" Version="2.0.0" />
</ItemGroup>
After that, you should be ready to start writing your first Lua script.
As a bonus, if you’re using JetBrains Rider you’ll get Lua syntax highlighting with the language injections feature.
In your Program.cs
file, add the following code.
using MoonSharp.Interpreter;
// language=lua
var lua =
"""
print("Hello, Lua")
""";
Script.DefaultOptions.DebugPrint = Console.WriteLine;
Script.RunString(lua);
You should see the following output in your console when you run your Console application.
Hello, Lua
Setting the DebugPrint
property is necessary to allow MoonSharp to redirect print output somewhere. We chose the console in this case, but it could be directed to a string
, Stream
, or whatever.
Invoke a Lua Function from C#
Doing a print
call is fun, but we can be more practical. Let’s step it up by invoking a Lua add
method that takes two integer arguments.
using MoonSharp.Interpreter;
Script.DefaultOptions.DebugPrint = Console.WriteLine;
// language=lua
var lua =
"""
function add(x, y)
return x + y
end
""";
var script = new Script();
// loads and executes script
script.DoString(lua);
// call our global method
DynValue value = script.Call(script.Globals["add"], 1, 1);
Console.WriteLine($"1 + 1 is {value.Number}");
Here, we load a new function of add
that takes two number arguments. Remember, Lua is dynamically typed, so you won’t see any type declarations. We create a script
variable to reuse the context of our script, which now holds a global add function. We can use the script variable from here to invoke our global function and the necessary arguments. The DynValue
is a dynamic result, but there are helper properties you can use to type the result to a known .NET type. In this case, we’ll use the Number
property to get an integer value. Executing our application, we get the console output.
1 + 1 is 2
What if we want a Lua script to call our .NET application?
Invoking a C# Method from a Lua Script
MoonSharp allows you to inject elements into the global script context. In this section, we’ll provide our Lua script with an add method and do the addition in the scope of a C# code block.
using MoonSharp.Interpreter;
Script.DefaultOptions.DebugPrint = Console.WriteLine;
// language=lua
var lua =
"""
local result = add(1,1)
local output = string.format("1 + 1 is %s", result)
print(output)
""";
var script = new Script();
int add(int x, int y)
{
Console.WriteLine("Yep, I'm .NET baby!");
return x + y;
}
// load our C# method into global
script.Globals[nameof(add)] = add;
// loads and executes script
script.DoString(lua);
We pass the C# local function of add
as a Func<int,int,int>
to Lua. This allows Lua scripts to invoke the global method. Running the code above returns the following result.
Yep, I'm .NET baby!
1 + 1 is 2
Awesome!
Conclusion
We’ve only scratched the surface of what MoonSharp has to offer with Lua, but with these three demonstrations, you can see that the interoperability possibilities are through the roof. Leveraging MoonSharp you can build extensibility into your applications using a battle-hardened scripting language.
If you want to learn more about MoonSharp, visit the official site to see more samples and to read the official documentation.
Thanks for reading and sharing my posts with friends and colleagues.