### Install World SDK using npm, yarn, pnpm, or bun
Source: https://world.dev/javascript/quickstart
Installs the World SDK package using various package managers. Ensure you have Node.js version 22 or higher and a package manager installed.
```bash
npm install @argus-labs/sdk
```
```bash
yarn add @argus-labs/sdk
```
```bash
pnpm add @argus-labs/sdk
```
```bash
bun add @argus-labs/sdk
```
--------------------------------
### Player Spawn Command Structure in Go
Source: https://world.dev/javascript/quickstart
Defines the structure for a 'player-spawn' command in Go, used on the Cardinal shard. This includes base command details and specific payload fields like authentication IDs, names, and coordinates. This is an example system component for handling the command sent by the SDK.
```go
type PlayerSpawnCommand struct {
cardinal.BaseCommand
ArgusAuthID string `json:"argus_auth_id"`
ArgusAuthName string `json:"argus_auth_name"`
X uint32 `json:"x"`
Y uint32 `json:"y"`
}
func (a PlayerSpawnCommand) Name() string {
return "player-spawn"
}
func PlayerSpawnSystem(state *SpawnPlayerSystemState) error {
// ... code omitted for brevity
}
```
--------------------------------
### Query API - Where Clause Examples
Source: https://world.dev/cardinal/build/query-api
Provides examples of using the 'where' clause for filtering query results based on component properties and logical conditions. Supports comparison, logical operators, and built-in functions from the Expr language.
```APIDOC
## POST /query (With Where Clause Examples)
### Description
Demonstrates various filtering capabilities using the 'where' clause in queries.
### Method
POST
### Endpoint
/query
### Parameters
#### Query Parameters
None
#### Request Body
- **find** (array of strings) - Required - A list of component names to search for.
- **match** (string) - Required - How to match components ('exact' or 'contains').
- **where** (string) - Required - An expression string for filtering results.
### Request Examples
**By Online Status:**
```json
{
"find": ["PlayerTag", "OnlineStatus"],
"match": "contains",
"where": "OnlineStatus.Online == true"
}
```
**By Name:**
```json
{
"find": ["PlayerTag", "Position"],
"match": "contains",
"where": "PlayerTag.Name == \"Alice\""
}
```
**By Nickname:**
```json
{
"find": ["PlayerTag"],
"match": "contains",
"where": "PlayerTag.Nickname contains \"admin\""
}
```
**By Online Status and Position:**
```json
{
"find": ["PlayerTag", "Position", "OnlineStatus"],
"match": "contains",
"where": "Position.X > 100 && Position.Y < 200 && OnlineStatus.Online == true"
}
```
**By PlayerTag ID:**
```json
{
"find": ["PlayerTag"],
"match": "contains",
"where": "PlayerTag.ID in [\"user1\", \"user2\", \"user3\"]"
}
```
**By Nickname Length and Position:**
```json
{
"find": ["PlayerTag", "Position"],
"match": "contains",
"where": "len(PlayerTag.Nickname) > 5 && Position.X + Position.Y < 500"
}
```
### Response
#### Success Response (200)
- **entities** (array of objects) - A list of entities matching the query criteria.
#### Response Example
```json
{
"entities": [
{
"id": "entityABC",
"PlayerTag": {"name": "AdminPlayer", "Nickname": "SuperAdmin", "ID": "user1"},
"Position": {"x": 50, "y": 50},
"OnlineStatus": {"Online": true}
}
]
}
```
```
--------------------------------
### Set up SDK instance in TypeScript/JavaScript
Source: https://world.dev/javascript/quickstart
Initializes the Argus Labs SDK by creating a configuration and then an SDK instance. This code is typically placed in a central file like `src/lib/sdk.ts` or `src/lib/sdk.js`. TypeScript is optional but recommended.
```typescript
import { createConfig, createSDK } from '@argus-labs/sdk'
// Basic configuration
export const config = createConfig()
// Create the SDK instance
export const world = createSDK(config)
```
--------------------------------
### Cardinal Command Struct Example
Source: https://world.dev/javascript/guides/command
Provides an example of a Go struct that defines a 'player-spawn' command. This Go struct serves as the backend definition, and its structure should be mirrored by the TypeScript interfaces used in the SDK for commands to ensure consistency and correct data transfer.
```go
type PlayerSpawnCommand struct {
cardinal.BaseCommand
ArgusAuthID string `json:"argus_auth_id"`
ArgusAuthName string `json:"argus_auth_name"`
Position struct {
X int `json:"x"`
Y int `json:"y"`
} `json:"position"`
}
func (c PlayerSpawnCommand) Name() string {
return "player-spawn"
}
```
--------------------------------
### Registering Cardinal Systems
Source: https://world.dev/cardinal/build/system/overview
Demonstrates how to register game systems with the Cardinal world. Systems can be registered to run at initialization (Init hook) or every game tick (default Update hook). This example shows spawning a player once and registering a player movement system.
```go
package main
import (
"github.com\/avage-d\/cardinal\/v2"
"path\/to\/your\/project\/system"
)
func main() {
world := cardinal.NewWorld()
// Spawn player at tick 0 (only once)
cardinal.RegisterSystem(world, system.PlayerSpawnerSystem, cardinal.WithHook(cardinal.Init))
// Register player movement system (runs every tick)
cardinal.RegisterSystem(world, system.PlayerMoveSystem)
world.StartGame()
}
```
--------------------------------
### Schema Validation Example with Valibot
Source: https://world.dev/javascript/guides/query
Provides an example of using the Valibot schema library for validating query responses. Similar to Zod, Valibot can be used to define expected data structures, ensuring the data returned from the SDK query conforms to the specified schema.
```typescript
import * as v from 'valibot'
const playersSchema = v.array(
v.object({
_id: v.number(),
playertag: v.object({
argus_auth_id: v.string(),
argus_auth_name: v.string(),
}),
position: v.object({
x: v.number(),
y: v.number(),
}),
})
)
const { data } = await shard.query({ find: ['playertag', 'position'] }, { schema: playersSchema })
```
--------------------------------
### Register a Shard Client with Argus Labs SDK
Source: https://world.dev/javascript/quickstart
Registers a shard client to connect to a specific Cardinal shard, enabling command sending, state querying, and event listening. This requires the SDK instance created previously.
```typescript
import { world } from './sdk'
export const shard = world.shard.register({
organization: 'argus',
project: 'demo',
shardId: 'cardinal-demo-game-1',
})
```
--------------------------------
### Initialize Cardinal World and Register Systems (Go)
Source: https://world.dev/cardinal/build/world/overview
Demonstrates the basic structure of a main.go file for a Cardinal game shard. It shows how to initialize a new world, register various systems (like PlayerSetUpdater, PlayerSpawnSystem, MovePlayerSystem, PlayerLeaveSystem, OnlineStatusUpdater), and optionally attach systems to specific hooks (e.g., PreUpdate).
```go
package main
import (
"github.com/argus-labs/monorepo/pkg/cardinal"
"github.com/argus-labs/monorepo/pkg/cardinal/examples/demo-game/system"
)
func main() {
world := cardinal.NewWorld()
// Example of using a hook. This hook runs before the main update phase.
// There are also other hooks:
// - Init (runs only once, at tick 0)
// - PreUpdate (runs before the main update phase)
// - Update (runs during the main update phase)
// - PostUpdate (runs after the main update phase)
cardinal.RegisterSystem(world, system.PlayerSetUpdater, cardinal.WithHook(cardinal.PreUpdate))
cardinal.RegisterSystem(world, system.PlayerSpawnSystem)
cardinal.RegisterSystem(world, system.MovePlayerSystem)
cardinal.RegisterSystem(world, system.PlayerLeaveSystem)
cardinal.RegisterSystem(world, system.OnlineStatusUpdater)
world.StartGame()
}
```
--------------------------------
### Position Component Definition (Go)
Source: https://world.dev/javascript/quickstart
This Go code defines the 'Position' component for World Engine, representing a player's coordinates in the game world. It includes X and Y integer fields and implements the Name() method, essential for component identification within World Engine.
```go
package component
type Position struct {
X int `json:"x"`
Y int `json:"y"`
}
func (Position) Name() string {
return "position"
}
```
--------------------------------
### Send Player Spawn Command using Argus Labs SDK
Source: https://world.dev/javascript/quickstart
Defines and sends a 'player-spawn' command to a registered Cardinal shard. This function takes command details as an argument and optionally logs any errors. It requires a pre-registered shard client and a defined command interface.
```typescript
import { shard } from './shard'
interface SpawnPlayerCommand {
name: 'player-spawn'
payload: {
argus_auth_id: string
argus_auth_name: string
x: number
y: number
}
}
// Call the following function from an event handler, e.g. a button
export async function spawnPlayer() {
const { error } = await shard.sendCommand({
name: 'player-spawn',
payload: {
argus_auth_id: 'abc123',
argus_auth_name: 'John Doe',
x: 100,
y: 200,
},
} satisfies SpawnPlayerCommand)
if (error) console.error(error)
}
```
--------------------------------
### Get Position Component from Entity in Cardinal (Go)
Source: https://world.dev/cardinal/build/system/component
Demonstrates how to retrieve a 'Position' component from an entity using the `Get` method in a Cardinal system. This function iterates through players, fetches their position, and logs the coordinates. It requires the `cardinal` and specific component packages.
```go
package system
import (
"github.com/argus-labs/monorepo/pkg/cardinal"
"github.com/argus-labs/monorepo/pkg/cardinal/examples/demo-game/component"
)
type GetPositionSystemState struct {
cardinal.BaseSystemState
Players PlayerSearch
}
func GetPositionSystem(state *GetPositionSystemState) error {
for entity, player := range state.Players.Iter() {
position := player.Position.Get()
state.Logger().Info().
Uint32("entity", uint32(entity.ID)).
Msgf("Player is at position X: %d, Y: %d", position.X, position.Y)
}
return nil
}
```
--------------------------------
### PlayerTag Component Definition (Go)
Source: https://world.dev/javascript/quickstart
This Go code defines the 'PlayerTag' component, used in World Engine to represent a player's unique identifier. It includes fields for Argus authentication ID and name, and implements the Name() method required by World Engine components.
```go
package component
type PlayerTag struct {
ArgusAuthID string `json:"argus_auth_id"`
ArgusAuthName string `json:"argus_auth_name"`
}
func (PlayerTag) Name() string {
return "playertag"
}
```
--------------------------------
### Query Player Data with World Engine SDK (TypeScript)
Source: https://world.dev/javascript/quickstart
This TypeScript function demonstrates how to query the world state to find player data, specifically their 'playertag' and 'position'. It uses the `shard.query` method from the Argus Labs SDK. The function handles potential errors and returns the retrieved data or null.
```typescript
import { Match } from '@argus-labs/sdk'
import { shard } from './shard'
export async function playerQuery() {
const { error, data } = await shard.query({
find: ['playertag', 'position'],
match: Match.CONTAINS,
})
if (error) {
console.error(error)
return null
}
return data
}
```
--------------------------------
### JSON Query using 'exact' Match Type
Source: https://world.dev/cardinal/build/query-api
Shows an example of the 'exact' match type in a JSON query. This method strictly returns entities that have precisely the listed components and no others.
```json
{
"find": ["PlayerTag", "Position"],
"match": "exact"
}
```
--------------------------------
### ECS Contains Match Type Example in Go
Source: https://world.dev/cardinal/build/system/search
Illustrates the 'ecs.Contains' match type in Go, which finds entities having at least the specified components. The example shows a search requiring 'PlayerTag' and 'Position', matching entities with these and potentially others.
```go
type PlayerSearch = ecs.Exact[struct {
Tag ecs.Ref[component.PlayerTag]
Position ecs.Ref[component.Position]
}]
```
--------------------------------
### Pattern Matching ConnectError Codes in TypeScript
Source: https://world.dev/javascript/guides/error-handling
Shows how to handle specific error types by matching against `ConnectError.code`. This example uses a switch statement to execute different logic based on the error code, such as redirecting to login for unauthenticated errors or scheduling a retry for unavailable services. It requires importing `ConnectError` and `Code` from '@argus-labs/sdk'.
```typescript
import { ConnectError, Code } from '@argus-labs/sdk'
const { error, data } = await shard.query({
// your query parameters
})
if (error) {
switch (error.code) {
case Code.Unauthenticated:
// Redirect to login
redirectToLogin()
break
case Code.PermissionDenied:
// Show access denied message
showAccessDeniedError()
break
case Code.NotFound:
// Handle missing resource
showNotFoundError()
break
case Code.Unavailable:
// Retry logic for temporary issues
scheduleRetry()
break
default:
// Handle other errors
showGenericError(error.message)
}
} else {
// Handle successful response
processData(data)
}
```
--------------------------------
### Configure Multiple Regions for SDK (TypeScript)
Source: https://world.dev/javascript/guides/multiple-regions
Configure multiple regions for the SDK by providing gateway URLs, display names, and optional latency simulation. This setup allows the SDK to automatically select the best region based on latency.
```typescript
import { createConfig, createSDK } from '@argus-labs/sdk'
const config = createConfig({
regions: {
'us-west-2': {
gatewayUrl: 'http://localhost:8080',
displayName: 'US West (Oregon)',
simulateLatencyCheckMs: 100, // optional, for development only
},
'eu-central-1': {
gatewayUrl: 'http://localhost:8081',
displayName: 'Europe (Frankfurt)',
simulateLatencyCheckMs: 300,
},
'ap-southeast-1': {
gatewayUrl: 'http://localhost:8082',
displayName: 'Asia Pacific (Singapore)',
simulateLatencyCheckMs: 200,
},
},
})
export const world = createSDK(config)
```
--------------------------------
### JSON Query with Length and Arithmetic Conditions
Source: https://world.dev/cardinal/build/query-api
An example of a JSON query that uses both a string length check and an arithmetic comparison within the 'where' clause to filter entities.
```json
{
"find": ["PlayerTag", "Position"],
"match": "contains",
"where": "len(PlayerTag.Nickname) > 5 && Position.X + Position.Y < 500"
}
```
--------------------------------
### Set Position Component on Entity in Cardinal (Go)
Source: https://world.dev/cardinal/build/system/component
Illustrates how to update a 'Position' component for an entity using the `Set` method in a Cardinal system. This example iterates through players and assigns a new `component.Position` with updated X and Y coordinates, logging the change. It depends on the `cardinal` and component packages.
```go
package system
import (
"github.com/argus-labs/monorepo/pkg/cardinal"
"github.com/argus-labs/monorepo/pkg/cardinal/examples/demo-game/component"
)
type SetPositionSystemState struct {
cardinal.BaseSystemState
Players PlayerSearch
}
func SetPositionSystem(state *SetPositionSystemState) error {
for entity, player := range state.Players.Iter() {
player.Position.Set(component.Position{X: 100, Y: 200})
state.Logger().Info().
Uint32("entity", uint32(entity.ID)).
Msg("Updated player position to X: 100, Y: 200")
}
return nil
}
```
--------------------------------
### JSON Query filtering by Online Status
Source: https://world.dev/cardinal/build/query-api
Provides a JSON query example that filters entities based on their online status, specifically looking for entities where 'OnlineStatus.Online' is true.
```json
{
"find": ["PlayerTag", "OnlineStatus"],
"match": "contains",
"where": "OnlineStatus.Online == true"
}
```
--------------------------------
### Create Basic SDK Configuration (TypeScript)
Source: https://world.dev/javascript/guides/configuration
Initializes the SDK configuration using `createConfig` and then creates the SDK instance with `createSDK`. This sets up the basic connection parameters for your application.
```typescript
import { createConfig, createSDK } from '@argus-labs/sdk'
const config = createConfig({
// Configuration options go here
})
export const world = createSDK(config)
```
--------------------------------
### JSON Query filtering by Nickname Substring
Source: https://world.dev/cardinal/build/query-api
An example of a JSON query that filters entities based on a substring match within their nickname, using the 'contains' operator in the 'where' clause.
```json
{
"find": ["PlayerTag"],
"match": "contains",
"where": "PlayerTag.Nickname contains \"admin\""
}
```
--------------------------------
### Get Current User with Argus Auth (TypeScript)
Source: https://world.dev/javascript/guides/authentication
Retrieves the currently authenticated user using `world.auth.getUser()`. Returns an AuthUser object if logged in, otherwise null. This is typically called in the main menu.
```typescript
import { world } from './sdk'
export function mainMenu() {
const user = world.auth.getUser()
console.log(user)
}
```
--------------------------------
### Basic useQuery Usage in React
Source: https://world.dev/javascript/react/use-query
Demonstrates the fundamental use of the useQuery hook to fetch player data from a World Engine shard. It handles different query states (idle, loading, error, success) and renders the player list. Requires the 'shard' client and basic query configuration.
```tsx
import { useQuery } from '@argus-labs/sdk/react'
import { Match } from '@argus-labs/sdk'
import { shard } from './shard'
function PlayerList() {
const { status, data, error } = useQuery({
shardClient: shard,
query: {
find: ['playertag', 'position'],
match: Match.CONTAINS,
},
})
if (status === 'idle') return null
if (status === 'loading') return
Loading players…
if (status === 'error') return Error: {error?.message}
return (
{data?.map((player) => (
-
{player.playertag.argus_auth_name} at ({player.position.x}, {player.position.y})
))}
)
}
```
--------------------------------
### Pattern Matching with Error Codes
Source: https://world.dev/javascript/guides/error-handling
Illustrates how to handle different types of errors by matching against specific `ConnectError.code` values using a switch statement.
```APIDOC
## Pattern Matching with Error Codes
### Description
This example demonstrates advanced error handling by using a `switch` statement to identify specific `ConnectError.code` values (e.g., `Unauthenticated`, `PermissionDenied`, `NotFound`, `Unavailable`) and executing distinct logic for each. A default case handles any other unexpected errors.
### Method
N/A (Client-side code snippet)
### Endpoint
N/A (Client-side code snippet)
### Parameters
N/A
### Request Example
```typescript
import { ConnectError, Code } from '@argus-labs/sdk';
const { error, data } = await shard.query({
// your query parameters
});
```
### Response
#### Success Response (200)
- **data** (any) - The data payload upon successful request.
#### Error Response
- **error** (ConnectError) - An object containing detailed error information, specifically the `code` property is used for matching.
### Response Example
**Success:**
```json
{
"data": {
"processed": true
}
}
```
**Error Handling Logic (Conceptual):**
```typescript
if (error) {
switch (error.code) {
case Code.Unauthenticated:
// Redirect to login
redirectToLogin();
break;
case Code.PermissionDenied:
// Show access denied message
showAccessDeniedError();
break;
case Code.NotFound:
// Handle missing resource
showNotFoundError();
break;
case Code.Unavailable:
// Retry logic for temporary issues
scheduleRetry();
break;
default:
// Handle other errors
showGenericError(error.message);
}
} else {
// Handle successful response
processData(data);
}
```
```
--------------------------------
### Basic JSON Query Structure
Source: https://world.dev/cardinal/build/query-api
Demonstrates the fundamental structure of a query to the Cardinal state, specifying components to find and a condition for filtering.
```json
{
"find": ["PlayerTag", "Health"],
"match": "contains",
"where": "Health.HP > 50"
}
```
--------------------------------
### Unsubscribing from Events in TypeScript
Source: https://world.dev/javascript/guides/subscribe-events
Provides an example of how to manage event subscriptions and unsubscribe from them when no longer needed. This pattern is typically used within a class managing resources, ensuring cleanup to prevent memory leaks. It relies on the `subscribeToPlayerEvents` function and the `UnsubscribeEventsResult` type from '@argus-labs/sdk'.
```typescript
import type { UnsubscribeEventsResult } from '@argus-labs/sdk'
// Assume subscribeToPlayerEvents is imported from elsewhere
// import { subscribeToPlayerEvents } from './eventSubscriptions'
class Game {
private unsubscribe: (() => Promise) | null = null
constructor() {}
async create() {
// this.unsubscribe = await subscribeToPlayerEvents()
}
async destroy() {
if (!this.unsubscribe) return
const { error } = await this.unsubscribe()
if (error) {
console.error('Failed to unsubscribe from events:', error)
}
}
}
// Placeholder for the actual subscribe function if not imported directly
async function subscribeToPlayerEvents() {
// Mock implementation for demonstration
console.log('Subscribing to events...');
return async () => {
console.log('Unsubscribing from events...');
return { error: null };
};
}
```
--------------------------------
### Create Entity with Components in Go
Source: https://world.dev/cardinal/build/system/entity
This Go code snippet demonstrates how to create multiple entities with associated components using the Cardinal engine. It iterates to create 10 players, assigning them a nickname and initial position. Ensure the 'github.com/argus-labs/monorepo/pkg/cardinal' package is available.
```go
package system
import (
"fmt"
"github.com/argus-labs/monorepo/pkg/cardinal"
"github.com/argus-labs/monorepo/pkg/cardinal/examples/demo-game/component"
)
type CreatePlayerSystemState struct {
cardinal.BaseSystemState
Players PlayerSearch
}
func CreatePlayerSystem(state *CreatePlayerSystemState) error {
for i := range 10 {
name := fmt.Sprintf("default-%d", i)
id, err := state.Players.Create(
component.PlayerTag{Nickname: name},
component.Position{X: 0, Y: 0},
)
if err != nil {
return err
}
state.Logger().Info().Uint32("entity", uint32(id)).Msgf("Created player %s", name)
}
return nil
}
```
--------------------------------
### Configure Production Multi-Regions (TypeScript)
Source: https://world.dev/javascript/guides/configuration
Sets up multiple regions for a production environment, specifying gateway URLs and display names for different geographical locations. This is crucial for global connectivity and performance.
```typescript
const config = createConfig({
regions: {
'us-west-2': {
gatewayUrl: 'https://us-west-2.gateway.example.com',
displayName: 'US West (Oregon)',
},
'eu-central-1': {
gatewayUrl: 'https://eu-central-1.gateway.example.com',
displayName: 'Europe (Frankfurt)',
},
},
})
```
--------------------------------
### Receive Player Death System Event in Go
Source: https://world.dev/cardinal/build/system/event
This Go code demonstrates how to receive system events, specifically player death events, within the Cardinal framework. It defines a system state that includes a `WithSystemEventReceiver` for `systemevent.PlayerDeath`. The `GraveyardSystem` function iterates over received player death events and creates a gravestone for each.
```go
package system
import (
"github.com/argus-labs/monorepo/pkg/cardinal"
"github.com/argus-labs/monorepo/pkg/cardinal/examples/basic/component"
systemevent "github.com/argus-labs/monorepo/pkg/cardinal/examples/basic/system_event"
)
type GraveyardSystemState struct {
cardinal.BaseSystemState
PlayerDeathSystemEvents cardinal.WithSystemEventReceiver[systemevent.PlayerDeath]
Graves GraveSearch
}
func GraveyardSystem(state *GraveyardSystemState) error {
// Iterate over all player-death system events received in the tick.
for event := range state.PlayerDeathSystemEvents.Iter() {
_, _ = state.Graves.Create(component.Gravestone{Nickname: event.Nickname})
}
return nil
}
```
--------------------------------
### Basic Error Handling
Source: https://world.dev/javascript/guides/error-handling
Demonstrates the fundamental approach to checking for and handling errors returned by an API call using the `{ error, data }` pattern.
```APIDOC
## Basic Error Handling
### Description
This example shows how to check the `error` field in the response object. If an error exists, its properties like `code`, `message`, and `rawMessage` are logged. Otherwise, the successful `data` is processed.
### Method
N/A (Client-side code snippet)
### Endpoint
N/A (Client-side code snippet)
### Parameters
N/A
### Request Example
```typescript
const { error, data } = await shard.query({
// your query parameters
});
```
### Response
#### Success Response (200)
- **data** (any) - The data payload upon successful request.
#### Error Response
- **error** (ConnectError) - An object containing detailed error information.
- **code** (number) - The specific error code.
- **message** (string) - The full error message, potentially including status code.
- **rawMessage** (string) - The error message without any prefix.
- **metadata** (object) - Response headers and trailers.
- **details** (any) - Additional error details.
- **cause** (Error) - The underlying cause of the error.
### Response Example
**Success:**
```json
{
"data": {
"key": "value"
}
}
```
**Error:**
```json
{
"error": {
"code": 3,
"message": "InvalidArgument: Invalid input provided.",
"rawMessage": "Invalid input provided.",
"metadata": {},
"details": null,
"cause": null
}
}
```
```
--------------------------------
### Error Handling for Subscriptions and Events in React with useSubscribeEvents
Source: https://world.dev/javascript/react/use-subscribe-events
Details how to implement comprehensive error handling for both the subscription itself and individual event callbacks using the `onError` prop within the `useSubscribeEvents` hook. This example manages connection status based on subscription and event processing errors.
```tsx
import { useSubscribeEvents } from '@argus-labs/sdk/react'
import { playerSpawnEvent } from './events'
import { shard } from './shard'
function GameEventsWithErrorHandling() {
const [connectionStatus, setConnectionStatus] = useState<'connected' | 'error' | 'connecting'>(
'connecting'
)
useSubscribeEvents({
shardClient: shard,
events: [
playerSpawnEvent({
onSuccess: (payload) => {
setConnectionStatus('connected')
console.log('Player spawned:', payload)
},
onError: (error) => {
console.error('Event processing error:', error)
},
}),
],
onError: (error) => {
console.error('Subscription error:', error)
setConnectionStatus('error')
},
})
return (
Connection: {connectionStatus}
{connectionStatus === 'error' &&
Failed to connect to game events
}
)
}
```
--------------------------------
### Multiple Event Subscriptions in React with useSubscribeEvents
Source: https://world.dev/javascript/react/use-subscribe-events
Shows how to subscribe to multiple different events simultaneously using a single `useSubscribeEvents` hook call. This example combines player spawn and movement events, demonstrating efficient handling of various real-time game updates within one component.
```tsx
import { useSubscribeEvents } from '@argus-labs/sdk/react'
import { playerSpawnEvent, playerMovementEvent } from './events'
import { shard } from './shard'
function GameEventHandler() {
const [notifications, setNotifications] = useState([])
const addNotification = (message: string) => {
setNotifications((prev) => [...prev.slice(-4), message]) // Keep last 5
}
useSubscribeEvents({
shardClient: shard,
events: [
playerSpawnEvent({
onSuccess: (payload) => {
addNotification(`${payload.argus_auth_name} spawned`)
},
onError: console.error,
}),
playerMovementEvent({
onSuccess: (payload) => {
addNotification(`${payload.argus_auth_name} moved`)
},
onError: console.error,
}),
],
})
return (
{notifications.map((notification, index) => (
{notification}
))}
)
}
```
--------------------------------
### Query API - Basic Query
Source: https://world.dev/cardinal/build/query-api
This endpoint allows clients to query the Cardinal state. Queries are read-only and retrieve information about entities, components, and world state. The 'find' field specifies the components to search for, 'match' defines how components are matched ('exact' or 'contains'), and the optional 'where' field allows for complex filtering using the Expr expression language.
```APIDOC
## POST /query
### Description
Allows clients to query the Cardinal state for entities based on specified components and filtering criteria.
### Method
POST
### Endpoint
/query
### Parameters
#### Query Parameters
None
#### Request Body
- **find** (array of strings) - Required - A list of component names to search for.
- **match** (string) - Required - How to match components. Accepts 'exact' or 'contains'.
- **where** (string) - Optional - An expression string for filtering results.
### Request Example
```json
{
"find": ["PlayerTag", "Health"],
"match": "contains",
"where": "Health.HP > 50"
}
```
### Response
#### Success Response (200)
- **entities** (array of objects) - A list of entities matching the query criteria. Each entity object may contain component data.
#### Response Example
```json
{
"entities": [
{
"id": "entity123",
"PlayerTag": {"name": "Player1"},
"Health": {"HP": 75}
}
]
}
```
```
--------------------------------
### Send Basic Player Spawn Command
Source: https://world.dev/javascript/guides/command
Demonstrates the simplest way to send a command to the shard to modify game state. This function sends a 'player-spawn' command with player details and coordinates. It checks for and logs any errors returned by the command.
```typescript
import { shard } from './shard'
export async function spawnPlayer() {
const { error } = await shard.sendCommand({
name: 'player-spawn',
payload: {
// TODO: when persona is implemented, we might not need to send auth id and name
argus_auth_id: 'abc123',
argus_auth_name: 'John Doe',
x: 100,
y: 200,
},
})
if (error) {
console.error(error)
return { error }
}
return { success: true }
}
```
--------------------------------
### Configure Development Server Region (TypeScript)
Source: https://world.dev/javascript/guides/configuration
Configures a specific region for a development server, typically running on localhost. This allows for targeted development testing.
```typescript
const config = createConfig({
regions: {
'dev-server': {
gatewayUrl: 'http://localhost:8080',
displayName: 'Development Server',
},
},
})
```
--------------------------------
### Initialize Region Manager and Auto-Selection (TypeScript)
Source: https://world.dev/javascript/guides/multiple-regions
Initialize the region manager to perform latency checks and automatically select the best region. The `initialize()` method returns an unsubscribe function for cleanup.
```typescript
import { world } from './sdk'
// Initialize and get cleanup function
const unsubscribe = world.regions.initialize()
// Clean up when done (e.g., game exits)
unsubscribe()
```
--------------------------------
### Iterate Entities Using Defined Search in Go
Source: https://world.dev/cardinal/build/system/search
Demonstrates how to use a defined search, 'PlayerSearch', to iterate over entities that have both 'PlayerTag' and 'Position' components. It retrieves and logs the nickname and position of each matched player entity.
```go
package system
import (
"github.com/argus-labs/monorepo/pkg/cardinal"
)
type PlayerSystemState struct {
cardinal.BaseSystemState
Players PlayerSearch
}
func PlayerSystem(state *PlayerSystemState) error {
for entity, player := range state.Players.Iter() {
tag := player.Tag.Get()
position := player.Position.Get()
state.Logger().Info().Msgf("Player %s is at %d, %d", tag.Nickname, position.X, position.Y)
}
return nil
}
```
--------------------------------
### Integrate React Devtool Component
Source: https://world.dev/javascript/react/devtool
This snippet shows how to import and use the Devtool component in a React application. It takes a `defaultOpen` prop to control its initial state. The Devtool is conditionally bundled for development environments only.
```typescript
import { Devtool } from '@argus-labs/sdk/react-devtool'
function App() {
return (
{/* Your other app content */}
)
}
```
--------------------------------
### Configure Default Localhost Region (TypeScript)
Source: https://world.dev/javascript/guides/configuration
Sets up the SDK configuration to default to a single `localhost` region if no specific regions are provided. This is useful for local development environments.
```typescript
const config = createConfig({
// No regions specified - defaults to localhost:8080
})
```
--------------------------------
### Handle Player Movement Command in Go System
Source: https://world.dev/cardinal/build/system/command
This Go code demonstrates how to handle the MovePlayerCommand within a Cardinal system. It uses MovePlayerCommands.Iter() to process incoming commands and accesses payload data and the command's originating persona. This is a fundamental pattern for game logic.
```go
package system
import (
"github.com/argus-labs/monorepo/pkg/cardinal"
)
type MovePlayerCommand struct {
cardinal.BaseCommand
// The payload of the command.
X uint32 `json:"x"`
Y uint32 `json:"y"`
}
func (MovePlayerCommand) Name() string {
// The name of the command. Clients specify the name when sending the command.
return "move-player"
}
type MovePlayerSystemState struct {
cardinal.BaseSystemState
MovePlayerCommands cardinal.WithCommand[MovePlayerCommand]
Players PlayerSearch
}
func MovePlayerSystem(state *MovePlayerSystemState) error {
// Iterate over all move-player commands received in the tick.
for cmd := range state.MovePlayerCommands.Iter() {
payload := cmd.Payload()
state.Logger().Info().Msgf("Player moved to %d, %d", payload.X, payload.Y)
// You can also access the persona associated with the command.
persona := cmd.Persona()
state.Logger().Info().Msgf("Command sent by persona %s", persona)
}
return nil
}
```
--------------------------------
### Emit Player Death System Event in Go
Source: https://world.dev/cardinal/build/system/event
This Go code demonstrates how to emit a player death system event. It defines an attack command and a system state that includes a player death event emitter. The `AttackPlayerSystem` function processes attack commands, and if a player's health drops to zero or below, it emits a `systemevent.PlayerDeath`.
```go
package system
import (
"github.com/argus-labs/monorepo/pkg/cardinal"
"github.com/argus-labs/monorepo/pkg/cardinal/examples/basic/component"
systemevent "github.com/argus-labs/monorepo/pkg/cardinal/examples/basic/system_event"
)
type AttackPlayerCommand struct {
cardinal.BaseCommand
Target string
Damage uint32
}
func (a AttackPlayerCommand) Name() string {
return "attack-player"
}
type AttackPlayerSystemState struct {
cardinal.BaseSystemState
AttackPlayerCommands cardinal.WithCommand[AttackPlayerCommand]
PlayerDeathSystemEvents cardinal.WithSystemEventEmitter[systemevent.PlayerDeath]
Players PlayerSearch
}
func AttackPlayerSystem(state *AttackPlayerSystemState) error {
// This is a contrived example for demonstration purposes.
// In a real implementation, you would want to avoid the nested loop
// by using a more efficient lookup mechanism (e.g., a map or index).
// Iterate over all attack-player commands received in the tick.
for msg := range state.AttackPlayerCommands.Iter() {
// Iterate over all players in the state.
for entity, player := range state.Players.Iter() {
tag := player.Tag.Get()
if msg.Target != tag.Nickname {
continue
}
newHealth := player.Health.Get().HP - int(msg.Damage)
if newHealth > 0 {
player.Health.Set(component.Health{HP: newHealth})
} else {
entity.Destroy()
state.PlayerDeathSystemEvents.Emit(systemevent.PlayerDeath{Nickname: tag.Nickname})
}
}
}
return nil
}
```
--------------------------------
### Explicitly Define Localhost Region (TypeScript)
Source: https://world.dev/javascript/guides/configuration
Explicitly defines the `localhost` region with its gateway URL and display name. This provides a more detailed configuration than the default.
```typescript
const config = createConfig({
regions: {
localhost: {
gatewayUrl: 'http://localhost:8080',
displayName: 'Localhost',
},
},
})
```
--------------------------------
### Query API - Match Type: Exact
Source: https://world.dev/cardinal/build/query-api
Demonstrates the 'exact' match type, which returns entities possessing only the specified components. No additional components are allowed for a match.
```APIDOC
## POST /query (Match Type: Exact)
### Description
Queries entities that contain exactly the specified components, with no additional components present.
### Method
POST
### Endpoint
/query
### Parameters
#### Query Parameters
None
#### Request Body
- **find** (array of strings) - Required - A list of component names to search for.
- **match** (string) - Required - Must be 'exact'.
- **where** (string) - Optional - An expression string for filtering results.
### Request Example
```json
{
"find": ["PlayerTag", "Position"],
"match": "exact"
}
```
### Response
#### Success Response (200)
- **entities** (array of objects) - A list of entities matching the query criteria.
#### Response Example
```json
{
"entities": [
{
"id": "entity789",
"PlayerTag": {"name": "Player3"},
"Position": {"x": 30, "y": 40}
}
]
}
```
```
--------------------------------
### Define Player Movement Command in Go
Source: https://world.dev/cardinal/build/system/command
This Go code defines a command for player movement, embedding cardinal.BaseCommand and implementing the Name() method. It includes X and Y coordinates as the command's payload. This structure is essential for clients to send movement requests.
```go
package system
import (
"github.com/argus-labs/monorepo/pkg/cardinal"
)
type MovePlayerCommand struct {
cardinal.BaseCommand
// The payload of the command.
X uint32 `json:"x"`
Y uint32 `json:"y"`
}
func (MovePlayerCommand) Name() string {
// The name of the command. Clients specify the name when sending the command.
return "move-player"
}
```
--------------------------------
### Emit PlayerMovement Event in Go System
Source: https://world.dev/cardinal/build/system/event
Implements a system that processes `MovePlayerCommand` and emits a `PlayerMovement` event. This Go code demonstrates how to set player position and use the `Emit` method from a `cardinal.WithEvent` field within system state.
```go
package system
import (
"github.com/argus-labs/monorepo/pkg/cardinal"
"github.com/argus-labs/monorepo/pkg/cardinal/examples/demo-game/component"
"github.com/argus-labs/monorepo/pkg/cardinal/examples/demo-game/event"
)
type MovePlayerCommand struct {
cardinal.BaseCommand
Nickname string `json:"nickname"`
X uint32 `json:"x"`
Y uint32 `json:"y"`
}
func (a MovePlayerCommand) Name() string {
return "move-player"
}
type MovePlayerSystemState struct {
cardinal.BaseSystemState
MovePlayerCommands cardinal.WithCommand[MovePlayerCommand]
PlayerMovementEvent cardinal.WithEvent[event.PlayerMovement]
Players PlayerSearch
}
func MovePlayerSystem(state *MovePlayerSystemState) error {
// This is a contrived example for demonstration purposes.
// In a real implementation, you would want to avoid the nested loop
// by using a more efficient lookup mechanism (e.g., a map or index).
// Iterate over all move-player commands received in the tick.
for msg := range state.MovePlayerCommands.Iter() {
// Iterate over all players in the state.
for entity, player := range state.Players.Iter() {
tag := player.Tag.Get()
if msg.Nickname != tag.Nickname {
continue
}
player.Position.Set(component.Position{X: int(msg.X), Y: int(msg.Y)})
state.PlayerMovementEvent.Emit(event.PlayerMovement{
Nickname: tag.Nickname,
X: msg.X,
Y: msg.Y,
})
}
}
return nil
}
```
--------------------------------
### Handle Command Errors
Source: https://world.dev/javascript/guides/command
Illustrates how to handle errors returned from sending a command. The function executes a 'player-spawn' command and checks the response for an `error` object. If an error is present, it's logged to the console; otherwise, a success message is returned.
```typescript
export async function handleCommand() {
const { error } = await shard.sendCommand({
name: 'player-spawn',
payload: {
argus_auth_id: 'abc123',
argus_auth_name: 'John Doe',
x: 100,
y: 200,
},
})
if (error) {
console.error('Command failed:', error)
return { error }
}
return { success: true }
}
```
--------------------------------
### Register Shard Client (TypeScript)
Source: https://world.dev/javascript/guides/shard-client
Registers a shard client to connect to a specific World Engine shard. Requires organization, project, and shard ID. This client can then be used to send commands, query game state, and subscribe to events.
```typescript
import { world } from './sdk'
const shard = world.shard.register({
organization: 'argus', // corresponds to CARDINAL_ORG
project: 'demo', // corresponds to CARDINAL_PROJECT
shardId: 'cardinal-demo-game-1', // corresponds to CARDINAL_SHARD_ID
})
// You can create shard clients for different shards
```
--------------------------------
### Querying Entities Based on Match Types (CONTAINS, EXACT)
Source: https://world.dev/javascript/guides/query
Demonstrates how to use different 'match' types in queries. 'Match.CONTAINS' returns entities with at least the specified components, while 'Match.EXACT' returns entities with only the specified components. These options allow for precise entity selection based on component sets.
```typescript
// Returns entities with playertag + position + any other components
const { data } = await shard.query({
find: ['playertag', 'position'],
match: Match.CONTAINS, // Default behavior
})
```
```typescript
// Returns entities with only playertag + position components
const { data } = await shard.query({
find: ['playertag', 'position'],
match: Match.EXACT,
})
```
--------------------------------
### Basic Event Subscription in TypeScript
Source: https://world.dev/javascript/guides/subscribe-events
Demonstrates how to subscribe to a specific event type, 'player-spawn', using the World Engine SDK. It includes basic success and error handlers for received event payloads. Requires '@argus-labs/sdk' and a configured 'shard' object.
```typescript
import { createEventDefinition } from '@argus-labs/sdk'
import { shard } from './shard'
// Create event definition
const playerSpawnEvent = createEventDefinition({
name: 'player-spawn',
})
export async function subscribeToPlayerSpawn() {
const { error, unsubscribe } = await shard.subscribeEvents([
playerSpawnEvent({
onSuccess: (payload) => {
console.log('Player spawned:', payload)
},
onError: (error) => {
console.error('Event error:', error)
},
}),
])
if (error) {
console.error('Failed to subscribe:', error)
return null
}
return unsubscribe
}
```
--------------------------------
### Configure World Forge SDK for Development
Source: https://world.dev/javascript/guides/world-forge
Sets up the World Forge SDK with a development-specific region preset. This preset is optimized for development testing, typically including the 'us-west-2' region. It relies on the '@argus-labs/sdk' package.
```typescript
import { createConfig, createSDK, worldForgePresetDevelopment } from '@argus-labs/sdk'
const config = createConfig({
regions: worldForgePresetDevelopment,
})
export const world = createSDK(config)
```
--------------------------------
### Configure World Forge SDK for Production
Source: https://world.dev/javascript/guides/world-forge
Sets up the World Forge SDK with a production-ready region preset. This preset includes multiple regions across different continents (e.g., US West, US East, Asia Pacific, Europe) for global connectivity and high availability. It depends on the '@argus-labs/sdk' package.
```typescript
import { createConfig, createSDK, worldForgePresetProduction } from '@argus-labs/sdk'
const config = createConfig({
regions: worldForgePresetProduction,
})
export const world = createSDK(config)
```