server

package
v0.1.14 Latest Latest
Warning

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

Go to latest
Published: Nov 8, 2023 License: MIT Imports: 23 Imported by: 0

Documentation

Index

Constants

View Source
const (
	Dev       GameMode = "dev"
	DevMySQL  GameMode = "devMySQL"
	DevSQLite GameMode = "devSQLite"
	Prod      GameMode = "prod"

	SaveStateInterval    = time.Second * 10
	DevSaveStateInterval = time.Millisecond * 100

	DefaultServerPort    = 9000
	DefaultWebsocketPort = 9001

	DefaultTickRate = 100 // ms

	TickRate = 100
)
View Source
const (
	MessageHeadLength = 13 // Fixed length of Message Head
)

Variables

View Source
var BaseTableSchemasToAccessors = map[interface{}]*state.TableBaseAccessor[any]{
	&TransactionSchema{}: (*state.TableBaseAccessor[any])(TransactionTable),
}
View Source
var (
	TransactionTable = state.NewTableAccessor[TransactionSchema]()
)

Functions

func AddSystemTransaction

func AddSystemTransaction(w *state.GameWorld, tickNumber int, transactionType string, data string, uuid string, isExternal bool) int

func BroadcastMessage

func BroadcastMessage(ctx *EngineCtx, clientEvents []ClientEvent)

func CORSMiddleware

func CORSMiddleware() gin.HandlerFunc

func CalcFutureTickFromMs added in v0.1.0

func CalcFutureTickFromMs(ctx *EngineCtx, timeInMs int) int

time in milliseconds

func CalcFutureTickFromS added in v0.1.0

func CalcFutureTickFromS(ctx *EngineCtx, timeInSeconds int) int

func CreateBasicResponseObject

func CreateBasicResponseObject(requestUuid string) interface{}

func CreateBasicResponseObjectWithData

func CreateBasicResponseObjectWithData(requestUuid string, data any) interface{}

func CreateRequestForTick

func CreateRequestForTick[T any](ctx *EngineCtx) gin.HandlerFunc

creates a corresponding request from a Gin request to user

func CreateResponseWithError

func CreateResponseWithError(requestUuid string, errorMessage string) interface{}

func DecodeRequestBody

func DecodeRequestBody[T any](c *gin.Context) (T, error)

func DeleteAllTicksAtTickNumber

func DeleteAllTicksAtTickNumber(w *state.GameWorld, tickNumber int)

func GetSystemTransactionsOfType

func GetSystemTransactionsOfType[T any](ctx *EngineCtx) []int

get tick transactions of type at a current tick number

func GetTickTransactionsOfType

func GetTickTransactionsOfType(w *state.GameWorld, transactionType string, tickNumber int) []int

get tick transactions

func GetTransactionUuid

func GetTransactionUuid(w state.IWorld, transactionId int) int

func GetTransactionsAtTickNumber

func GetTransactionsAtTickNumber(w *state.GameWorld, tickNumber int) []int

func HandleRewindState added in v0.1.0

func HandleRewindState(ctx *EngineCtx) gin.HandlerFunc

TODO will only one person have the power to restore the state initialize the world before calling it

func PrintErrorLog

func PrintErrorLog(ctx *EngineCtx)

used in debug mode, print all the errors the game has collected should be the same set of errors that are broadcasted to clients

func QueueTxAtTime

func QueueTxAtTime[T any](w state.IWorld, tickNumber int, data KeystoneTx[T], uuid string, isExternal bool) error

queues tick transactions to be executed in the future

func QueueTxFromExternal

func QueueTxFromExternal[T any](ctx *EngineCtx, data KeystoneTx[T], tickId string) error

queue transactions that are user-initiated aka external

func QueueTxFromInternal

func QueueTxFromInternal[T any](w state.IWorld, tickNumber int, data KeystoneTx[T], tickId string) error

queue transactions that are internal (ex: move planning)

func RegisterDefaultTables

func RegisterDefaultTables(w *state.GameWorld)

registers default tables keystone must operates on such as tick related

func SerializeRequestToString

func SerializeRequestToString[T any](req T) (string, error)

func SetupSaveStateLoop

func SetupSaveStateLoop(ctx *EngineCtx, saveInterval time.Duration)

game loop that triggers the save world state

func SetupSaveTxLoop added in v0.1.0

func SetupSaveTxLoop(ctx *EngineCtx, saveInterval time.Duration)

