API

The world and players

Read and change blocks, spawn entities, talk to players. In CraftScript names use snake_case (block_at, max_health); in Kotlin and Java they use camelCase (blockAt, maxHealth). They are the same objects.

An example

commands/beacon.craftCraftScript
command beacon requires "rubies.beacon" describe "Light a beacon where you stand" {
    if player == null { return "Players only" }
    let w = player.world
    let at = player.location
    w.set_block(at.block_x, at.block_y, at.block_z, "minecraft:lantern", { hanging: false })
    w.spawn_particle("minecraft:flame", at, 30, 0.5, 0.02)
    w.play_sound(at, "minecraft:block.lantern.place")
    player.title("&eLit", "")
}
commands/BeaconCommand.ktKotlin
object BeaconCommand {
    fun register() {
        Crafting.commands.command("beacon") {
            permission = "rubies.beacon"
            executes { c ->
                val at = c.player.location
                val world = c.player.world
                world.setBlock(at.blockX, at.blockY, at.blockZ, Identifier.parse("minecraft:lantern"), mapOf("hanging" to false))
                world.spawnParticle(Identifier.parse("minecraft:flame"), at, count = 30, spread = 0.5, speed = 0.02)
                world.playSound(at, Identifier.parse("minecraft:block.lantern.place"))
                c.player.title("&eLit")
            }
        }
    }
}

World

world() in CraftScript (the main world, or world("minecraft:the_nether")); Crafting.server?.world(id) or player.world in Kotlin.

Member What it does
id, players, time, is_raining, data World id, players, time of day (read and write), whether it is raining, saved data.
block_at(x, y, z) The block at that position.
set_block(x, y, z, type) Places a block.
set_block(x, y, z, type, states) Places a block with states: { open: true }, { facing: "north" }.
spawn(type, location) Spawns an entity.
drop_item(location, stack) Drops an item on the ground.
explode(location, power, fire?) Explosion.
strike_lightning(location) Lightning bolt.
spawn_particle(id, location, count?, spread?, speed?) Particles.
spawn_particle(id, location, velocity) One particle going with that velocity, in blocks per tick. Some, like minecraft:enchant and minecraft:portal, go toward where they are spawned: they come from location + velocity.
play_sound(location, id, volume?, pitch?) A sound at a position.
light_at(x, y, z) How much light there is, from 0 to 15.
container_at(x, y, z) The inventory of a chest, barrel…, or null.
set_sign_text(x, y, z, lines) Text on a sign.
set_chunk_loaded(cx, cz, loaded) Keeps a chunk loaded even when nobody is nearby.
entities() The entities in the world.
living_near(location, radius) The living entities near a place, nearest first.
shoot(projectile, from, velocity, shooter?, damage?) Launches a projectile, the game's or a mod's.

Player

Member What it does
name, uuid, is_op, has_crafting_client Identity; whether the client has Crafting installed.
send(msg), action_bar(msg), title(title, subtitle?) Messages in chat, the action bar and on screen. Colors with &.
inventory, held_item, give(stack) Inventory, the item in hand, give an item.
set_held_item(stack) Puts an item in the main hand, in place of what was there; null empties it.
health, max_health, food_level, game_mode Health, hunger (read and write) and game mode.
is_sleeping Whether the player is sleeping.
data Data saved with the player (below).
play_sound(id, volume?, pitch?) A sound for that player only.
has_permission(p), kick(reason) Permissions; kick.

A Player is also a living entity (below).

Entities, blocks and inventories

Type Members
Entity uuid, type, world, location, custom_name, is_alive, data, direction, vehicle; teleport, remove, set_rotation, add_tag, has_tag.
LivingEntity Everything in Entity plus health, max_health; damage, heal, set_ai, add_effect, remove_effect, has_effect, effects, add_modifier, remove_modifier, attribute, set_attribute, equipment, set_equipment (turns its own behavior off or on).
Block type, x, y, z, world, location, is_solid, data; set_type, relative(dx, dy, dz).
Inventory size; get(slot), set(slot, stack), add(stack), count(id), clear().
Location world, x, y, z, yaw, pitch, block_x, block_y, block_z; add(dx, dy, dz), distance_to(other).

An ItemStack holds an id, a count, a name, a description (lore) and the mod's own data, and keeps them as it moves through inventories and chests. In CraftScript you create one with item("rubies:ruby", 3); in Kotlin, with ItemStack.of("rubies:ruby", 3) or the full constructor.

stack.enchantments is a map from each enchantment's id to its level (minecraft:sharpness → 3); an enchanted book's are the ones it gives. In Kotlin, stack.withEnchantments(mapOf(Identifier.parse("minecraft:sharpness") to 3)) is the same stack with those enchantments. A stack read from the game keeps everything it has, including what the API doesn't name (a map's contents, a potion's effects), when a mod moves it or changes it with with_count or withEnchantments (Kotlin's copy doesn't keep it).

Effects, attributes and equipment

