cardinal

package module
v1.3.2 Latest Latest
Warning

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

Go to latest
Published: Apr 30, 2024 License: LGPL-3.0 Imports: 49 Imported by: 3

Documentation

Index

Constants

View Source
const (
	DefaultCardinalNamespace         = "world-1"
	DefaultCardinalLogLevel          = "info"
	DefaultRedisAddress              = "localhost:6379"
	DefaultBaseShardSequencerAddress = "localhost:9601"
)
View Source
const (
	DefaultHistoricalTicksToStore = 10
	RedisDialTimeOut              = 15
)

Variables

View Source
var (
	ErrEntityMutationOnReadOnly          = errors.New("cannot modify state with read only context")
	ErrEntitiesCreatedBeforeReady        = errors.New("entities should not be created before world is ready")
	ErrEntityDoesNotExist                = iterators.ErrEntityDoesNotExist
	ErrEntityMustHaveAtLeastOneComponent = iterators.ErrEntityMustHaveAtLeastOneComponent
	ErrComponentNotOnEntity              = iterators.ErrComponentNotOnEntity
	ErrComponentAlreadyOnEntity          = iterators.ErrComponentAlreadyOnEntity
)
View Source
var NewLegacySearch = search.NewLegacySearch

NewLegacySearch allows users to create a Search object with a filter already provided as a property.

Example Usage:

cardinal.NewLegacySearch().Entity(filter.Exact(Alpha{}, Beta{})).Count()

View Source
var NewSearch = search.NewSearch

NewSearch is used to create a search object.

Usage:

cardinal.NewSearch().Entity(filter.Contains(filter.Component[EnergyComponent]()))

Functions

func AddComponentTo

func AddComponentTo[T types.Component](wCtx engine.Context, id types.EntityID) (err error)

func AuthorizePersonaAddressSystem

func AuthorizePersonaAddressSystem(wCtx engine.Context) error

AuthorizePersonaAddressSystem enables users to authorize an address to a persona tag. This is mostly used so that users who want to interact with the game via smart contract can link their EVM address to their persona tag, enabling them to mutate their owned state from the context of the EVM.

func Create