Set up save transaction loop

func ShouldTriggerTick

func ShouldTriggerTick(tickNumber int, tickRate int, frequencyInMs int) bool

if the tick happened between the previous and the current tick, we can still trigger it

func TickGameSystems

func TickGameSystems(ctx *EngineCtx)

used for tests

func TickWorldForward added in v0.1.0

func TickWorldForward(ctx *EngineCtx, ticks int) int

ticks the world forward for testing. time machine go brr

Types

type CMD

type CMD uint32

type ClientEvent

type ClientEvent struct {
	NetworkMessage *NetworkMessage
	PlayerIds      []int
}

type ConnectionType added in v0.1.0

type ConnectionType struct {
	SubscribeAllStateUpdates bool
}

type EngineCtx

type EngineCtx struct {
	// Unique game ID
	GameId string

	// Is the game live
	IsLive bool

	// Is the game state is being restored from db
	IsRestoringState bool

	// Game world containing table game state
	World *state.GameWorld

	// Game tick. The heartbeat of your game
	GameTick *GameTick

	// Stream server for broadcasting data such as table changes and errors to clients
	Stream *StreamServer

	// Gin HTTP server
	GinHttpEngine *gin.Engine

	// HTTP port
	HttpPort int

	// Transaction queue
	TransactionsToSaveLock sync.Mutex

	// Transactions to be stored in the data availability layer (aka a write ahead log basically)
	TransactionsToSave []TransactionSchema

	// Handles interactions for saving stae
	ShouldSaveState  bool
	SaveStateHandler ISaveState

	ShouldSaveTransactions  bool
	SaveTransactionsHandler ISaveTransactions

	// Implementations on how to broadcast events and errors
	SystemErrorHandler     ISystemErrorHandler
	SystemBroadcastHandler ISystemBroadcastHandler

	// "dev", "prod"
	Mode GameMode

	// Whether game should record error in error log
	ShouldRecordError bool

	// Error log for printing when testing
	ErrorLog []ErrorLog

	StateUpdatesMutex sync.Mutex

	// State updates
	PendingStateUpdatesToSave []state.TableUpdate
}

Context containing everything for the game server

func (*EngineCtx) AddStateUpdatesToSave

func (ctx *EngineCtx) AddStateUpdatesToSave()

add to the list of state updates to save to database

func (*EngineCtx) AddSystem added in v0.1.12

func (ctx *EngineCtx) AddSystem(IntervalMs int, tickFunction TickSystemFunction)

Interval: how frequently a system ticks (in milliseconds)

func (*EngineCtx) AddTables added in v0.1.12

func (ctx *EngineCtx) AddTables(tables map[interface{}]*state.TableBaseAccessor[any])

Add tables to world

func (*EngineCtx) AddTransactionToSave

func (ctx *EngineCtx) AddTransactionToSave(transaction TransactionSchema, tick int) error

add a transactions that needs to be saved

func (*EngineCtx) AddTransactionsToSave

func (ctx *EngineCtx) AddTransactionsToSave()

func (*EngineCtx) ClearStateUpdatesToSave

func (ctx *EngineCtx) ClearStateUpdatesToSave()

func (*EngineCtx) ClearTransactionsToSave

func (ctx *EngineCtx) ClearTransactionsToSave()

clear transactions to save

func (*EngineCtx) SetEmitErrorHandler added in v0.1.12

func (ctx *EngineCtx) SetEmitErrorHandler(errorHandler ISystemErrorHandler)

Set broadcast error handler

func (*EngineCtx) SetEmitEventHandler added in v0.1.12

func (ctx *EngineCtx) SetEmitEventHandler(broadcastHandler ISystemBroadcastHandler)

Set broadcast event handler

func (*EngineCtx) SetGameId added in v0.1.12

func (ctx *EngineCtx) SetGameId(id string)

Set game ID

func (*EngineCtx) SetGameLiveliness

func (ctx *EngineCtx) SetGameLiveliness(isLive bool)

set whether game is live or not

func (*EngineCtx) SetPort added in v0.1.12

func (ctx *EngineCtx) SetPort(port int)

Set HTTP port

func (*EngineCtx) SetSaveState added in v0.1.13

func (ctx *EngineCtx) SetSaveState(saveState bool)

Whether engine runs the state backup service. By default disabled for local development

func (*EngineCtx) SetSaveStateHandler added in v0.1.12

