Sidebars, UI, Results, and Mashup
Sidebar DSL
Section titled “Sidebar DSL”@Suppress("unused")private val sidebarLayout by lazy { sidebar { title = "<gold><bold>PILLARS" refreshSeconds = 1
line { "<yellow>Phase: <white>$phase" } alive { trackedAlivePlayers.size } matchTimeLeft(limitSeconds = config.gameDurationSeconds) perPlayer { viewer -> "<gray>You: <white>${viewer.name}" } rows({ alivePlayers() }, { player -> "<green>${player.name}" }) }}Use helpers:
matchClock(label)to show elapsed time.matchTimeLeft(label, limitSeconds)to show remaining time.alive(label)to show alive count.field(label, color) { value }for simple dynamic fields.rows(source, row, empty)for expanding player lists.trackMatchClock(limitSeconds)to tell the sidebar it depends on match clock state.
Sidebar annotations
Section titled “Sidebar annotations”For simple sidebars, annotations are enough:
@Sidebar(title = "<gold><bold>SPLEEF", refreshSeconds = 1)class SpleefGame : GameTemplate() { @SidebarLine(order = 0) fun aliveLine() = "<green>Alive: ${aliveCount()}"
@SidebarLine(order = 1, spacer = true) val spacer = ""
@SidebarLine(order = 2, expand = true) fun playerRows() = alivePlayers().map { "<white>${it.name}" }}Use the DSL when you want stronger structure and helper functions; use annotations for compact scoreboards.
Sendables
Section titled “Sendables”MiniModes wraps common player-facing output:
player.send(Chat("<green>Ready."))player.send(ActionBar("<yellow>Cooldown: 2s"))player.send(Title("<gold>Victory", "<white>${player.name} wins"))player.send(SoundEffect("entity.player.levelup"))players.send(Chat("<aqua>Round starting."))Messages use MiniMessage-style strings through the platform adapter.
Inventory menus
Section titled “Inventory menus”GamePlayer.openMenu accepts a platform-neutral InventoryMenu:
player.openMenu( InventoryMenu( title = "<gold>Pick a Kit", rows = 3, items = mapOf( 11 to ItemDSL("iron_sword") { name = "<red>Fighter" }, 15 to ItemDSL("bow") { name = "<aqua>Archer" }, ), ) { slot -> when (slot) { 11 -> chooseKit(player, "fighter") 15 -> chooseKit(player, "archer") } player.closeMenu() })Use mutable slots and close/click snapshots when the player is allowed to arrange items.
Outcomes
Section titled “Outcomes”endGame(GameOutcome.winner(player))
endGame( rankedOutcome( placements = listOf(listOf(first), listOf(second, third)), scores = points, reason = GameCompletionReason.OBJECTIVE, detail = "Highest score", metadata = mapOf("mode" to config.mode.displayName), ))Completion reasons are OBJECTIVE, ELIMINATION, TIME_LIMIT, DRAW, CANCELLED, and ERROR.
Mashup
Section titled “Mashup”@Game(name = "Laser Tag", minPlayers = 2, maxPlayers = 16)@MashupRunnable( pace = MashupPace.FAST, family = "arena-combat", weight = 120, cooldownRounds = 2,)class LaserTagGame : SettingsGameTemplate()Paces are SLOW, CHILL, FAST, and BLITZ.