What is GopherLua?
mastergoto statement from Lua 5.2) written entirely in Go. Its primary purpose is to provide a scripting language with extensible semantics that can be easily embedded into Go host programs via a user-friendly Go API.repository·master·Indexed 12 days ago
https://github.com/heroiclabs/nakamaA distributed server for social and realtime games and apps, providing multiplayer, chat, social graphs, and storage. It is scalable and extensible with custom logic in Lua, TypeScript/JavaScript, or Go. Features include a REST API for user authentication, an embedded management console, and support for deployment via Docker or native binaries.
goto statement from Lua 5.2) written entirely in Go. Its primary purpose is to provide a scripting language with extensible semantics that can be easily embedded into Go host programs via a user-friendly Go API.All data in GopherLua is represented by the LValue interface. You can interact with these values in Go using type assertions or the Type() method.
Important Note: LBool, LNumber, and LString are not pointers. To test for LNilType or LBool, you must use the pre-defined constants lua.LNil or lua.LTrue/lua.LFalse.
| Type name | Go type | Type() value | Constants |
|---|---|---|---|
LNilType | (constants) | LTNil | LNil |
LBool | (constants) | LTBool | LTrue, LFalse |
LNumber | float64 | LTNumber | - |
LString | string | LTString | - |
LFunction | *struct | LTFunction | - |
LUserData | *struct | LTUserData | - |
LState | *struct | LTThread | - |
LTable | *struct | LTTable | - |
LChannel | chan LValue | LTChannel | - |
// Using type assertion
lv := L.Get(-1)
if str, ok := lv.(lua.LString); ok {
fmt.Println(string(str))
}
// Using Type()
if lv.Type() != lua.LTString {
panic("string required.")
}
// Correct way to check booleans/nil
if lv == lua.LTrue { /* ... */ }
// Using helper functions for Lua-style truthiness (nil and false are false)
if lua.LVIsFalse(lv) { /* ... */ }
if lua.LVAsBool(lv) { /* ... */ }GopherLua is a VM and compiler for Lua written in Go. While it aims for compatibility, there are several key differences from standard Lua:
channel type and a channel table providing channel functions.os.setenv(name, value) to set environment variables.goto and ::label:: statements.string.dump, os.setlocale, lua_Debug.namewhat, package.loadlib, and debug hooks are not supported.collectgarbage does not take arguments and triggers garbage collection for the entire Go program.file:setvbuf does not support line buffering.GopherLua supports Go channels via LChannel.
Concurrency Rules:
LState is not goroutine-safe. Use one LState per goroutine.LThread (state), LFunction, LUserData, or a LTable with a metatable.channel.make([buf:int]) -> ch:channel: Creates a channel with optional buffer size.channel:send(data:any): Sends data.channel:receive() -> ok:bool, data:any: Receives data.channel:close(): Closes the channel.channel.select(case:table, ...): Performs a select operation similar to Go.{"|<-", ch, handler_func}{"<-|", ch, data, handler_func}{"default", handler_func}-- Lua example of channel.select
local idx, recv, ok = channel.select(
{"|<-", ch1},
{"|<-", ch2}
)
if not ok then
print("closed")
elseif idx == 1 then
print(recv)
endTo store custom types in a skiplist, your type must implement a Less method. This method determines the sort order of the elements. The signature should be:
func (u *YourType) Less(other interface{}) bool
Return true if the current element should come before the other element in the sorted list.
Nakama supports developing native code in Go using the Go standard library plugin package. This allows you to compile shared objects (.so files) that the game server loads at startup.
Use the Go runtime to:
This provides the same capabilities as the Lua runtime but with the advantage of full Go ecosystem compatibility.
To create a new Go module for Nakama, follow these steps:
mkdir -p "$HOME/plugin_code"
cd "$HOME/plugin_code"go mod init and fetch the required nakama-common dependency.go mod init "plugin_code"
go get -u "github.com/heroiclabs/nakama-common@v1.23.0"⚠️ Version Warning: Official Nakama v3.12.+ expects nakama-common v1.23.0. Using older versions or omitting the version may result in a plugin was built with a different version of package error at startup. If working on Nakama's master branch, omit the @v1.23.0 suffix.
go mod init "plugin_code"
go get -u "github.com/heroiclabs/nakama-common@v1.23.0"If you want to build Nakama from source without regenerating protocol buffers, you can use a simple build process. All dependencies are vendored within the Go project. Ensure you have a modern Go toolchain installed.
# 1. Download the source tree
git clone "https://github.com/heroiclabs/nakama" nakama
cd nakama
# 2. Build the project from source
go build -trimpath -mod=vendor
./nakama --versionTo develop and test your plugin locally using the Nakama binary:
go build -buildmode=plugin -trimpath -o ./plugin_code.so--runtime.path flag to point to the directory containing your .so file../nakama --runtime.path "$HOME/plugin_code"Note: Ensure your database is also running.
go build -buildmode=plugin -trimpath -o ./plugin_code.so
./nakama --runtime.path "$HOME/plugin_code"To execute Lua code using GopherLua, create a new state using lua.NewState(), and then use DoString for raw strings or DoFile for loading .lua files. Always ensure you call L.Close() to clean up resources.
import (
"github.com/yuin/gopher-lua"
)
// Run a string
L := lua.NewState()
defer L.Close()
if err := L.DoString(`print("hello")`); err != nil {
panic(err)
}
// Run a file
if err := L.DoFile("hello.lua"); err != nil {
panic(err)
}You can install the cronexpr command-line utility using Go's get and install commands. This utility allows you to evaluate cron time expressions against a specific starting time.
go get github.com/gorhill/cronexpr
go install github.com/gorhill/cronexprThe Nakama server includes an embedded web UI for management and inspection. There is no separate installation required. You can use the console to:
By default, the console is accessible at: http://127.0.0.1:7351