How to Use Lua in Scripts

This page describes how to use Lua in your own scripts.


Easy-Access DialogueLua Methods

The PixelCrushers.DialogueSystem.DialogueLua class is the easiest way to access Lua data.

To get and set data in the standard Dialogue System Lua tables – Actor[], Item[], Location[] and Variable[] – use these methods:

Method Description Example
GetVariable() Get the value of a variable bool hasBox = DialogueLua.GetVariable("hasBox").AsBool
SetVariable() Set the value of a variable DialogueLua.SetVariable("hasBox", true);
GetActorField() Get the value of a field in an actor int xp = DialogueLua.GetActorField("Player", "XP").AsInt;
SetActorField() Set the value of a field in an actor DialogueLua.SetActorField("Player", "Intoxicated", true);
GetItemField() Get the value of a field in an item float weight = DialogueLua.GetItemField("Anvil", "Weight");
SetItemField() Set the value of a field in an item DialogueLua.SetItemField("Anvil", "Cost", 50);
GetQuestField() Get the value of a field in a quest. Equivalent to GetItemField() string state = DialogueLua.GetQuestField("Kill 5 Rats", "State").AsString;
SetQuestField() Set the value of a field in a quest. Equivalent to SetItemField() DialogueLua.SetQuestField("Kill 5 Rats", "State", "success");
GetLocationField() Get the value of a field in a location string desc = DialogueLua.GetLocationField("Moonbase", "Description");
SetLocationField() Set the value of a field in a location DialogueLua.SetLocationField("Moonbase", "Description", "A desolate lunar spaceport.");

The DialogueLua class automatically converts table indices' spaces and hyphens to underscores. When using the DialogueLua class, you can ignore the note in Important Note About Table Indices. (However, when bypassing the DialogueLua class and using the Lua class directly, you must remember to convert spaces and hyphens to underscores.)

The DialogueLua.GetXXX() methods return a Lua.Result value. To get a basic data type, use properties such as AsString, AsInt, AsFloat, and AsBool. For example:

int age = DialogueLua.GetActorField("Player", "Age").AsInt;

The Actor[], Item[], and Location[] tables are two-dimensional, meaning each element in the table has fields. Use the DialogueLua.GetXXXField() methods to access their fields.

The Variable[] table, on the other hand, is one-dimensional. The elements are regular data types (Boolean, string, number, etc.), so you cannot use the DialogueLua.GetXXXField() methods. Instead, use DialogueLua.GetVariable().

bool gotMilk = DialogueLua.GetVariable("Got Milk").AsBool;

Localization

To get the version of a field for the current language, use the localized versions of these methods:

Method Description
GetLocalizedActorField() Get the value of a localized field in an actor (e.g., "Description es" for Spanish)
SetLocalizedActorField() Set the value of a localized field in an actor
GetLocalizedItemField() Get the value of a localized field in an item
SetLocalizedItemField() Set the value of a localized field in an item
GetLocalizedQuestField() Get the value of a localized field in a quest. Equivalent to GetLocalizedItemField()
SetLocalizedQuestField() Set the value of a localized field in a quest. Equivalent to SetLocalizedItemField()
GetLocalizedLocationField() Get the value of a localized field in a location
SetLocalizedLocationField() Set the value of a localized field in a location

For example:

string localizedQuestName = DialogueLua.GetLocalizedQuestField("Kill 5 Rats", "Name").AsString;

Lua Class

The PixelCrushers.DialogueSystem.Lua class provides lower-level access to the Lua environment through these functions:

Method Description Example
Run() Run Lua code and return a Lua.Result structure int nextYear = Lua.Run("return Actor['Player'].Age + 1").AsInt;
IsTrue() Run Lua code and return true if the Lua result is true, otherwise false if (Lua.IsTrue("Actor['Player'].Age >= 21")) {...}
RegisterFunction() Register a C# method as a Lua function Lua.RegisterFunction("Exists", null, typeof(MyClass).GetMethod("Exists")); (*see below)

