Skip to content

Items, Entities, and Abilities

val dashFeather = ItemDSL("feather") {
name = "<aqua><bold>Phase Dash"
lore += "<gray>Right-click to dash forward."
customModelData = 1201
uses = 3
showUsesInLore = true
glint()
meta("ability", "dash")
onRightClick(cooldownMillis = 1500) { ctx ->
ctx.player.velocity = ctx.player.lookDirection.normalize().multiply(1.8)
ctx.player.playSound("entity.enderman.teleport", 1f, 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 right/left click, entity click, player damage, any entity damage, projectile launch, projectile hit player/entity, 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(ItemDSL("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.