Queries are predefined API endpoints that provide access to the game state data and other information that a game client might need.

In Cardinal, queries are defined as a pair of Go structs representing a Request and Response along with a handler function with the following signature:

func Query(worldCtx cardinal.WorldContext, req *Request) (*Response, error)

Example:

  • A WorldVars static query used to provide the client with game constants.
  • A PlayerLocation query used to provide the client with the location of the player.

Defining Queries

By convention, queries are defined in the query directory with each query definition in its own separate file.

You can easily create a new query and register it to the world by following these steps:

1

Define the request/response struct and the handler function

A query is defined using a pair of Go structs and a handler function. You can write any arbitrary logic in the handler function and access the game state using cardinal.WorldContext.

/query/player_health.go
package query

import "pkg.world.dev/world-engine/cardinal"

type PlayerHealthRequest struct {
    Nickname string
}

type PlayerHealthResponse struct {
    HP int
}

func PlayerHealth(world cardinal.WorldContext, req *PlayerHealthRequest) (*PlayerHealthResponse, error) {
    // Handle PlayerHealthRequest -> PlayerHealthResponse here
}
2

Register the query in the world

Queries must be registered in the world before they can be used. This is done by calling the RegisterQuery function and passing in the name of the endpoint and the function handler.

main.go
package main

import (
    "pkg.world.dev/world-engine/cardinal"
    "github.com/argus-labs/starter-game-template/cardinal/query"
)

func main() {
    w, err := cardinal.NewWorld()
    if err != nil {
        log.Fatal().Err(err).Msg("failed to create world")
    }

    // Register queries
    // NOTE: You must register your queries here for it to be accessible.
    err := cardinal.RegisterQuery[query.PlayerHealthRequest, query.PlayerHealthResponse](w, "world-vars", query.PlayerHealth))
    if err != nil {
        log.Fatal().Err(err).Msg("failed to register query")
    }

    // ...
}

Query Options

EVM Support

Queries can be sent by EVM smart contracts by using the WithQueryEVMSupport option when you register your queries. This will generate the ABI types necessary for interactions with smart contracts.

import (
    "pkg.world.dev/world-engine/cardinal"
    qry "pkg.world.dev/world-engine/cardinal/query"
    "github.com/argus-labs/starter-game-template/cardinal/query"
)

cardinal.RegisterQuery[query.PlayerHealthRequest, query.PlayerHealthResponse](w, "player-health", 
    qry.WithQueryEVMSupport[query.PlayerHealthRequest, query.PlayerHealthResponse]())

Not all Go types are supported for the fields in your query structs when using this option. See EVM+ Message and Query to learn more.