Return Values

Remember that Lua.Run() returns a Lua.Result that can be a Boolean, string, number, or table. To get the Boolean value, you need to add ".AsBool", as in this example:

if (Lua.Run("return Variable['Kissed_the_Frog']").AsBool) {
//(Player kissed the frog, so do something.)
}

Similarly, if your variable is a number, you can do this:

int myCoins = Lua.Run("return Variable['numberOfCoins']").AsInt);

Since Lua.IsTrue() always returns a Boolean value (true or false), you don't need to add AsXXX to the end:

if (Lua.IsTrue("Variable['Kissed_the_Frog']")) {
//(Player kissed the frog, so do something.)
}

Registering Functions

The RegisterFunction() method lets you tie your own C# code into the Lua environment. This is extremely handy to give your dialogue entry Conditions and Scripts new capabilities. (Use the corresponding UnregisterFunction() method to unregister the C# method from Lua.)

For example, say you want a dialogue entry to be available only when a certain GameObject named "White Elephant" is in the scene. You want to be able to set the dialogue entry's Conditions field to this:

  • Conditions: GameObjectExists("White Elephant")

Simply add this class to your scene:

public class MyLuaFunctions : MonoBehaviour {
void OnEnable() {
Lua.RegisterFunction("GameObjectExists", this, typeof(MyLuaFunctions).GetMethod("GameObjectExists"));
}
void OnDisable() {
Lua.UnregisterFunction("GameObjectExists");
}
public bool GameObjectExists(string name) {
return GameObject.Find(name) != null;
}
}

Data Types Allowed in Lua Functions

IMPORTANT: C# methods registered with Lua must use double for numbers, not float or int.

Only use these types in your Lua functions' parameters and return values:

Type Notes
double LuaInterpreter uses doubles for all number types; you can cast to (int), (float), etc inside your function if necessary
bool Use as normal
string Use as normal

Important Notes:

  1. Lua treats all numbers as double. In your C# methods, use double instead of float or int.
  2. Don't try to register more than one C# method with the same function name. For example, if you write a MonoBehaviour that registers a function, don't add that MonoBehaviour to multiple characters in the scene since each character will try to register the same function. In this case, you may want to add only one instance of the MonoBehaviour to the Dialogue Manager GameObject instead.

Starter Template Script for Custom Lua Functions

You can find a starter template script in Scripts/Templates/TemplateCustomLua.cs. To add your own Lua functions, you can make a copy of this template and customize it as indicated by the comments in the script.

Alternate Format for Windows Store/Phone Compatibility

For Windows Store/Windows Phone compatibility, you can use this alternate format to register Lua functions:

using PixelCrushers.DialogueSystem; // Include for SymbolExtensions class.
...
Lua.RegisterFunction("GameObjectExists", this, SymbolExtensions.GetMethodInfo(() => GameObjectExists(string.Empty)));

You may also prefer to use this format because it performs type validation on the function's parameters.


Lua Observers

In some cases, you may want to be notified when the value of a Lua variable changes.

The DialogueManager class lets you manage observers on Lua expressions using these methods:

Method Description Example
DialogueManager.AddLuaObserver() Add an observer on a Lua expression DialogueManager.AddLuaObserver("Variable['Credits']", LuaWatchFrequency.EveryDialogueEntry, OnCreditsChanged);
DialogueManager.RemoveLuaObserver() Remove an observer DialogueManager.RemoveLuaObserver("Variable['Credits']");
DialogueManager.RemoveAllLuaObservers() Remove all observers DialogueManager.RemoveAllLuaObservers();

AddLuaObserver()

Adds an observer on a Lua expression that will be checked on a specified frequency. The frequency can be EveryUpdate, EveryDialogueEntry, or EndOfConversation. If the expression changes, the Dialogue System will invoke a delegate that takes the form:

void MyDelegate(LuaWatchItem luaWatchItem, Lua.Result newValue) {...}

Example:

DialogueManager.AddLuaObserver("Variable['Credits']", LuaWatchFrequency.EveryDialogueEntry, OnCreditsChanged);
void OnCreditsChanged(LuaWatchItem luaWatchItem, Lua.Result newValue) {
Debug.Log("Number of credits changed to: " + newValue.AsInt);
}

Note: For best performance, limit the number of observers you set, especially when the frequency is EveryUpdate. Each observer requires an extra Lua call to evaluate the current state of the Lua expression.

RemoveLuaObserver()

Removes an observer. The observer is identified by the Lua expression, which should exactly match the same string that you passed to AddLuaObserver().

RemoveAllLuaObservers()

Removes all observers.


Note about Lua & Dialogue Database Loading

The Dialogue System delays loading of the master dialogue database until the data is needed. This avoids potentially long delays during Start() if you have a very large initial database. If you want to load the database manually (for example to run Lua commands on its contents) before the database has been used for a conversation, bark, or sequence, call DialogueManager.PreloadMasterDatabase() first.


Lua Under the Hood

The Dialogue System uses Liu Junfeng's Lua Interpreter (http://www.codeproject.com/Articles/228212/Lua-Interpreter), available under MIT License. The included version of Lua Interpreter has been modified to be compatible with Windows Store and Windows Phone projects. It also does not implement the following functions:

  • basic library: collectgarbage(), load(), rawequal(), rawlen(), rawset(), xpcall()
  • coroutines library: all functions
  • modules library: all functions
  • string library: dump(), format(), gmatch, gsub, match
  • table library: pack(), unpack()
  • bit32 library: all functions
  • input library: functions defined but disabled (to prevent malicious code insertion)
  • os: functions defined but disabled (to prevent malicious code insertion)
  • debug: all functions

    Historical Note: Versions 1.0 - 1.2.4.2 used George Foot's KopiLuaInterface (https://github.com/gfoot/kopiluainterface), which is another excellent Lua implementation. However, it heavily uses a programming technique called reflection that is not fully supported in the restrictive Windows Store and Windows Phone environments. This prompted a switch to Lua Interpreter.

The Dialogue System provides a PixelCrushers.DialogueSystem.Lua wrapper class which isolates the actual Lua implementation from the rest of the Dialogue System. If you want to use a different Lua implementation, you only need to replace these classes:

  • Lua.cs: The main wrapper class.
  • LuaTableWrapper.cs: A wrapper that allows you to handle Lua tables similarly to C# dictionaries.
  • DialogueLua.cs: Contains some Lua Interpreter-specific optimizations.

If you use Unity Pro or Unity 5+, you can opt to switch to NLua. For instructions, see the Using NLua page.


<< Special Lua Variables & Functions | Lua Examples >>

PixelCrushers.DialogueSystem.DialogueTriggerEvent.OnDisable
Trigger when the GameObject is disabled
PixelCrushers.DialogueSystem.Lua
A static class that provides a global Lua virtual machine.
Definition: Lua.cs:13
PixelCrushers.DialogueSystem.DialogueTriggerEvent.OnEnable
Trigger when the trigger script is enabled (allows retriggering if you disable and re-enable the scri...
PixelCrushers.DialogueSystem
Definition: ArticyConverterWindow.cs:8
PixelCrushers
Definition: ArticyConverterWindow.cs:8
PixelCrushers.DialogueSystem.Lua.RegisterFunction
static void RegisterFunction(string functionName, object target, MethodInfo method)
Registers a C# function with the Lua interpreter so it can be used in Lua.
Definition: Lua.cs:228
PixelCrushers.DialogueSystem.LuaWatchFrequency
LuaWatchFrequency
Lua watch frequencies.
Definition: LuaWatchers.cs:10