Skip to content

Items, Entities, and Abilities

val dashFeather = item("feather") {
name("<aqua><bold>Phase Dash")
lore("<gray>Right-click to dash forward.")
customModelData = 1201
uses(3)
showUsesInLore = true
glint()
meta("ability", "dash")
rightClick {
cooldown(1500.milliseconds)
impulse { forward(1.8) }
sound("entity.enderman.teleport", pitch = 1.4f)
}
}

Item fields include amount, name, lore, custom model data, damage, unbreakable, hide flags, enchantments, metadata, arbitrary components, dye color, base material, uses, and vanilla-interaction cancellation.

Interactive hooks include rightClick, leftClick, entity click, player damage, any entity damage, shot { launch {}; hit {} }, and drop.

You can either put behavior in the item definition or listen centrally:

events.onItemRightClick {
if (!requireAlive()) return@onItemRightClick
if (item.meta["ability"] == "dash") {
consumed = true
}
}

This is useful when several items share routing logic or when the game needs to inspect current phase/team state before allowing the action.

val projectileId = projectile(player, type = "arrow") {
speed = 4.2
gravity = false
critical = true
meta("weapon", "laser")
meta("tier", 2)
}

Read metadata in projectile-related events:

events.onEntityDamageByEntity {
val projectile = damager as? ProjectileDamager ?: return@onEntityDamageByEntity
if (projectile.metadata["weapon"] != "laser") return@onEntityDamageByEntity
suppressDamage()
removeProjectile()
}
val guardian = entity("zombie", at = pos(world, 0.0, 80.0, 0.0)) {
name = "<red>Guardian"
glowing = true
ai = true
invulnerable = false
attribute("generic.max_health", 80.0)
mainHand(item("iron_sword"))
pathfinding {
speed = 1.2
follow(players.first())
}
onDeath { info ->
gamePlayers.send(Chat("<gold>The guardian fell."))
}
}

After spawning, GameEntity supports remove, teleport, rotate, name, flag, attribute, equipment, and pathing through entity.path.to(pos), entity.path.follow(player), and entity.path.stop().

val cart = minecart(at = start) {
name = "<gold>Race Cart"
gravity = true
invulnerable = true
passenger(player)
}
cart.velocity(Velocity(0.6, 0.0, 0.0))
cart.clearPassengers()
private var doubleJumpSession: DoubleJumpSession? = null
override fun start() {
doubleJumpSession = gameRuntime.platform.doubleJump.create(doubleJump {
maxAerialJumps = 1
cooldownMillis = 450L
enabled = { player -> isAlive(player) && config.doubleJumpEnabled }
canAttempt = { player -> player.pos.world.slot == gameWorld?.slot }
onDoubleJump = { player ->
player.velocity = player.lookDirection.normalize().multiply(0.9).withY(0.75)
player.playSound("entity.breeze.jump", 0.8f, 1.2f)
}
})
alivePlayers().forEach { doubleJumpSession?.track(it) }
}
override fun end(winner: GamePlayer?) {
doubleJumpSession?.dispose()
}

Track players when they become eligible, untrack eliminated players, and call reset(player) after forced respawns.