cardinal

package module
v1.0.2-beta Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 5, 2023 License: LGPL-3.0 Imports: 29 Imported by: 4

README ¶

Cardinal 🦉

WIP

Documentation ¶

Index ¶

Examples ¶

Constants ¶

View Source
const (
	ModeProd             = "production"
	ModeDev              = "development"
	DefaultMode          = ModeDev
	DefaultNamespace     = "world-1"
	DefaultRedisPassword = ""
	DefaultRedisAddress  = "localhost:6379"
)

Variables ¶

View Source
var ErrEntitiesCreatedBeforeStartGame = errors.New("entities should not be created before start game")

Functions ¶

func AddComponentTo ¶

func AddComponentTo[T component.Component](wCtx WorldContext, id entity.ID) error

AddComponentTo Adds a component on an entity.

func GetComponent ¶

func GetComponent[T component.Component](wCtx WorldContext, id entity.ID) (*T, error)

GetComponent Get returns component data from the entity.

func RegisterComponent ¶

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

func RegisterMessages ¶

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

RegisterMessages adds the given messages to the game world. HTTP endpoints to queue up/execute these messages will automatically be created when StartGame is called. This Register method must only be called once.

func RegisterQuery ¶

func RegisterQuery[Request any, Reply any](
	world *World,
	name string,
	handler func(wCtx WorldContext, req *Request) (*Reply, error),
) error

RegisterQuery adds the given query to the game world. HTTP endpoints to use these queries will automatically be created when StartGame is called. This function does not add EVM support to the query.

func RegisterQueryWithEVMSupport ¶

func RegisterQueryWithEVMSupport[Request any, Reply any](
	world *World,
	name string,
	handler func(wCtx WorldContext, req *Request) (*Reply, error),
) error

RegisterQueryWithEVMSupport adds the given query to the game world. HTTP endpoints to use these queries will automatically be created when StartGame is called. This Register method must only be called once. This function also adds EVM support to the query.

func RegisterSystems ¶

func RegisterSystems(w *World, systems ...System) error

func Remove ¶

func Remove(wCtx WorldContext, id EntityID) error

Remove removes the given entity id from the world.

func RemoveComponentFrom ¶

func RemoveComponentFrom[T component.Component](wCtx WorldContext, id entity.ID) error

RemoveComponentFrom Removes a component from an entity.

func SetComponent ¶

func SetComponent[T component.Component](wCtx WorldContext, id entity.ID, comp *T) error

SetComponent Set sets component data to the entity.

func TestingWorldContextToECSWorld ¶

func TestingWorldContextToECSWorld(worldCtx WorldContext) *ecs.World

func UpdateComponent ¶

func UpdateComponent[T component.Component](wCtx WorldContext, id entity.ID, fn func(*T) *T) error

UpdateComponent Updates a component on an entity.

Types ¶

type AnyMessage ¶

type AnyMessage interface {
	Convert() message.Message
}

AnyMessage is implemented by the return value of NewMessageType and is used in RegisterMessages; any message created by NewMessageType can be registered with a World object via RegisterMessages.

type CreatePersonaTransaction ¶

type CreatePersonaTransaction = ecs.CreatePersona

The following type and function are exported temporarily pending a refactor of how Persona works with the different components of Cardinal.

type EntityID ¶

type EntityID = entity.ID

EntityID represents a single entity in the World. An EntityID is tied to one or more components.

func Create ¶

func Create(wCtx WorldContext, components ...component.Component) (EntityID, error)

Create creates a single entity in the world, and returns the id of the newly created entity. At least 1 component must be provided.

func CreateMany ¶

func CreateMany(wCtx WorldContext, num int, components ...component.Component) ([]EntityID, error)

CreateMany creates multiple entities in the world, and returns the slice of ids for the newly created entities. At least 1 component must be provided.

type Filter ¶

type Filter interface {
	// contains filtered or unexported methods
}

func All ¶

func All() Filter

func And ¶ added in v1.3.3

func And(filters ...Filter) Filter

func Contains ¶

func Contains(components ...component.Component) Filter

func Exact ¶

func Exact(components ...component.Component) Filter

func Not ¶ added in v1.3.3

func Not(filter Filter) Filter

func Or ¶ added in v1.3.3

func Or(filters ...Filter) Filter

type MessageType ¶ added in v1.3.3

type MessageType[Input, Result any] struct {
	// contains filtered or unexported fields
}

MessageType represents a type of message that can be executed on the World object. The Input struct represents the input, and the Result struct represents the result of processing the message.

Example ¶
//nolint:testableexamples // can figure this out later.
package main