func Create(wCtx engine.Context, components ...types.Component) (_ types.EntityID, err 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 engine.Context, num int, components ...types.Component) (entityIDs []types.EntityID, err 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.

func CreatePersonaSystem

func CreatePersonaSystem(wCtx engine.Context) error

CreatePersonaSystem is a system that will associate persona tags with signature addresses. Each persona tag may have at most 1 signer, so additional attempts to register a signer with a persona tag will be ignored.

func EachMessage

func EachMessage[In any, Out any](wCtx engine.Context, fn func(message.TxData[In]) (Out, error)) error

func FilterFunction added in v1.3.0

func FilterFunction[T types.Component](f func(comp T) bool) func(ctx engine.Context, id types.EntityID) (bool, error)

func GetComponent

func GetComponent[T types.Component](wCtx engine.Context, id types.EntityID) (comp *T, err error)

GetComponent returns component data from the entity.

func MustRegisterComponent

func MustRegisterComponent[T types.Component](w *World)

func NewReadOnlyWorldContext

func NewReadOnlyWorldContext(world *World) engine.Context

func NewWorldContext

func NewWorldContext(world *World) engine.Context

func RegisterComponent

func RegisterComponent[T types.Component](w *World) error

func RegisterInitSystems

func RegisterInitSystems(w *World, sys ...system.System) error

func RegisterMessage

func RegisterMessage[In any, Out any](world *World, name string, opts ...message.MessageOption[In, Out]) error

RegisterMessage registers a message to the world. Cardinal will automatically set up HTTP routes that map to each registered message. Message URLs are take the form of "group.name". A default group, "game", is used unless the WithCustomMessageGroup option is used. Example: game.throw-rock

func RegisterQuery

func RegisterQuery[Request any, Reply any](
	w *World,
	name string,
	handler func(wCtx engine.Context, req *Request) (*Reply, error),
	opts ...query.Option[Request, Reply],
) (err error)

func RegisterSystems

func RegisterSystems(w *World, sys ...system.System) error

func Remove

func Remove(wCtx engine.Context, id types.EntityID) (err error)

Remove removes the given Entity from the engine.

func RemoveComponentFrom

func RemoveComponentFrom[T types.Component](wCtx engine.Context, id types.EntityID) (err error)

RemoveComponentFrom removes a component from an entity.

func SetComponent

func SetComponent[T types.Component](wCtx engine.Context, id types.EntityID, component *T) (err error)

SetComponent sets component data to the entity.

func UpdateComponent

func UpdateComponent[T types.Component](wCtx engine.Context, id types.EntityID, fn func(*T) *T) (err error)

Types

type EVMTxReceipt

type EVMTxReceipt struct {
	ABIResult []byte
	Errs      []error
	EVMTxHash string
}

type Namespace

type Namespace string

Namespace is a unique identifier for a world used for posting to the data availability layer and to prevent signature replay attacks across multiple worlds.

func (Namespace) String

func (n Namespace) String() string

func (Namespace) Validate

func (n Namespace) Validate() error

Validate validates that the namespace is alphanumeric or - (hyphen).

type Option

type Option func(*World)

type Plugin

type Plugin interface {
	Register(world *World) error
}
type Search = search.Search

type System

type System = system.System

type TickResults

type TickResults struct {
	Tick     uint64
	Receipts []receipt.Receipt
	Events   [][]byte
}

func NewTickResults

func NewTickResults(initialTick uint64) *TickResults

func (*TickResults) AddEvent

func (tr *TickResults) AddEvent(event any) error

func (*TickResults) AddStringEvent

func (tr *TickResults) AddStringEvent(e string) error

func (*TickResults) Clear

func (tr *TickResults) Clear()

func (*TickResults) SetReceipts

func (tr *TickResults) SetReceipts(newReceipts []receipt.Receipt)

func (*TickResults) SetTick

func (tr *TickResults) SetTick(tick uint64)

type World

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

func NewWorld

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

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

func (*World) AddEVMTransaction

func (w *World) AddEVMTransaction(
	id types.MessageID,
	v any,
	sig *sign.Transaction,
	evmTxHash string,
) (
	tick uint64, txHash types.TxHash,
)

func (*World) AddTransaction

func (w *World) AddTransaction(id types.MessageID, v any, sig *sign.Transaction) (
	tick uint64, txHash types.TxHash,
)

AddTransaction adds a transaction to the transaction pool. This should not be used directly. Instead, use a MessageType.AddTransaction to ensure type consistency. Returns the tick this transaction will be executed in.

func (*World) ConsumeEVMMsgResult

func (w *World) ConsumeEVMMsgResult(evmTxHash string) ([]byte, []error, string, bool)

ConsumeEVMMsgResult consumes a tx result from an EVM originated Cardinal message. It will fetch the receipt from the map, and then delete ('consume') it from the map.

func (*World) CurrentTick

func (w *World) CurrentTick() uint64

func (*World) GameStateManager

func (w *World) GameStateManager() gamestate.Manager

func (*World) GetComponentByName

func (w *World) GetComponentByName(name string) (types.ComponentMetadata, error)

func (*World) GetEVMMsgReceipt

func (w *World) GetEVMMsgReceipt(evmTxHash string) (EVMTxReceipt, bool)

func (*World) GetMessageByFullName

func (w *World) GetMessageByFullName(name string) (types.Message, bool)

func (*World) GetMessageByID

func (w *World) GetMessageByID(id types.MessageID) (types.Message, bool)

func (*World) GetQueryByName

func (w *World) GetQueryByName(name string) (engine.Query, error)

func (*World) GetReadOnlyCtx added in v1.3.0

func (w *World) GetReadOnlyCtx() engine.Context

func (*World) GetRegisteredComponents

func (w *World) GetRegisteredComponents() []types.ComponentMetadata

func (*World) GetRegisteredMessages

func (w *World) GetRegisteredMessages() []types.Message

func (*World) GetRegisteredQueries

func (w *World) GetRegisteredQueries() []engine.Query

func (*World) GetRegisteredSystemNames

func (w *World) GetRegisteredSystemNames() []string

func (*World) GetSignerComponentForPersona

func (w *World) GetSignerComponentForPersona(personaTag string) (*component.SignerComponent, error)

func (*World) GetSignerForPersonaTag

func (w *World) GetSignerForPersonaTag(personaTag string, tick uint64) (addr string, err error)

GetSignerForPersonaTag returns the signer address that has been registered for the given persona tag after the given tick. If the engine's tick is less than or equal to the given tick, ErrorCreatePersonaTXsNotProcessed is returned. If the given personaTag has no signer address, ErrPersonaTagHasNoSigner is returned.

func (*World) GetTransactionReceiptsForTick

func (w *World) GetTransactionReceiptsForTick(tick uint64) ([]receipt.Receipt, error)

func (*World) HandleEVMQuery

func (w *World) HandleEVMQuery(name string, abiRequest []byte) ([]byte, error)

func (*World) IsGameRunning

func (w *World) IsGameRunning() bool

func (*World) Namespace

func (w *World) Namespace() string

func (*World) RecoverFromChain

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

RecoverFromChain will attempt to recover the state of the engine based on historical transaction data. The function puts the World in a recovery state, and will then query all transaction batches under the World's namespace. The function will continuously ask the EVM base shard for batches, and run ticks for each batch returned.

func (*World) RegisterPlugin

func (w *World) RegisterPlugin(plugin Plugin)

func (*World) Search

func (w *World) Search(filter filter.ComponentFilter) search.EntitySearch

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, registerMessagesByName, 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) StoreReader

