In Cardinal, the main.go file is used as the entry point for your game shard implementation. This is where you will initialize your world and register your component, message, query, and system to it.

Example

A typical main.go file will look like this:

main.go
package main

import (
	"errors"
	"github.com/argus-labs/starter-game-template/cardinal/component"
	"github.com/argus-labs/starter-game-template/cardinal/msg"
	"github.com/argus-labs/starter-game-template/cardinal/query"
	"github.com/argus-labs/starter-game-template/cardinal/system"
	"github.com/rs/zerolog/log"
	"pkg.world.dev/world-engine/cardinal"
)

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

	// Register components
	// Components can be registered in any order. Each component must have a unique name.
	Must(
		// Example component registration - order doesn't matter
		cardinal.RegisterComponent[component.Player](w),
		cardinal.RegisterComponent[component.Transform](w),
		cardinal.RegisterComponent[component.Health](w),
		cardinal.RegisterComponent[component.Inventory](w),
	)

	// Register messages (user actions)
	// Message names should be descriptive and follow the pattern: "{action}_{target}"
	Must(
		// Player management messages
		cardinal.RegisterMessage[msg.CreatePlayerRequest, msg.CreatePlayerResponse](w, "create_player"),
		cardinal.RegisterMessage[msg.UpdatePlayerRequest, msg.UpdatePlayerResponse](w, "update_player"),

		// Combat messages
		cardinal.RegisterMessage[msg.AttackPlayerRequest, msg.AttackPlayerResponse](w, "attack_player"),
		cardinal.RegisterMessage[msg.DefendPlayerRequest, msg.DefendPlayerResponse](w, "defend_player"),
	)

	// Register queries
	// NOTE: You must register your queries here for it to be accessible.
	Must(
		cardinal.RegisterQuery[query.WorldVarsRequest, query.WorldVarsResponse](w,
		"world-vars",
		query.WorldVars,
	))

	// Register systems
	// Systems are executed sequentially in registration order.
	// Follow this recommended order:
	// 1. Input/Message processing systems
	// 2. Game state update systems
	// 3. Output/Effect systems
	Must(cardinal.RegisterSystems(w,
		// 1. Input processing
		system.MessageProcessingSystem,
		system.PlayerInputSystem,

		// 2. Game state updates
		system.MovementSystem,
		system.CombatSystem,

		// 3. Effects and outputs
		system.EffectSystem,
		system.NotificationSystem,
	))

	// Start the game shard
	// This will begin the game loop and start processing ticks
	Must(w.StartGame())
}

func Must(err ...error) {
	e := errors.Join(err...)
	if e != nil {
		log.Fatal().Err(e).Msg("")
	}
}