Nakama Server

repository·master·Indexed 12 days ago

https://github.com/heroiclabs/nakama

A 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.

Tokens
8.9K
Snippets
33
Records
43
Agent score
92%

What's inside Nakama

  1. Understand the GopherLua Data Model (LValue)

    master

    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 nameGo typeType() valueConstants
    LNilType(constants)LTNilLNil
    LBool(constants)LTBoolLTrue, LFalse
    LNumberfloat64LTNumber-
    LStringstringLTString-
    LFunction*structLTFunction-
    LUserData*structLTUserData-
    LState*structLTThread-
    LTable*structLTTable-
    LChannelchan LValueLTChannel-
    // 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) { /* ... */ }
  2. Understand differences between Lua and GopherLua

    master

    GopherLua is a VM and compiler for Lua written in Go. While it aims for compatibility, there are several key differences from standard Lua:

    Supported Features

    • Goroutines: GopherLua supports channel operations via a channel type and a channel table providing channel functions.
    • Environment Variables: Use os.setenv(name, value) to set environment variables.
    • Lua 5.2 Syntax: Supports goto and ::label:: statements.

    Unsupported or Modified Features

    • Unsupported Functions: string.dump, os.setlocale, lua_Debug.namewhat, package.loadlib, and debug hooks are not supported.
    • Garbage Collection: collectgarbage does not take arguments and triggers garbage collection for the entire Go program.
    • File I/O: file:setvbuf does not support line buffering.
    • Time: Daylight saving time is not supported.
  3. Use Channels and Goroutines in GopherLua

    master

    GopherLua supports Go channels via LChannel.

    Concurrency Rules:

    • LState is not goroutine-safe. Use one LState per goroutine.
    • Communicate between goroutines using channels.
    • DO NOT send the following objects over channels: LThread (state), LFunction, LUserData, or a LTable with a metatable.

    Lua API for Channels

    • 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.
      • Receiving: {"|<-", ch, handler_func}
      • Sending: {"<-|", ch, data, handler_func}
      • Default: {"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)
    end
  4. Implement the Less method for skiplist elements

    master

    To 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.

  5. Use the Nakama Go Runtime

    master

    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:

    • Develop authoritative multiplayer match handlers.
    • Implement RPC functions.
    • Hook into messages processed by the server.
    • Extend the server with custom logic using any package from the Go ecosystem.

    This provides the same capabilities as the Lua runtime but with the advantage of full Go ecosystem compatibility.

  6. Setup a Nakama Go plugin project

    master

    To create a new Go module for Nakama, follow these steps:

    1. Install Go: Ensure the Go toolchain is installed on your system.
    2. Create a directory: Create a folder for your plugin code.
      mkdir -p "$HOME/plugin_code"
      cd "$HOME/plugin_code"
    3. Initialize the module: Run 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"
  7. Perform a Simple Build of Nakama

    master

    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 --version
  8. Build and load a Go plugin manually

    master

    To develop and test your plugin locally using the Nakama binary:

    1. Compile the plugin: Build your code as a plugin shared object.
      go build -buildmode=plugin -trimpath -o ./plugin_code.so
    2. Run Nakama: Start the Nakama server and use the --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"
  9. Run Lua scripts in GopherLua

    master

    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)
    }
  10. Access the Nakama Console

    master

    The Nakama server includes an embedded web UI for management and inspection. There is no separate installation required. You can use the console to:

    • Inspect data stored via APIs
    • View service metrics
    • Manage player data and storage objects
    • Manage realtime multiplayer matches
    • Use the API explorer

    By default, the console is accessible at: http://127.0.0.1:7351