func (w *World) StoreReader() gamestate.Reader

func (*World) UseNonce

func (w *World) UseNonce(signerAddress string, nonce uint64) error

func (*World) WaitForNextTick

func (w *World) WaitForNextTick() (success bool)

WaitForNextTick blocks until at least one game tick has completed. It returns true if it successfully waited for a tick. False may be returned if the engine was shut down while waiting for the next tick to complete.

type WorldConfig

type WorldConfig struct {
	// CardinalNamespace The shard namespace for Cardinal. This needs to be unique to prevent signature replay attacks.
	CardinalNamespace string `config:"CARDINAL_NAMESPACE"`

	// CardinalRollupEnabled When true, Cardinal will sequence and recover to/from base shard.
	CardinalRollupEnabled bool `config:"CARDINAL_ROLLUP_ENABLED"`

	// CardinalLogLevel Determines the log level for Cardinal.
	CardinalLogLevel string `config:"CARDINAL_LOG_LEVEL"`

	// CardinalLogPretty Pretty logging, disable by default due to performance impact.
	CardinalLogPretty bool `config:"CARDINAL_LOG_PRETTY"`

	// RedisAddress The address of the redis server, supports unix sockets.
	RedisAddress string `config:"REDIS_ADDRESS"`

	// RedisPassword The password for the redis server. Make sure to use a password in production.
	RedisPassword string `config:"REDIS_PASSWORD"`

	// BaseShardSequencerAddress This is the address that Cardinal will use to sequence and recover to/from base shard.
	BaseShardSequencerAddress string `config:"BASE_SHARD_SEQUENCER_ADDRESS"`

	// BaseShardRouterKey is a token used to secure communications between the game shard and the base shard.
	BaseShardRouterKey string `config:"BASE_SHARD_ROUTER_KEY"`

	// TelemetryEnabled When true, Cardinal will send telemetry to a telemetry agent.
	TelemetryEnabled bool `config:"TELEMETRY_ENABLED"`

	// TelemetryStatsdAddress The address of a statsd metric agent that will collect stats from Cardinal.
	TelemetryStatsdAddress string `config:"TELEMETRY_STATSD_ADDRESS"`

	// TelemetryTraceAddress The address of an agent that supports the collection of traces (e.g. a DataDog agent).
	TelemetryTraceAddress string `config:"TELEMETRY_TRACE_ADDRESS"`
}

func (*WorldConfig) Validate

func (w *WorldConfig) Validate() error

Validate validates the config values. If CARDINAL_ROLLUP=true, the BASE_SHARD_SEQUENCER_ADDRESS and BASE_SHARD_ROUTER_KEY are required.

type WorldContext

type WorldContext = engine.Context

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 WithCustomLogger

func WithCustomLogger(logger zerolog.Logger) WorldOption

func WithCustomRouter

func WithCustomRouter(rtr router.Router) WorldOption

func WithDisableSignatureVerification

func WithDisableSignatureVerification() WorldOption

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

func WithMockRedis

func WithMockRedis() WorldOption

WithMockRedis runs the World with an embedded miniredis instance on port 6379.

func WithPort

func WithPort(port string) WorldOption

WithPort sets the port that the HTTP server will run on.

func WithPrettyLog

func WithPrettyLog() 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 gamestate.Manager) WorldOption

func WithTickChannel

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

WithTickChannel sets the channel that will be used to decide when world.doTick 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
Package ecb allows for buffering of state changes to the ECS dbStorage 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 dbStorage layer, and either committing those changes in an atomic Redis transaction, or discarding the changes.
msg
Package receipt keeps track of transaction receipts for a number of ticks.
Package receipt keeps track of transaction receipts for a number of ticks.
iterator/mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
docs
Package docs Code generated by swaggo/swag.
Package docs Code generated by swaggo/swag.
Package statsd is a helper package that wraps some common statsd methods.
Package statsd is a helper package that wraps some common statsd methods.
engine/mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.

Jump to

Keyboard shortcuts

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