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
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", "")
}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).
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).
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:
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.
// 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
}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_intreturns 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.