NewWorld

NewWorld creates a new World object.

func NewWorld(opts ...WorldOption) (*World, error)

Parameters

ParameterTypeDescription
opts…WorldOptionOptions for configuring the world.

Return Values

TypeDescription
*WorldA pointer to the newly created World instance.
errorAn error indicating any issues during creation.

Options

WithCustomMockRedis

The WithCustomMockRedis option uses the given miniredis instance as the storage layer for the game state. Game state saved to these instances of miniredis are not persistent across world restarts, so this should only be used for local development and testing.

func WithCustomMockRedis(miniRedis *miniredis.Miniredis) WorldOption
Parameters
ParameterTypeDescription
miniRedis*miniredis.MiniredisA miniredis instance.

WithDisableSignatureVerification

The WithDisableSignatureVerification option disables signature verification on the World’s server. This should only be used for testing.

func WithDisableSignatureVerification() WorldOption
Parameters

This method has no parameters.

WithPort

The WithPort option allows for a custom port to be set for the World’s server. If this option is unset it uses a default port of “4040”.

func WithPort(port string) WorldOption
Parameters
ParameterTypeDescription
portstringThe port number for the world’s server.

WithPrettyLog

The WithPrettyLog option enables JSON parsing and colorized, human-friendly formatted logs using zerolog.

func WithPrettyLog() WorldOption
Parameters

This method has no parameters.

WithReceiptHistorySize

The WithReceiptHistorySize option specifies the number of ticks for which the World object retains receipts. For instance, at tick 40 with a receipt history size of 5, the World stores receipts from ticks 35 to 39. Upon reaching tick 41, it will hold receipts for ticks 36 to 40. If this option remains unset, it defaults to a history size of 10. Game clients can get receipts via the /query/receipts/list endpoint. Nakama also uses this endpoint to transmit receipts to listening clients.

func WithReceiptHistorySize(size int) WorldOption
Parameters
ParameterTypeDescription
sizeintThe size of the receipt history to be set for World.

Setting a very large receipt history size may impact memory usage and performance. Choose a size that balances your game’s needs with resource constraints.

WithStoreManager

The WithStoreManager option overrides the default gamestate manager. The gamestate manager is responsible for storing entity and component information, and recovering those values after a world restart. A default manager will be created if this option is unset.

func WithStoreManager(s gamestate.Manager) WorldOption
Parameters
ParameterTypeDescription
sgamestate.ManagerThe replacement game-state manager.

WithTickChannel

The WithTickChannel option sets a channel that will be used to start each tick. A game tick will be started each time a message appears on the given channel. A custom tick rate can be set using time.Tick. This is also useful in tests to manually start ticks. If unset, a default tick rate of 1 per second is used.

func WithTickChannel(ch <-chan time.Time) WorldOption
Parameters
ParameterTypeDescription
ch<-chan time.TimeThe channel that will start each tick.
Example
// Example 1: Set tick rate to 500ms (2 ticks per second)
opt := WithTickChannel(time.Tick(500*time.Millisecond))

// Example 2: Set tick rate to 50ms (20 ticks per second) for fast-paced games
opt := WithTickChannel(time.Tick(50*time.Millisecond))

// Example 3: Use a custom channel for manual tick control in tests
tickCh := make(chan time.Time)
opt := WithTickChannel(tickCh)

Choose your tick rate carefully based on your game’s requirements. Higher tick rates provide smoother updates but require more processing power and network bandwidth.

WithTickDoneChannel

The WithTickDoneChannel option sets a channel that will receive the just-completed tick number each time a tick completes execution. All systems are guaranteed to have been called when a message appears on this channel. This is particularly useful in tests to ensure your systems have fully executed before checking expectations.

func WithTickDoneChannel(ch chan<- uint64) WorldOption
Parameters
ParameterTypeDescription
chchan<- uint64The channel that will be notified at the end of each tick.
Example
// Example usage in tests
func TestGameSystem(t *testing.T) {
    tickCh := make(chan time.Time)
    doneCh := make(chan uint64)

    world, _ := cardinal.NewWorld(
        WithTickChannel(tickCh),
        WithTickDoneChannel(doneCh),
    )

    // Start game in a goroutine
    go world.StartGame()

    // Trigger a tick
    tickCh <- time.Now()

    // Wait for tick to complete
    <-doneCh

    // Now safe to check game state
    // Your test assertions here...
}

The WithTickDoneChannel is essential for writing deterministic tests. Always wait for the done signal before making assertions about game state changes.

RegisterSystems registers one or more systems to the World. Systems are executed in the order of which they were added to the world.

func RegisterSystems(w *World, s ...cardinal.System)

Example

package main

import (
	"github.com/my-username/my-world-engine-project/systems"
	"pkg.world.dev/world-engine/cardinal"
)

