Lifecycle and Runtime
- Discover The loader scans extension JARs for `@Game` classes and resource annotations.
- Configure The engine binds runtime, events, commands, dialog settings, teams, and leader state.
- Prepare `createGameWorldSuspend`, additional worlds, settings finalization, and setup happen in order.
- Run Game code reacts through normalized handles while tasks and subscriptions stay scoped.
- Dispose End/cancel paths clear prompts, tasks, events, entities, projectiles, vehicles, and worlds.
@Game( name = "Pillars", displayItem = "bedrock", description = "Outlast everyone else on your own pillar.", minPlayers = 2, maxPlayers = 8, pack = "classic", category = "survival",)class PillarsGame : SettingsGameTemplate()Use resources on @Game for simple embedded resource paths, or prefer @GameResource / @GameMap for typed resource metadata.
GameTemplate
Section titled “GameTemplate”Core lifecycle methods:
abstract fun setup(players: List<GamePlayer>)abstract fun start()abstract fun end(winner: GamePlayer? = null)abstract fun getMinPlayers(): Intabstract fun getMaxPlayers(): IntOptional suspend hooks:
override suspend fun createGameWorldSuspend(): GameWorld? = worlds.pooled(getStartPlayers())override suspend fun prepareAdditionalWorldsSuspend(players: List<GamePlayer>) {}override fun preparesAdditionalWorldsAfterTeams(): Boolean = falseThe engine calls these in the correct phase. You normally do not construct GameRuntime yourself.
Player state helpers
Section titled “Player state helpers”MiniModes stores participants and tracked alive players by UUID:
initializeAlivePlayers(players, initialLives = 3)trackAlivePlayer(player)setPlayerLives(player, lives = 2)consumePlayerLives(player)eliminateTrackedPlayer(player)aliveCount()alivePlayers()isParticipant(player)isAlive(player)Use these helpers so built-in event behavior, item interaction gating, sidebars, and end checks share one state model.
Timers and scheduler wrappers
Section titled “Timers and scheduler wrappers”startMatchClock(timeLimitSeconds = 600)
val heartbeat = every(20L) { if (aliveCount() <= 1) endGame(alivePlayers().firstOrNull())}
after(100L) { gamePlayers.send(Chat("<yellow>Five seconds passed."))}startGameCountdown provides a standard match-start flow with optional movement locking:
startGameCountdown(seconds = 5, lockMovement = true) { isRunning = true}Override onCountdownStart, onCountdownTick, and onCountdownComplete for custom announcements.
Prompts
Section titled “Prompts”prompt( player = leader, type = GameInputTypes.integer(min = 1, max = 10), message = "<yellow>How many rounds?", lockMovement = true,) { respondent, rounds -> respondent.send(Chat("<green>Rounds set to $rounds"))}End paths and outcomes
Section titled “End paths and outcomes”Use endGame(winner) for simple games. Use GameOutcome when rankings, ties, scores, or special completion reasons matter:
endGame( rankedOutcome( placements = listOf(listOf(first), listOf(second, third)), scores = scoreByPlayer, reason = GameCompletionReason.TIME_LIMIT, detail = "Most coins after 10 minutes", ))performEnd sets isRunning = false, clears input state, stops the match clock, disposes runtime objects, calls your end, and clears participants. finalizeShutdown cleans game worlds.