func (ctx *EngineCtx) SetSaveStateHandler(saveStateHandler ISaveState, saveInterval time.Duration)

Set save state handler

func (*EngineCtx) SetSaveTx added in v0.1.13

func (ctx *EngineCtx) SetSaveTx(saveTx bool)

Whether engine runs the transaction backup service By default disabled for local development

func (*EngineCtx) SetSaveTxHandler added in v0.1.12

func (ctx *EngineCtx) SetSaveTxHandler(saveTxHandler ISaveTransactions, saveInterval time.Duration)

Set save transaction handler

func (*EngineCtx) SetSocketRequestRouter added in v0.1.12

func (ctx *EngineCtx) SetSocketRequestRouter(router ISocketRequestRouter)

Set websocket request router

func (*EngineCtx) SetStreamRate added in v0.1.14

func (ctx *EngineCtx) SetStreamRate(rate int)

Set rate of streaming packets to clients (milliseconds)

func (*EngineCtx) SetTickRate added in v0.1.12

func (ctx *EngineCtx) SetTickRate(tickRateMs int)

Set tick rate (milliseconds)

func (*EngineCtx) SetWebsocketPort added in v0.1.12

func (ctx *EngineCtx) SetWebsocketPort(port int)

Set websocket port

func (*EngineCtx) Start added in v0.1.12

func (ctx *EngineCtx) Start()

Start Keystone game server

type ErrorLog

type ErrorLog struct {
	Tick    int
	Message string
}

for debugging

type EthereumWalletAuth added in v0.1.14

type EthereumWalletAuth struct {
	Base64Signature string
	Base64Hash      string
	Base64PublicKey string
}

func NewEthereumWalletAuth added in v0.1.14

func NewEthereumWalletAuth[T any](privateKey *ecdsa.PrivateKey, req T) (*EthereumWalletAuth, error)

func (*EthereumWalletAuth) Verify added in v0.1.14

func (p *EthereumWalletAuth) Verify() bool

type EventCtx

type EventCtx struct {
	ClientEvents []ClientEvent
}

used once per-request

func (*EventCtx) AddEvent

func (e *EventCtx) AddEvent(msg *NetworkMessage, playerIds []int)

adds a client event to the event context

type GameMode added in v0.1.0

type GameMode string

type GameTick

type GameTick struct {
	// the current game tick number
	TickNumber int

	// per how many milliseconds the game ticks
	TickRateMs int

	// schedule of ticks and corresponding functions
	Schedule *TickSchedule
}

func NewGameTick

func NewGameTick(tickRateMs int) *GameTick

func (*GameTick) Start added in v0.1.12

func (g *GameTick) Start(ctx *EngineCtx)

set up a game tick

type HeaderField added in v0.1.13

type HeaderField string
const (
	EthereumWalletAuthHeader HeaderField = "ethereumWalletAuth"
)

type IMiddleware

type IMiddleware[T any] func(ctx *TransactionCtx[T]) bool // manually emit errors to the transaction context as needed using ctx.EmitError

func VerifyEthereumWalletAuth added in v0.1.14

func VerifyEthereumWalletAuth[T any]() IMiddleware[T]

type ISaveState

type ISaveState interface {
	SaveState(tableUpdates []state.TableUpdate) error

	RestoreState(ctx *EngineCtx, gameId string) error
}

general interface to implement

type ISaveTransactions

type ISaveTransactions interface {
	SaveTransactions(updates []TransactionSchema) error

	// TODO: hook this up with a CLI for our SDK
	RestoreStateFromTxs(ctx *EngineCtx, tickNumber int, gameId string) error
}

type ISocketRequestRouter

type ISocketRequestRouter func(ctx *EngineCtx, requestMsg *NetworkMessage, socketConnection *websocket.Conn)

type ISystemBroadcastHandler

type ISystemBroadcastHandler interface {
	BroadcastMessage(ctx *EngineCtx, clientEvents []ClientEvent)
}

error broadcasting interface

type ISystemErrorHandler

type ISystemErrorHandler interface {
	FormatMessage(transactionUuidIdentifier int, errorMessage string) *NetworkMessage
}

error handling interface

type ISystemHandler

type ISystemHandler[T any] func(ctx *TransactionCtx[T])

type KeystoneTx added in v0.1.13

type KeystoneTx[T any] struct {
	Headers map[HeaderField]json.RawMessage
	Data    T
}

