Lua Runtime #
The game server allows you to load and run custom logic written in Lua. This is useful to implement game code you would not want to run on the client, or trust the client to provide unchecked inputs on.
You can think of this Nakama feature as similar to Lambda or Cloud Functions in other systems. A good use case is if you wanted to grant the user a reward each day that they play the game.
Unlike when writing your server logic in Go or TypeScript, there is no toolchain or other setup needed when writing your code in Lua. Lua is a powerful embeddable scripting language and does not need to be compiled or transpiled. This makes it a good choice if you want to get up and running quickly and easily.
You can learn more about how to write your Lua code in the official documentation.
Develop code #
You can find the full Lua Nakama module function reference here.
Before you begin, create a new folder for your project and open it in an editor of your choice (e.g. VS Code).
Start by creating a new folder called
modules and inside create a new file called
main.lua. The code below is a simple Hello World example which uses the
"Logger" to write a message.
The Lua runtime is a Lua 5.1-compatible implementation with a small set of additional packages backported from newer versions - see available functions. For best results ensure your Lua modules and any 3rd party libraries are compatible with Lua 5.1.
The Lua virtual machine embedded in the server uses a restricted set of Lua standard library modules. This ensures the code sandbox cannot tamper with operating system input/output or the filesystem.
The list of available Lua modules are:
- base module
- Subset of
Global state #
The Lua runtime code is executed in instanced contexts (VM pool). You cannot use global variables as a way to store state in memory or communicate with other Lua processes or function calls.
Single threaded #
The use of multi-threaded processing (coroutines) is not supported in the Nakama implementation of the Lua runtime.
The Lua runtime code is fully sandboxed and cannot access the filesystem, input/output devices, or spawn OS threads or processes.
This allows the server to guarantee that Lua modules cannot cause fatal errors - the runtime code cannot trigger unexpected client disconnects or affect the main server process.
Error handling #
Lua error handling uses raised errors rather than error return values. If you want to trap the error which occurs in the execution of a function you’ll need to execute it via
pcall as a “protected call”.
will_error uses the
error function in Lua to throw an error with a reason message. The
pcall will invoke the
will_error function and trap any errors. We can then handle the success or error cases as needed. We recommend you use this pattern with your Lua code.
info(default level) or below, the server will return Lua stack traces to the client. This is useful for debugging but should be disabled for production.
Returning errors to the client #
When writing your own custom runtime code, you should ensure that any errors that occur when processing a request are passed back to the client appropriately. This means that the error returned to the client should contain a clear and informative error message and an appropriate HTTP status code.
Internally the Nakama runtime uses gRPC error codes and converts them to the appropriate HTTP status codes when returning the error to the client.
You can define the gRPC error codes as constants in your Lua module as shown below:
Global state #
The Lua runtime can use global variables as a way to store state in memory and store and share data as needed, but concurrency and access controls are the responsibility of the developer.
Sharing state is discouraged and should be avoided in your runtime code as it is not supported in multi-node environments.
Run the project #
You can use Docker with a compose file for local development or setup a binary environment for:
When this is complete you can run the game server and have it load your code:
The server logs will show this output or similar which shows that the code we wrote above was loaded and executed at startup.
Next steps #
Have a look at the Nakama project template which covers the following Nakama features: