Published: 24 Nov 2011
By: Xianzhong Zhu
Download Sample Code

Lua is a world-famous scripting language. It is a lightweight multi-paradigm programming language designed as a scripting language with extensible semantics as a primary goal. In this article, we are to explore how to integrate Lua into C# applications, especially WPF games.

Contents [hide]

Introduction

Lua is a world-famous scripting language. It is a lightweight multi-paradigm programming language designed as a scripting language with extensible semantics as a primary goal. A typical usage of Lua is to serve as an embedded script tool in a large application developed using C, C++, Java, C#, etc. In this article, we are to explore how to integrate Lua into C# applications, especially WPF games.

NOTE

The test environments we'll utilize in the sample applications include:

1. Windows 7;

2. .NET 4.0;

3. Visual Studio 2010;

4. LuaForWindows (version 5.1.4-45 at http://code.google.com/p/luaforwindows/), the famous Lua integration development tools on Windows;

5. LuaInterface (http://luaforge.net/projects/luainterface/).

Introducing Lua and LuaInterface

Lua was created in 1993 in Brazil. As a small scripting language, Lua is designed to be embedded inside applications in order to provide flexible expansion and customization. The most famous applications based upon Lua should be the online game "World of Warcraft" and the AngryBirds game release on the iOS platform.

Lua scripts can be easily called in C/C++ code. Lua can in turn call functions written using C/C++, which makes Lua widely used in applications. Lua can not only be used as an extension script but can be used as an ordinary configuration file, instead of XML, .ini, and other file formats, easier to understand and maintain.

Download and rebuild LuaInterface

LuaInterface is a library for integration between the Lua language and Microsoft .NET platform's Common Language Runtime (CLR). Lua scripts can use it to instantiate CLR objects, access properties, call methods, and even handle events with Lua functions. As of this writing, the latest version of LuaInterface is 2.0.3 compiled against lower version of .NET.

To use LuaInterface in the latest .NET 4.0, we have to rebuild the source code project. To do this, we can download the source project from here running the following command at the MS-DOS command line:

svn checkout http://luainterface.googlecode.com/svn/trunk/luainterface-read-only

NOTE

To successfully rebuild LuaInterface under .NET 4.0, you should remain the two files, App.config under the project LuaInterface.net35, and App.config under the project LuaRunner. If you remove these two files, you are sure to meet some error during the course of the build. The related reason and solution is simply given at somewhere at MSDN. I forgot taking it down; if you meet such an error, please search MSDN or leave message at the end of this file. To use LuaInterface more securely, you are suggested to use the assemble LuaInterface.dll and its buddy .dll.

A good news is within the project LuaInterface.Test, there is a file LuaTests.cs. In this file, there are a lot of test examples (based on XUnit and Mock) related to using LuaInterface in .NET CLR.

Now that the preconditions have been prepared, it is time to build some examples to illustrate how to combine LuaInterface with .NET projects.

Build the Console Sample project - LuaForCSharpTest

First off, create a new C# Console program and name it LuaForCSharpTest. For readers more clearly see the relations between the interested stuff, I create a folder LuaInterfaceStuff which holds the two file LuaInterface.dll and lua51.dll.

Now, add reference to LuaInterface.dll in the sample project, the other DLL should be automatically copied to the output folder with it.

As usual, let's add reference to the namespace defined in the assemble:

Let's next introduce the related tiny samples one by one.

Sample 1 - access global variables

To interact with Lua, we should first create an instance of the Lua virtual machine. And then we create the following .NET code to access the global variables defined in the .NET side (you can of course access those defined in Lua files - to be shown later).

There are only eight basic types defined in Lua, i.e. nil, boolean, number, string, userdata, function, thread, and table. The table type is like a magic, with which you can achieve more flexible and stronger data structures, and other fantastic features. Here, we defined some global variables, use the method NewTable to define a table and use the related method GetTable to access the table. As you may have guessed, all the global variables are held inside the property Globals of the Lua virtual machine. As for the method DoString, we'll discuss it in particular later on.

The running-time snapshot is shown in Figure 1.

Figure 1: The running-time snapshot for Sample 1

The running-time snapshot for Sample 1

Sample 2 - access functions and tables defined in Lua

In Lua, functions can be stored in variables, passed as arguments to other functions, and returned as results. With this definition, you can easily redefine a function to add new functionality, or simply erase a function to create a secure environment when running a piece of untrusted code. Moreover, Lua offers good support for functional programming. And also, functions play a key role in Lua's object- oriented programming.

On the other hand, table is similar to the associative array in C# and Java, but with more flexibility and efficiency. An associative array is an array that can be indexed not only with numbers, but also with strings or any other value of the language, except nil. By digging further, you will easily find that tables are virtually the only data structuring mechanism in Lua, with which you can represent ordinary arrays, symbol tables, sets, records, queues, and other data structures, in a simple, uniform, and efficient way.

Detailing into function and table is beyond the scope of this short article. Let's see a simple example concerning accessing Lua function and table via CLR.

First, we define a .lua file named LuaAdd.lua using SCiTE.

In the above script file, we defined two functions, three tables (named mytable1, color, and tree respectively), three global variables - width, height, and message.

NOTE

Please don't define the .lua file content with Visual Studio because the .lua file is not the simplest text file format as you image. So you are suggested to create .lua files using special .lua editor like SciTE (together with the Lua for windows package). If you create .lua file using Visual Studio you are sure to meet some error when running the application.

Now, let's see the CLR code dealing with the above Lua script.

The DoFile method loads and executes the Lua script. By digging into the anti-compiled code using ILSpy.exe (a good open-source .NET assembly browser and decompiler with which you can remove your .NET Reflector since it will become a commercial tool), I find GetFunction is just a simple helper method of the Lua class. The real work is finished in another class LuaFunction, which has a Call method to execute the target function, with two arguments (in this case), and return the function's return values inside an array.

With the GetTable method of class Lua and another class LuaTable, we can easily retrieve all the table related info defined in the Lua side as shown above. Figure 2 illustrates the related running-time screenshot.

Figure 2: The running-time snapshot for Sample 2

The running-time snapshot for Sample 2

Sample 3 - the DoString method

There is a Lua function called loadstring which is similar to another Lua function loadfile, except that it reads its chunk from a string, not from a file. As you image, the preceding DoFile method and another method DoString are just the correspondents of the Lua function loadfile and loadstring. Every time the method DoString is called, the compilation is executed, so although DoString is stronger it may result in huge overhead. Before using it please make sure that you cannot find simpler one to tackle your immediate problem.

Now, let's look at a related example.

As you've seen, we can within the method DoString do common Lua things. The corresponding running-time snapshot is given in Figure 3.

Figure 3: The running-time snapshot for Sample 3

The running-time snapshot for Sample 3

Sample 4 - calling of a function inside a table

As is mentioned previously, you can easily extend the current function of Lua using table. The following example gives a simple example, in which we define an empty object and also define a method for it. In fact, with this approach, we can achieve object-oriented programming support in Lua. Though, this is only a simple case; the real thing is associated with more details.

Let's look at the related CLR code.

The corresponding running-time snapshot is given in Figure 4.

Figure 4: The running-time snapshot for Sample 4

The running-time snapshot for Sample 4

Sample 5 - calling of a global function that returns two values

In this sample, we are going to use DoString method to construct a Lua function, and then call it using the Lua virtual machine. Through this example, you will further have an idea of the powerful feature of the DoString method.

The related running-time snapshot is shown in Figure 5.

Figure 5: The running-time snapshot for Sample 5

The running-time snapshot for Sample 5

Sample 6 - Test the RegisterFunction method

In this example, we will explore another powerful feature of LuaInterface. Via the RegisterFunction method of the Lua virtual machine class, we can register a CLR function to Lua, so that the Lua script can invoke the function as if it is an internal function. And at last, we will use the above means to test it.

First of all, let's define a simple C# method named outString outside the method Main.

This method simple sets the fore color of the Console and then output the incoming string.

Now, let's look at the first case in which we will register the above function within the Lua virtual machine and then invoke this method from the CLR side.

The running-time snapshot for Sample 6 case 1 is given below.

Figure 6: The running-time snapshot for Sample 6 case 1

The running-time snapshot for Sample 6 case 1

In the second case, we will invoke the above registered CLR function inside Lua script. Let's first look at the Lua script (named outStringTest.lua), as shown below.

Finally, we start to test in the C# side with the following code.

In this case, we invoke the method DoFile of the Lua virtual machine to execute the above Lua script, so that the method outString1 gets invoked inside Lua. The second case related snapshot is shown in Figure 7 below.

Figure 7: The running-time snapshot for Sample 6 case 2

The running-time snapshot for Sample 6 case 2

In the above samples, you've seen how we can invoke Lua scripts from inside C# applications. In fact, as a high-efficiency embedded language, Lua can do far more than that. In the next section, you will see more complex samples where lua files can invoke other .lua files, components defined inside .NET assembles and even more...

Sample 7 - Invoking other .lua files, .NET assembles and more…

The following sample is adapted from the online LuaInterface samples (http://penlight.luaforge.net/packages/LuaInterface/). In most of the online samples, you would see Lua scripts inside C# application can easily interact with .NET libraries and related data structures. Now, let's take a look at a related example.

First, let's build up a Lua script file named Prompting.wlua which looks like this.

First note that require command is the generally-used higher-level function to load and run libraries in Lua. Roughly, require does the same job as dofile, but with two important differences. First, require searches for the file in a path; second, require controls whether a file has already been run to avoid duplicating the work. Because of these features, require is the preferred function in Lua for loading libraries.

Second, CLRForm.lua is a lua script file shipped together with LuaForWindows_v5.1.4- 45.exe, which is located under \Program Files\Lua\5.1\lua. The CLRForm module contains some very useful utilities for doing Windows Forms programming in Lua. In fact, by opening CLRForm.lua, you will notice it further call another module using require "CLRPackage". CLRPackage.lua is a helper script to simplify the explicit invocation of all the required types, which is also located under \Program Files\Lua\5.1\lua.

Third, PromptForString is a function defined in the file CLRForm.lua. In this case, we use the method PromptForString to prompt the user to enter some content and then call the delegate MessageBox to show a CLR dialog.

Finally, according to the online LuaInterface samples, the .wlua extension is associated with the GUI version wlua.exe while .lua is associated with the console version lua.exe. Though, in our self-built samples we can also use the .wlua files.

NOTE

To make our sample normally run, we copy the two files CLRForm.lua, and CLRPackage.lua at the project root folder while put the other .lua script files under the sub folder named scripts, all of whose "Build Action" property should be set to "Content" and the "Copy to Output Directory" to "Copy if newer".

Next, let's look at the .NET side programming.

There is only a simple DoFile method call; most of the work has been done in the Lua side.

The running-time snapshot is shown in Figure 8 and 9.

Figure 8: One of the running-time snapshots for Sample 7

One of the running-time snapshots for Sample 7

In this case, I input a simple string "Hi" at the textbox, and then you will see a related modal dialog like Figure 9.

Figure 9: The other running-time snapshot for Sample 7

The other running-time snapshot for Sample 7

As you will notice in the downloadable source project, there are still more samples in the file Program1.cs, which are nearly corresponding to the ones in the online samples. Nearly all of them have been passed in this sample project.

Integrate Lua into WPF Games

Embedded scripting language can give our application system more powerful flexibility and scalability. Take the world-famous network game World of Warcraft for example. This application used a bit more than 200K of Lua volume but gained a very fast computation speed. Nowadays, in Microsoft .NET platform, Lua can be widely applied to applications (such as WinForm, WebForm, WPF, etc.) which allow unsafe code. The good features of ease of use (no needing to consider the core module of complex logic, just using the simple script to complete the task can be specified), cross-platform (once compiled by the right script language can be free to migrate to other systems), and expansion of demand (in the function of the complement system and upgrade in the same play a pivotal role) makes Lua applicable over a wide variety of development areas.

Starting from this section, let's explore how to make WPF games interact with Lua.

First, start up Visual Studio 2010 and create a general WPF application named LuaInWPFGame based upon .NET 4.0.

Second, add a reference to LuaInterface in our WPF project. In our case, we use the afore-mentioned ready-made assemble LuaInterface.dll (together with the related file lua51.dll).

Next, let's take the popular chat scene in a WPF game as an example to introduce how to embed Lua inside a WPF application.

Set up Lua script

The first thing to do is to create a Lua script file (named Talk.lua). The script is responsible for storing the chat content, as well as making corresponding process according to the income parameters. And especially, the script will invoke a C# method, return the data to the code-behind .cs file, and eventually the contents are reflected to the UI interface. The complete script code is as follows:

The first variable content is a table, which is used to store all kinds of chat contents. Here I defined three sets of contents. As is shown, the method ShowTalk called another method RandomTalk that's defined in the C# site to achieve the target of displaying conversation contents onto the screen. Apparently, the RandomTalk method does not belong as part of the Lua script file. In this case, we illustrate to you how Lua calls C# method within a WPF application. Of course, we also need to register this method for the script in the background WPF C# code, so that the method can ultimately play the role.

NOTE

The Build Action of the script file Talk.lua should be set as "Embedded Resource" in the Properties dialog.

WPF C# programming

As the preceding C# Console samples, to use Lua inside WPF, we should first add necessary namespace reference.

Next, we define a Lua virtual machine class (as well as define other related variables used in the sample game):

Also note that we defined a Sprite array to represent the sprites to be rendered in the game scene. In this case, we will simple draw five game characters and let them chatter around a fire. Each character is described using the Sprite class (refer to the source code yourself).

Now, set up the C# method to be invoked with the Lua script.

Here, we randomly select a sprite and assign the passed in argument as his topic.

Now, we should register the above C# method to make Lua know it and all related info.

Since all the related details concerning registering the method have been covered previously, we are no more to delve into it. You've also seen after the registration we invoked the method DoFile of the lua virtual machine to load and run the script.

Till now, the core of the mechanism of embedding Lua script inside a WPF application has been introduced. Figure 10 gives one of the running-time snapshots.

Figure 10: One of the running-time snapshots of the WPF game

One of the running-time snapshots of the WPF game

Summary

In this article you learned the fundamental means of integrating Lua into C# based Console and WPF applications. Lua is a high-efficient embedded language based upon ANSI C. Lua offers many advanced features based upon the two components table and function; we cannot delve into all the interesting stuffs, but you can refer to other detailed Lua materials together with this tutorial to do further research.

<<  Previous Article Continue reading and see our next or previous articles Next Article >>

About Xianzhong Zhu

I'm a college teacher and also a freelance developer and writer from WeiFang China, with more than fourteen years of experience in design, and development of various kinds of products and applications on Windows platform. My expertise is in Visual C++/Basic/C#, SQL Server 2000/2005/2008, PHP+MyS...

This author has published 81 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category


Data binding to CLR objects in WPF
In this article, you will learn how to bind to a method of a CLR object in WPF.
Creating Video Clips in WPF
In this article we will see how we can clip videos with few kilobytes of memory being used by your h...
Styles in WPF
In this article, you will learn what are styles, how to create and use styles in WPF applications.
Cascading ListBox Using MVVM in WPF
In this article we will see how we could implement a List Box and using the powerful Model View View...
Storyboard Playing with Playlist Manager in WPF
In last article we achieved clipping videos out of the parent video. In this article we will see how...

You might also be interested in the following related blog posts


InfoStrat releases a Virtual Earth control for both WPF and Surface to CodePlex read more
Expression Products Added to MSDN read more
Host WPF Controls in Windows Forms read more
Using WPF, Virtual Earth, and WPF/E together... read more
More WPFE, Virtual Earth, and AJAX goodness! read more
Windows Forms Additions in the Next Version of .NET read more
WPF/E and Script# read more
ASPInsiders Public Notes - Scott Guthrie read more
You gotta love SeeWindowsVista read more
Top
 
 
 

Please login to rate or to leave a comment.