wraps the headers

func DecodeTxData

func DecodeTxData[T any](ctx *EngineCtx, transactionId int) KeystoneTx[T]

decode a string

func NewKeystoneTx added in v0.1.13

func NewKeystoneTx[T any](req T, headers map[HeaderField]json.RawMessage) KeystoneTx[T]

type NetworkMessage

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

func NewMessage

func NewMessage(flag uint8, command uint32, param uint32, data proto.Message) (*NetworkMessage, error)

func NewMessageFromBuffer

func NewMessageFromBuffer(buffer []byte) *NetworkMessage

decode message from client to server

func NewRequestMessage added in v0.1.13

func NewRequestMessage[T proto.Message](flag uint8, command uint32, param uint32, data KeystoneTx[T]) (*NetworkMessage, error)

func (*NetworkMessage) GetCommand

func (msg *NetworkMessage) GetCommand() uint32

func (*NetworkMessage) GetData added in v0.1.13

func (msg *NetworkMessage) GetData() []byte

func (NetworkMessage) GetProtoMessage

func (msg NetworkMessage) GetProtoMessage(structData proto.Message) (proto.Message, error)

Get Proto Message from Network Message

func (*NetworkMessage) Param

func (msg *NetworkMessage) Param() uint32

func (*NetworkMessage) ParseFromBuffer

func (msg *NetworkMessage) ParseFromBuffer(buffer []byte)

Parse NetworkMessage from network buffer

func (*NetworkMessage) ParseToBuffer

func (msg *NetworkMessage) ParseToBuffer() []byte

Parse NetworkMessage to network buffer

type NetworkMessageHead

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

func (*NetworkMessageHead) Decode

func (head *NetworkMessageHead) Decode(buffer []byte)

func (*NetworkMessageHead) Encode

func (head *NetworkMessageHead) Encode(buffer []byte)

func (*NetworkMessageHead) ParseHeadFromBuffer

func (head *NetworkMessageHead) ParseHeadFromBuffer(buffer []byte)

type NetworkMessages

type NetworkMessages []*NetworkMessage

type ProtoBasedBroadcastHandler added in v0.1.13

type ProtoBasedBroadcastHandler struct {
}

func (*ProtoBasedBroadcastHandler) BroadcastMessage added in v0.1.13

func (h *ProtoBasedBroadcastHandler) BroadcastMessage(ctx *EngineCtx, clientEvents []ClientEvent)

type ProtoBasedErrorHandler added in v0.1.13

type ProtoBasedErrorHandler struct {
}

func (*ProtoBasedErrorHandler) FormatMessage added in v0.1.13

func (h *ProtoBasedErrorHandler) FormatMessage(transactionUuidIdentifier int, errorMessage string) *NetworkMessage

format message into protobuf

type RewindStateRequest added in v0.1.0

type RewindStateRequest struct {
	ElapsedSeconds int    `json:"elapsedSeconds"`
	GameId         string `json:"gameId"`
}

type StreamServer

type StreamServer struct {
	// Websocket port
	Port int

	// Stream interval (milliseconds)
	StreamInterval int

	// Lock for protobuf packets
	ProtoBufPacketsMutex sync.Mutex

	// Socket request router
	SocketRequestRouter ISocketRequestRouter

	// Client message data packets to be broadcasted
	ClientEventsQueue []ClientEvent

	// Table updates to be broadcasted
	TableUpdatesQueue []state.TableUpdate

	// A pool of connections
	Conns      map[*websocket.Conn]ConnectionType
	ConnsMutex sync.Mutex

	// PlayerID to websocket connection
	PlayerIdToConnection      map[int]*websocket.Conn
	PlayerIdToConnectionMutex sync.Mutex
}

func NewStreamServer

func NewStreamServer() *StreamServer

Initialize new stream server

func (*StreamServer) AddConnection added in v0.1.0

func (ws *StreamServer) AddConnection(conn *websocket.Conn, subscribeToStateUpdates bool)

func (*StreamServer) ClearClientMessageQueue

func (ws *StreamServer) ClearClientMessageQueue()

clear all messages in the client message queue

func (*StreamServer) ClearTableUpdatesQueue

func (ws *StreamServer) ClearTableUpdatesQueue()

clear all table updates from queue

func (*StreamServer) FetchEventsFromQueue

func (ws *StreamServer) FetchEventsFromQueue() []ClientEvent

