How to use custom plugin modules with the cloned copy of Nakama

I am always getting this error:

plugin was built with a different version of package github.com/heroiclabs/nakama/api

Hi @kr-aman. The Go server runtime can be a little difficult with the setup of a development environment right now due to a few limitations in Go’s plugin package though we do have instructions here. I’ll run you through the two major approaches you can use to ensure your development environment is setup correctly.

Using Docker

We provide both Nakama and a helper image called the pluginbuilder to help with development of your custom server code in Go. This is the preferred way to develop your code. It contains the Go toolchain inside the container and can be used to run a build with the binaries copied to your host filesystem as a Linux shared object which can be run by our Docker compose instructions.

To demonstrate I’ll use a minimal Go file which looks like:

package main

import (
	"context"
	"database/sql"
	"github.com/heroiclabs/nakama/runtime"
)

func InitModule(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, initializer runtime.Initializer) error {
	logger.Info("custom engine loaded.")
	return nil
}

We’ll place this file in a folder for our project on our host filesystem like "$HOME/Projects/game_project". From that folder location we can then build a shared object with this command:

docker run --rm -v "$PWD:/go/src/custom_engine" -w "/go/src/custom_engine" heroiclabs/nakama-pluginbuilder:2.6.0 build --buildmode=plugin -o ./modules/custom_engine.so

The command above does a few different things so I’ll describe it for you:

  1. -v "$PWD:/go/src/custom_engine" - This mounts the current working directory into the container filesystem so your source code can be found by the Go compiler.
  2. -w "/go/src/custom_engine" - This changes the work directory to that location in the container.
  3. The output of the container is written back to the host filesystem under a folder called “modules”.

The rest of the command is just instructions to the Go compiler on how to build the code. These arguments are the same as you’d usually use to compile your Go code.

Finally we can check that the container can be run with this docker-compose file run from the same directory as our code.

docker-compose -f ./docker-compose-postgres.yml up

You should see a log line in the container logs which contains the message we wrote in the Go code above:

...
nakama      | {"level":"info","ts":"...","msg":"custom engine loaded."}
...

There are a few workflow improvements you can make at this point as you continue development:

  1. You could use Docker to restart the “nakama” container each time you do a new build of your code when you’ve got your containers started with Docker compose.
  2. You could write a multi-stage Docker file which will build your code with the pluginbuilder image and package it together with the main Nakama container. This is how we handle things for developers and studios on our Managed Cloud.

Using Go’s native toolchain

The second way you can develop your custom server code to be loaded by Nakama at startup is with the Go toolchain natively although this is a little quirky due to a few onerous restrictions from the current Go release (1.12) which are expected to be improved in Go 1.13.

I’ll assume you already have the Go toolchain installed and a GOPATH system variable set to your home folder (i.e. GOPATH="$HOME/go"). The location of your GOPATH doesn’t matter but it’s necessary to set it.

  1. Download and install the Nakama binaries at the correct version with go get:

    env GO111MODULE=off go get -d "github.com/heroiclabs/nakama"
    cd "$GOPATH/src/github.com/heroiclabs/nakama"
    git checkout v2.6.0
    env GO111MODULE=off go install
    

    This will build Nakama at the correct tag on your filesystem and install it to the GOBIN folder.

  2. We’ll create the project on our GOPATH. i.e. ("$GOPATH/src/game_project"). Navigate to your project folder. Use the same "main.go"file as above.

  3. Build the Go code as a shared object.

    env GO111MODULE=off go build --buildmode=plugin -o ./modules/custom_engine.so
    
  4. Run the shared object with Nakama server.

    NOTE You’ll need to run a database server either Postgres or cockroachdb. Refer to the native development instructions here for how to setup the database.

    $GOPATH/bin/nakama --logger.level DEBUG --runtime.path "$PWD/modules"
    
  5. Look for the same output as with the Docker workflow above.

    ...
    {"level":"info","ts":"...","msg":"custom engine loaded."}
    ...
    

The key to the development process with native builds is that the Nakama binary and your Go plugin code MUST have been built from the same system GOPATH. This restriction will be lifted in future versions of Go and will be helped as we move Nakama binaries to be built with Go modules (scheduled for the 2.7.0 release of the server).

Hope this helps.

1 Like