Effects. Any living entity can have the game's effects. e.add_effect("minecraft:speed", 8, 3) takes the id, the seconds and the level (1 is I); an optional last argument, true or false, sets whether it shows particles. remove_effect(id), has_effect(id) and effects (a map from id to { level, seconds }) complete it. In Kotlin: addEffect(Identifier.parse("minecraft:speed"), 8.0, 3) and ActiveEffect(level, seconds).

A mod can declare effects of its own (see Blocks, items and recipes); they are given and read with these same members.

Attributes. attribute("minecraft:movement_speed") returns the value right now, counting armor and effects. set_attribute("minecraft:scale", 1.6) changes the base value: scale, attack_damage, max_health, jump_strength, armor… In Kotlin: attribute(id) and setAttribute(id, value).

commands/grow.craftCraftScript
command grow() {
    let p = player
    if p.attribute("minecraft:scale") > 1.2 { p.set_attribute("minecraft:scale", 1) } else { p.set_attribute("minecraft:scale", 1.6) }
}

Modifiers. A modifier changes an attribute without replacing its base value, so several can add up and each one can be taken away. e.add_modifier("minecraft:movement_speed", "mymod:frozen_slow", -0.3, "percent_of_base") takes the attribute, an id for the modifier, the amount and the operation; e.remove_modifier("minecraft:movement_speed", "mymod:frozen_slow") removes it. Adding the same id again replaces it. The operations are add (adds the amount), percent_of_base (adds the amount times the base value) and multiply_total (multiplies the result by 1 plus the amount). In Kotlin: addModifier(attr, id, amount, ModifierOperation.PERCENT_OF_BASE).

commands/chill.craftCraftScript
command chill() {
    player.add_modifier("minecraft:movement_speed", "mymod:chill", -0.3, "percent_of_base")
    // later: player.remove_modifier("minecraft:movement_speed", "mymod:chill")
}

Riding and area effects. entity.vehicle is what the entity is riding, or null. world.living_near(location, radius) lists the living entities around a place, nearest first, which is what area effects need:

commands/frostwave.craftCraftScript
command frostwave() {
    let p = player
    for other in p.world.living_near(p.location, 8) {
        if other.type != "minecraft:player" { other.add_effect("mymod:frozen", 4, 1) }
    }
}

Equipment. e.equipment("head") is the item worn there, or null; e.set_equipment("main_hand", item("minecraft:iron_sword")) changes it. The slots are main_hand, off_hand, head, chest, legs and feet. In Kotlin: EquipmentSlot.HEAD, equipment(slot) and setEquipment(slot, stack).

Direction and cooldowns. entity.direction is where it looks, a vector one block long. player.set_cooldown(item, seconds) and player.has_cooldown(item) put an item on cooldown and check it.

Saved data

Players, entities, blocks and worlds have data: a key-value store that survives restarts. It stores strings, numbers, booleans, lists and maps.

lib/storage.craftCraftScript
// Data that survives restarts. Keys start with the mod id: they're shared by every mod.
const VISITS = "rubies.visits"

fun visits(p: Player): number {
    return p.data.get_int(VISITS) ?? 0
}

fun add_visit(p: Player): number {
    let n = visits(p) + 1
    p.data.set(VISITS, n)
    return n
}
storage/Visits.ktKotlin
package com.example.rubies.storage

object Visits {
    private const val KEY = "rubies.visits"   // shared by every mod: prefix it with the mod id

    fun of(player: Player): Int = player.data.getInt(KEY) ?: 0

    fun add(player: Player): Int = (of(player) + 1).also { player.data[KEY] = it }
}
CraftScript Kotlin / Java What it does
data.set(k, v) or data[k] = v data[k] = v Stores a value (null deletes it).
data[k] data[k] Reads a value as it was stored, or null.
data.get_int(k), get_number, get_string, get_boolean getInt(k), getNumber, getString, getBoolean Reads a value of that type, or null if there is none.
data.remove(k), data.clear(), data.keys remove(k), clear(), keys Deletes a key, deletes everything, lists the keys.
  • Keys are shared by all mods. Start each key with your mod id (rubies.visits) so you don't overwrite another mod's keys.
  • How long it lasts: a player's data stays with the player; an entity's data goes away when it dies; a block's data goes away when a player breaks it or when it is replaced through the API.
  • Numbers are stored as decimals; get_int returns them as integers.
  • Put the keys and their functions in a single file (lib/storage.craft, storage/ in Kotlin): the rest of the mod doesn't need to know them. See Organizing a mod.

Server

Member What it does
players, worlds, motd, tps, is_dedicated Server state; tps is the average ticks per second (20 is ideal).
player(name), world(id) Find an online player or a world.
broadcast(msg) Message to everyone.
stop() Saves and stops the server.
run_command(cmd) Escape hatch: runs a game command (see below).

Escape hatches

Two functions accept the game's own formats: run_command (run(…) in CraftScript), which runs a game command, and summon(type, location, nbt), which creates an entity with data in the game's internal format. They exist for what the API doesn't cover yet, but those formats belong to Minecraft and can change in a new version, so a mod that depends on them can break. Use them as little as possible and always prefer the API.

Nothing made up. No API member returns a placeholder value. If something can't work in the running game, it raises an error that says what and why.