func (*StreamServer) FetchTableUpdatesFromQueue

func (ws *StreamServer) FetchTableUpdatesFromQueue() []state.TableUpdate

fetch all table updates from queue

func (*StreamServer) PublishStateChanges

func (ws *StreamServer) PublishStateChanges(tableUpdates state.TableUpdateArray, clientEvents []ClientEvent)

this is similar to broadcasting events in Solidity. we broadcast state changes to client along with additional useful metadata, for clients, data pipelines down the line, etc TODO: NOTE: currently we do not broadcast table updates

func (*StreamServer) RemoveConnection added in v0.1.0

func (ws *StreamServer) RemoveConnection(conn *websocket.Conn)

func (*StreamServer) SetPlayerIdToConnection

func (ws *StreamServer) SetPlayerIdToConnection(playerId int, conn *websocket.Conn)

func (*StreamServer) SetSocketRequestRouter added in v0.1.12

func (s *StreamServer) SetSocketRequestRouter(router ISocketRequestRouter)

Set socket request router

func (*StreamServer) Start added in v0.1.12

func (s *StreamServer) Start(ctx *EngineCtx)

Start websocket server TODO: have this return an error?

func (*StreamServer) StartMessageBroadcastLoop added in v0.1.14

func (ws *StreamServer) StartMessageBroadcastLoop()

Start message broadcast loop

type TickSchedule

type TickSchedule struct {
	// list of systems that need to be triggered
	ScheduledTickSystems []TickSystem
}

func NewTickSchedule

func NewTickSchedule() *TickSchedule

Initialize an empty tick schedule. Systems are added to the tick schedule

func (*TickSchedule) AddSystem added in v0.1.12

func (s *TickSchedule) AddSystem(tickInterval int, tickFunction TickSystemFunction)

tick interval in milliseconds

type TickSystem

type TickSystem struct {
	// how fast the game ticks
	TickInterval int

	// tick system function
	TickFunction TickSystemFunction
}

type TickSystemFunction

type TickSystemFunction func(ctx *EngineCtx) error

func CreateGeneralSystem

func CreateGeneralSystem(handler ISystemHandler[any]) TickSystemFunction

general are not triggered by user inputs

func CreateSystemFromRequestHandler

func CreateSystemFromRequestHandler[T any](handler ISystemHandler[T], middlewareFunctions ...IMiddleware[T]) TickSystemFunction

type TransactionCtx

type TransactionCtx[T any] struct {
	GameCtx *EngineCtx

	// the transaction entity ID
	TxId int

	// access world variables through this
	W state.IWorld

	// transaction request parameters
	Req KeystoneTx[T]

	EventCtx *EventCtx

	ErrorReturned bool

	Meta map[string]any
}

transaction ctx

func (*TransactionCtx[T]) EmitError

func (ctx *TransactionCtx[T]) EmitError(errorMessage string, playerIds []int)

emit error

func (*TransactionCtx[T]) EmitEvent

func (ctx *TransactionCtx[T]) EmitEvent(cmd CMD, data proto.Message, playerIds []int, isBlocking bool)

type TransactionSchema

type TransactionSchema struct {
	// Entity ID
	Id int `gorm:"primaryKey;autoIncrement:false"`

	// Transaction type
	Type string

	// A uuid that's sent from the client, which is usd to identify which quest has been satisfied
	Uuid string

	// Data payload serialized to string format
	Data string

	// Tick number when the transaction was to be processed
	TickNumber int

	// Timestamp of when the transaction was received by server
	UnixTimestamp int

	// whether transaction was submitted by player or other systems
	IsExternal bool
}

func CopyTransactions

func CopyTransactions(transactions []TransactionSchema) []TransactionSchema

type UpdatePacket

type UpdatePacket struct {
	// array of table update packets that need to be broadcasted to clients
	TableUpdates []state.TableUpdate `json:"tableUpdates"`

	// id of package that corresponds with the HTTP requests's returned UUID (similar to a transaction hash)
	Uuid string `json:"uuid"`

	// timestamp
	Time int64 `json:"time"`

	// error message string returned from a request
	Message string `json:"message"`
}

TODO: unused. remove in future

type WSMessage

type WSMessage struct {
	EventType string `json:"type"`
	Payload   any    `json:"message"`
}

Directories

Path Synopsis
serverpb

Jump to

Keyboard shortcuts

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