func main() {
	// ... world setup ...

	// Systems will run in order in which they are added:
	// 1. MoveSystem
	// 2. HealthRegenSystem
	// 3. AttackSystem
	cardinal.RegisterSystems(world,
		systems.MoveSystem,
		systems.HealthRegenSystem,
		systems.AttackSystem)
}

RegisterInitSystems

RegisterInitSystems registers one or more init systems to the World. Init systems are executed exactly one time on tick 0. Init systems will not be run when loading a pre-existing world from permanent storage (e.g. on a server restart).

func RegisterInitSystems(world *World, s ...cardinal.System)

Example

package main

import (
	"github.com/my-username/my-world-engine-project/systems"
	"pkg.world.dev/world-engine/cardinal"
)

func main() {
	// ... world setup ...

	// Systems will be run one time on tick 0
	// 1. CreateEntities
	// 2. InitializeHealth
	cardinal.RegisterSystems(world,
		systems.CreateEntities,
		systems.InitializeHealth,
    )
}

Parameters

ParameterTypeDescription
world*WorldA pointer to a World instance.
s…SystemVariadic parameter for init systems to be added to the World.

RegisterComponents

RegisterComponents registers one or more components to the World. Upon registration, components are assigned an ID. IDs are assigned incrementally, starting from 0, in the order in which they were passed to the method.

func RegisterComponent[T metadata.Component](world *World) error

Example

package main

import (
	"log"
	"github.com/my-username/my-world-engine-project/component"
	"pkg.world.dev/world-engine/cardinal"
)

func main() {
	// ... world setup ...

	err := cardinal.RegisterComponent[LocationComponet](world)
	if err != nil {
		log.Fatal(err)
	}
	err = cardinal.RegisterComponent[AttackPowerComponent](world)
	if err != nil {
		log.Fatal(err)
	}
	err = cardinal.RegisterComponent[HealthComponent](world)
	if err != nil {
		log.Fatal(err)
	}

	// Alternative RegisterComponent pattern with less error checking:
	err = errors.Join(
		cardinal.RegisterComponent[LocationComponet](world),
		cardinal.RegisterComponent[AttackPowerComponent](world),
		cardinal.RegisterComponent[HealthComponent](world),
	)
	if err != nil {
		log.Fatal(err)
	}
}

Parameters

ParameterTypeDescription
Ttype parameterA component struct that implements the Name method.
world*WorldA pointer to a World instance.

Return Value

TypeDescription
errorAn error indicating any issues that occurred during the component registration.

RegisterQuery

RegisterQuery registers the queries in the World. This allows the Query endpoints to be automatically generated.

func RegisterQuery[Request, Reply any](
    world *World,
    name string,
    handler func(engine.Context, req *Request) (*Reply, error),
    opts ...QueryOption[Request, Reply]) error

Example

package main

import (
	"log"

	"github.com/my-username/my-world-engine-project/query"
	"pkg.world.dev/world-engine/cardinal"
)

func main() {
	// ... world setup ...

    err := cardinal.RegisterQuery[query.HealthRequest, query.HealthResponse](
		world,
        "query_health",
        func(worldCtx cardinal.WorldContext, req *query.HealthRequest) (reply *query.HealthReply, err error) {
			// ...fetch relevant health from worldCtx...
			return &HealthReply{}, nil
        })
    if err != nil {
		log.Fatal(err)
    }
}

Parameters

ParameterTypeDescription
Requesttype parameterThe input type of this query
Replytype parameterThe output type of this query
world*WorldA pointer to a World instance.
namestringThe name of the server endpoint to use this query
handlerfunc(engine.Context, *Request) (Reply, error)The handler to execute the logic of this query
opts…QueryOption[Request, Reply]Variadic options to augment the behavior of this query

Return Value

TypeDescription
errorAn error indicating any issues that occurred during the query registration.

RegisterMessages

RegisterMessages registers messages in the World. This allows message endpoints to be automatically generated.

func RegisterMessages(world *World, msgs ...AnyMessage) error

Example

package main

import (
	"log"

	"github.com/my-username/my-world-engine-project/msg"
	"pkg.world.dev/world-engine/cardinal"
)

func main() {
	// ... world setup ...

	err := cardinal.RegisterMessages(world,
		msg.Move,
		msg.Attack,
	)
	if err != nil {
		log.Fatal(err)
	}
}

Parameters

ParameterTypeDescription
world*WorldA pointer to a World instance.
msgs…AnyMessageVariadic parameter for Message instances to be registered.

Return Value

TypeDescription
errorAn error indicating any issues that occurred during the message registration.

StartGame

StartGame starts the game by loading any previously saved game state, spinning up the message/query handler, and starting the game ticks. This method blocks the main Go routine. If for whatever reason execution needs to continue after calling this method, it should be called in a separate go routine.

func (w *World) StartGame() error

Return Value

TypeDescription
errorAn error indicating any issues when starting the game.