import (
	"errors"
	"fmt"

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

type MovePlayerMsg struct {
	DeltaX int
	DeltaY int
}

type MovePlayerResult struct {
	FinalX int
	FinalY int
}

var MoveMsg = cardinal.NewMessageType[MovePlayerMsg, MovePlayerResult]("move-player")

func main() {
	world, err := cardinal.NewMockWorld()
	if err != nil {
		panic(err)
	}

	err = cardinal.RegisterMessages(world, MoveMsg)
	if err != nil {
		panic(err)
	}

	err = cardinal.RegisterSystems(world, func(wCtx cardinal.WorldContext) error {
		MoveMsg.Each(wCtx, func(txData cardinal.TxData[MovePlayerMsg]) (MovePlayerResult, error) {
			// handle the transaction
			// ...

			if err := errors.New("some error from a function"); err != nil {
				// A returned non-nil error will be appended to this transaction's list of errors. Any existing
				// transaction result will not be modified.
				return MovePlayerResult{}, fmt.Errorf("problem processing transaction: %w", err)
			}

			// Returning a nil error implies this transaction handling was successful, so this transaction result
			// will be saved to the transaction receipt.
			return MovePlayerResult{
				FinalX: txData.Msg().DeltaX,
				FinalY: txData.Msg().DeltaY,
			}, nil
		})
		return nil
	})
	if err != nil {
		panic(err)
	}
	// The above system will be called during each game tick.

	err = world.StartGame()
	if err != nil {
		panic(err)
	}
}
Output:

func NewMessageType ¶ added in v1.3.3

func NewMessageType[Input, Result any](name string) *MessageType[Input, Result]

NewMessageType creates a new instance of a MessageType.

func NewMessageTypeWithEVMSupport ¶

func NewMessageTypeWithEVMSupport[Input, Result any](name string) *MessageType[Input, Result]

NewMessageTypeWithEVMSupport creates a new instance of a MessageType, with EVM messages enabled. This allows this message to be sent from EVM smart contracts on the EVM base shard.

func (*MessageType[Input, Result]) AddToQueue ¶

func (t *MessageType[Input, Result]) AddToQueue(world *World, data Input, sigs ...*sign.Transaction) TxHash

AddToQueue is not meant to be used in production whatsoever, it is exposed here for usage in tests.

func (*MessageType[Input, Result]) Convert ¶

func (t *MessageType[Input, Result]) Convert() message.Message

Convert implements the AnyMessageType interface which allows a MessageType to be registered with a World via RegisterMessages.

func (*MessageType[Input, Result]) Each ¶ added in v1.3.3

func (t *MessageType[Input, Result]) Each(wCtx WorldContext, fn func(TxData[Input]) (Result, error))

func (*MessageType[Input, Result]) GetReceipt ¶ added in v1.3.3

func (t *MessageType[Input, Result]) GetReceipt(wCtx WorldContext, hash TxHash) (Result, []error, bool)

GetReceipt returns the result (if any) and errors (if any) associated with the given hash. If false is returned, the hash is not recognized, so the returned result and errors will be empty.

func (*MessageType[Input, Result]) In ¶ added in v1.3.3

func (t *MessageType[Input, Result]) In(wCtx WorldContext) []TxData[Input]

In returns the TxData in the given transaction queue that match this message's type.

type Receipt ¶

type Receipt = receipt.Receipt
type Search struct {
	// contains filtered or unexported fields
}

Search allowed for the querying of entities within a World.

func (*Search) Count ¶ added in v1.3.3

func (q *Search) Count(wCtx WorldContext) (int, error)

Count returns the number of entities that match this search.

func (*Search) Each ¶ added in v1.3.3

func (q *Search) Each(wCtx WorldContext, callback SearchCallBackFn) error

Each executes the given callback function on every EntityID that matches this search. If any call to callback returns falls, no more entities will be processed.

func (*Search) First ¶ added in v1.3.3

func (q *Search) First(wCtx WorldContext) (EntityID, error)

First returns the first entity that matches this search.

type SearchCallBackFn ¶

type SearchCallBackFn func(EntityID) bool

SearchCallBackFn represents a function that can operate on a single EntityID, and returns whether the next EntityID should be processed.

type System ¶

type System func(WorldContext) error

System is a function that process the transaction in the given transaction queue. Systems are automatically called during a world tick, and they must be registered with a world using RegisterSystems.

type TxData ¶ added in v1.3.3

type TxData[T any] struct {
	// contains filtered or unexported fields
}

TxData represents a single transaction.

func (*TxData[T]) Hash ¶ added in v1.3.3

func (t *TxData[T]) Hash() TxHash

Hash returns the hash of a specific message, which is used to associated results and errors with a specific message.

func (*TxData[T]) Msg ¶ added in v1.3.3

func (t *TxData[T]) Msg() T

Msg returns the input value of a message.

func (*TxData[T]) Tx ¶ added in v1.3.3

func (t *TxData[T]) Tx() *sign.Transaction

Tx returns the transaction data.

type TxHash ¶

type TxHash = message.TxHash

type World ¶

type World struct {
	// contains filtered or unexported fields
}

func NewMockWorld ¶

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

NewMockWorld creates a World object that uses miniredis as the storage layer suitable for local development. If you are creating a World for unit tests, use NewTestWorld.

func NewWorld ¶

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

NewWorld creates a new World object using Redis as the storage layer.

func (*World) CurrentTick ¶

func (w *World) CurrentTick() uint64

func (*World) Init ¶

func (w *World) Init(system System)

Init Registers a system that only runs once on a new game before tick 0.

func (*World) Instance ¶

func (w *World) Instance() *ecs.World

func (*World) IsGameRunning ¶

func (w *World) IsGameRunning() bool

func (*World) ShutDown ¶

func (w *World) ShutDown() error

func (*World) StartGame ¶

func (w *World) StartGame() error

StartGame starts running the world game loop. Each time a message arrives on the tickChannel, a world tick is attempted. In addition, an HTTP server (listening on the given port) is created so that game messages can be sent to this world. After StartGame is called, RegisterComponent, RegisterMessages, RegisterQueries, and RegisterSystems may not be called. If StartGame doesn't encounter any errors, it will block forever, running the server and ticking the game in the background.

func (*World) TestingAddCreatePersonaTxToQueue ¶

func (w *World) TestingAddCreatePersonaTxToQueue(data CreatePersonaTransaction)

func (*World) TestingGetTransactionReceiptsForTick ¶

func (w *World) TestingGetTransactionReceiptsForTick(tick uint64) ([]Receipt, error)

func (*World) Tick ¶

func (w *World) Tick(ctx context.Context) error

type WorldConfig ¶

type WorldConfig struct {
	RedisAddress      string
	RedisPassword     string
	CardinalNamespace string
	CardinalPort      string
	CardinalMode      string
}

func GetWorldConfig ¶

func GetWorldConfig() WorldConfig

type WorldContext ¶

type WorldContext interface {
	// NewSearch creates a new Search object that can iterate over entities that match
	// a given Component filter.
	//
	// For example:
	// search, err := worldCtx.NewSearch(cardinal.Exact(Health{}))
	// if err != nil {
	// 		return err
	// }
	// err = search.Each(worldCtx, func(id cardinal.EntityID) bool {
	// 		...process each entity id...
	// }
	// if err != nil {
	// 		return err
	// }
	NewSearch(filter Filter) (*Search, error)

	// CurrentTick returns the current game tick of the world.
	CurrentTick() uint64

	// EmitEvent broadcasts an event message to all subscribed clients.
	EmitEvent(event string)

	// Logger returns a zerolog.Logger. Additional metadata information is often attached to
	// this logger (e.g. the name of the active System).
	Logger() *zerolog.Logger

	Instance() ecs.WorldContext
}

func TestingWorldToWorldContext ¶

func TestingWorldToWorldContext(world *World) WorldContext

type WorldOption ¶

type WorldOption struct {
	// contains filtered or unexported fields
}

WorldOption represents an option that can be used to augment how the cardinal.World will be run.

func WithAdapter ¶

func WithAdapter(adapter shard.Adapter) WorldOption

WithAdapter provides the world with communicate channels to the EVM base shard, enabling transaction storage and transaction retrieval for state rebuilding purposes.

func WithCustomMockRedis ¶

func WithCustomMockRedis(miniRedis *miniredis.Miniredis) WorldOption

func WithDisableSignatureVerification ¶

func WithDisableSignatureVerification() WorldOption

WithDisableSignatureVerification disables signature verification for the HTTP server. This should only be used for local development.

func WithEventHub ¶

func WithEventHub(eventHub events.EventHub) WorldOption

func WithLoggingEventHub ¶

func WithLoggingEventHub(logger *ecslog.Logger) WorldOption

func WithReceiptHistorySize ¶

func WithReceiptHistorySize(size int) WorldOption

WithReceiptHistorySize specifies how many ticks worth of transaction receipts should be kept in memory. The default is 10. A smaller number uses less memory, but limits the amount of historical receipts available.

func WithStoreManager ¶

func WithStoreManager(s store.IManager) WorldOption

func WithTickChannel ¶

func WithTickChannel(ch <-chan time.Time) WorldOption

WithTickChannel sets the channel that will be used to decide when world.Tick is executed. If unset, a loop interval of 1 second will be set. To set some other time, use: WithTickChannel(time.Tick(<some-duration>)). Tests can pass in a channel controlled by the test for fine-grained control over when ticks are executed.

func WithTickDoneChannel ¶

func WithTickDoneChannel(ch chan<- uint64) WorldOption

WithTickDoneChannel sets a channel that will be notified each time a tick completes. The completed tick will be pushed to the channel. This option is useful in tests when assertions need to be performed at the end of a tick.

Directories ¶

Path Synopsis
ecs
abi
cql
ecb
Package ecb allows for buffering of state changes to the ECS storage layer, and either committing those changes in an atomic Redis transaction, or discarding the changes.
Package ecb allows for buffering of state changes to the ECS storage layer, and either committing those changes in an atomic Redis transaction, or discarding the changes.
log
receipt
Package receipt keeps track of transaction receipts for a number of ticks.
Package receipt keeps track of transaction receipts for a number of ticks.
types

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL