Spinning Topp Logo BlackTopp Studios
inc

Many scripting languages suitable for being embedded in games have a number of similar traits. All have some kind of runtime that must be initialized, this runtime accepts strings of script source and performs the steps the source desribe. Some keep internal track of the source, others expect the the caller to do so. Most allow passing arguments into scripts and accepting return values. Some allow the script to be compiled to a bytecode and others do not. A scripting manager is a generic interface to this functionality and is expected to be the primary interface for game developers who want to use a given scripting language.

Almost every language makes a point of interoperating with C. Some provide a special Application Prorammer Interface (API - intended for mostly programmers use) for C to call on like Ruby, Lua and AngelScript. Some take advantage of the reliable and unchanging C Application Binary Interface (ABI - primarily for direct executable to executable integration), such as Java, C#, Ruby when using FFI.

In addition to these kinds of complexities, there are different reasons to use a scripting language. The uses cases fall on a spectrum of "Writing a game in a Scripting language with just performance sensitive pieces in C/C++" to the other extreme of "The bulk of the code in C/C++ with the ability to run scripts for flexibilty". The are reasons for both of these use cases and they do not meaningfully conflict. Presumably any extra code written in the more performant C and C++ will benefit all, with the primary reason to not do so being time and technical skill required to do it. If something is already written this way, then why not take advantage of it.

The Interface of the scripting system was an attempt to allow enough flexibility to accomodate most scripting and managed languages, for the purpose of this discussion I mean any language with its own bytecode.

The scripting system is included the Mezzanine::Scripting namespace. It is primarily composed of four interface classes, four abstract classes. An implementation of a scripting system should implement these four classes in a sub-namespace:



SWIG ( http://swig.org ) is a tool that generates code in either C or the target language. It gets the information required to do this byreading the Mezzanine source code directly. It support a variety of languages but is currently

Whether or not the is updated each build can be controlled by the Mezz_SWIG CMake Flag. When this flag is enabled a SWIG_Mezzanine build target is added to the project. To satisfy build systems this target/project compiles src/blank.cpp as the only files. During the build steps in that target it attempt to Swig from the command line.

This can be run manually by invoking that target specifically. For example:

$ make SWIG_Mezzanine
$ ninja SWIG_Mezzanine

How the C++ API converts to Lua

The Documentation for the C++ API is also the canonical documentation for the Lua scripting system. The are some differences those that are not and these detailed on the functions that are different are generalized here.

Lua Modules are Related to Namespaces

Major namespaces become modules in Lua. You can check on the Lua51ScriptingEngine if there is a function for loading a specific namespace. For example if you want a script to use classes and functions in the Mezzanine::Threading namespace then you will need to load either the safe or the unlimited threading libraries in Lua. This can be done either by passing the right flags to the constructor of the Lua51ScriptingEngine or by calling Lua51ScriptingEngine::OpenMezzanineThreadingLibrary() or Lua51ScriptingEngine::OpenMezzanineThreadingSafeLibrary() . Each Module in Lua stores all of its members in a table of the module's name, and a reference to the table is stored in the Mezzanine table. This is preferred way to call Lua functionality from modules, and calling the table directly may be removed in the future. Here is an example of using a class in the Threading and another in the root namespace:

bar = MezzanineSafe.Threading.Barrier(4)
vec = MezzanineSafe.Vector3(1,1,1)



Other Namespaces Are Flattened

Namespaces are flattened into the Lua module they are included n: C++ code:



Lua Code:

Vec=MezzanineSafe.ConvertToVector3("3 4 6")



Enums Are Flattened

In C++ enumerations might hold values useful in the scope of class. For example the Mezzanine::Exception holds ExceptionCodes that are useful categorizing types of errors. Because each C++ class is represented in Lua as a function that returns a class instance, the syntax "MezzanineSafe.Exception.IO_EXCEPTION" could not work. Enums that are part of a class are instead defined in the same table as the class function and have the class name concatenated to theirs.
This is different than enums A few example can explain better: C++ code:

int x = Mezzanine::Exception::IO_EXCEPTION // An enum value on a class
int y = Mezzanine::Threading::NotStarted // An enum value in the Threading namespace



Lua Code:

x = MezzanineSafe.Exception_IO_EXCEPTION -- flattened to the MezzanineSafe Table/Module
y = MezzanineSafe.Threading.NotStarted -- In the Threading table/Module



Need to say something about modules in lua datatypes, singleton, vector3, quaternion, and the proxies are likely to be duplicate in multiple places