2
\$\begingroup\$

There are some engines that can be scripted with different languages than that of which the engine, itself, is written with. How does that work?

\$\endgroup\$
  • \$\begingroup\$ What part you asking? Are you how asking how scripting works? How engines juggle scripting with non-scripted code? How engines in general work with extensibility? Which engine and which style/degree of scripting are you unsure about? What research into scriptable engines have you already performed? \$\endgroup\$ – Sean Middleditch Aug 16 '15 at 6:50
  • \$\begingroup\$ I am just wondering how the scripting works. Just kind of basically how the communication works on the low level. \$\endgroup\$ – Meeesh Aug 16 '15 at 6:53
  • \$\begingroup\$ hmm, okay. I felt like surely that question has been answered already, btu I honestly can't find a good one on Stackoverflow. I feel like you should still rephrase the question in terms of the specific parts you're unsure about; the question as it stands is very broad and would take an overly long and complex answer to fully explain. \$\endgroup\$ – Sean Middleditch Aug 16 '15 at 7:01
  • \$\begingroup\$ Essentially, I just want to know basically the communication between the engine and the scripts. I mostly work with just algorithms and back-end in applications, but I am getting into gamedev. I started gamedev about a year ago and I want to make a C++ engine and allow scripting for other languages. I generally have an idea of what I can do, but I am just wondering how things conventionally work to try do it in a solid, smooth, and efficient way. \$\endgroup\$ – Meeesh Aug 16 '15 at 7:46
6
\$\begingroup\$

There are many ways to implementing scripting in game engines, or applications in general.

Most conventional scripting languages are just like any other library. Just as libpng interprets a particular data format and provides APIs to read the results of processing that format, a scripting language library like Lua read in a particular format (Lua source code) and provides API for reading the results of interpreting that data. In general, compilers and interpreters are just like any other algorithm: they process input data and produce output data.

Scripting language libraries provide a means of binding functions from the host language into the script language and provide a means of calling a script function from the native code. There are myriad ways for this binding to work. Some scripting languages use a "foreign function interface" (FFI) that can allow the script language to directly call native functions by mapping integers and strings and such between the script language's representation and the native representations. Other language provide specialized abstractions, meaning that only particular native functions can be called from the scripts, requiring that wrapping binder functions be written. Other script languages (or helper libraries) can auto-generate those binder functions.

Examples:

FFI

LuaJIT has an FFI library that allows you to write this:

ffi.cdef[[int printf(const char *fmt, ...);]]
ffi.C.printf("Hello %s!", "world")

That allows the Lua script code to call any exported C function it wants.

Explicit Binding

With regular Lua, only C functions of the exact interface int(Lua_State* state) can be bound to the interpreter. In order to retrieve arguments, the programmer must use special functions provided by Lua. Likewise, to return values, the programmer must call particular functions. To bind a non-variadic printf function, the programmer would have to write something like:

int printf(Lua_State* state) { puts(lua_tostring(state, -1)); return 0; }

If there is a function such as int LoadLevel(char const* name) in the engine, the programmer would then have to write a wrapper int script_LoadLevel(Lua_state*) function that reads the Lua parameters and transfer them to the native C function.

Automatic Wrappers

In these APIs - which can be wrappers or helpers for libraries not intended for them - the user specifies the functions that should be exported to script in the native language and then a special tool or support code generates the binding functions. Languages like C don't make this innately possible, but you can build binding helpers in C++ or D or the like easily enough.

Tools like SWIG can read in C code and then generate binding code.

Since many game engines already have complex reflection systems to deal with I/O serialization, networking, level editors, or so on, they will reuse these reflection systems to generate script bindings with a library like Lua. A user might write a class like this:

class Player {
public:
  int GetHitPoints() const;
  void SetHitPoints(int hp);
};

and then bind this with reflection like so:

BEGIN_REFLECT(Player)
  PROPERTY("hp", GetHitPoints, SetHitPoints);
END_REFLECT(Player)

and then the scripting system might have some code like this:

void Reflect(ReflectedType& type)
{
  auto scriptType = CreateScriptType(type.GetName());
  for (auto& property : type.GetProperties())
    AddGetterSetter(
        scriptType,
        property.GetName(),
        property.GetGetter(),
        property.GetSetter()
    );
}

Summary

Game engines pick a scripting language and some library that implements that language. This in turn determines how the scripts are bound to the language.

Then the game engine decides what it wants to expose to the language and uses the appropriate method to bind the engine's functionality to the language.

There's many different types of scripting languages, some languages have multiple libraries that are bound in different ways, and engines can decide to expose different functionality in different ways (just like some game engines must be purely procedural/imperative and some might be object-oriented and some are functional and so on, likewise two different engines using Lua can decide to expose functionality in a procedural style or an OO style or whatever the way).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.