API

El mundo y los jugadores

Leer y cambiar bloques, generar entidades, hablar con los jugadores. En CraftScript los nombres van en snake_case (block_at, max_health); en Kotlin y Java, en camelCase (blockAt, maxHealth). Son los mismos objetos.

Un ejemplo

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")
            }
        }
    }
}

El mundo

world() en CraftScript (el mundo principal, o world("minecraft:the_nether")); Crafting.server?.world(id) o player.world en Kotlin.

Miembro Qué hace
id, players, time, is_raining, data Id del mundo, jugadores, hora (lectura y escritura), si llueve, datos guardados.
block_at(x, y, z) El bloque en esa posición.
set_block(x, y, z, type) Pone un bloque.
set_block(x, y, z, type, states) Pone un bloque con estados: { open: true }, { facing: "north" }.
spawn(type, location) Genera una entidad.
drop_item(location, stack) Suelta un ítem en el suelo.
explode(location, power, fire?) Explosión.
strike_lightning(location) Rayo.
spawn_particle(id, location, count?, spread?, speed?) Partículas.
spawn_particle(id, location, velocity) Una partícula que va con esa velocidad, en bloques por tick. Algunas, como minecraft:enchant y minecraft:portal, van hacia donde se generan: vienen de location + velocity.
play_sound(location, id, volume?, pitch?) Sonido en una posición.
light_at(x, y, z) Cuánta luz hay, de 0 a 15.
container_at(x, y, z) El inventario de un cofre, barril…, o null.
set_sign_text(x, y, z, lines) Texto de un cartel.
set_chunk_loaded(cx, cz, loaded) Mantiene un chunk cargado aunque no haya nadie cerca.
entities() Las entidades del mundo.
living_near(location, radius) Las entidades vivas cerca de un lugar, la más cercana primero.
shoot(projectile, from, velocity, shooter?, damage?) Lanza un proyectil, del juego o de un mod.

El jugador

Miembro Qué hace
name, uuid, is_op, has_crafting_client Identidad; si el cliente tiene Crafting instalado.
send(msg), action_bar(msg), title(title, subtitle?) Mensajes en el chat, la barra de acción y la pantalla. Colores con &.
inventory, held_item, give(stack) Inventario, lo que lleva en la mano, darle un ítem.
set_held_item(stack) Pone un objeto en la mano principal, en lugar de lo que había; null la vacía.
health, max_health, food_level, game_mode Vida, hambre (lectura y escritura) y modo de juego.
is_sleeping Si está durmiendo.
data Datos guardados con el jugador (abajo).
play_sound(id, volume?, pitch?) Un sonido solo para ese jugador.
has_permission(p), kick(reason) Permisos; expulsar.

Un Player también es una entidad viva (abajo).

Entidades, bloques e inventarios

Tipo Miembros
Entity uuid, type, world, location, custom_name, is_alive, data, direction, vehicle; teleport, remove, set_rotation, add_tag, has_tag.
LivingEntity Lo de Entity y health, max_health; damage, heal, set_ai, add_effect, remove_effect, has_effect, effects, add_modifier, remove_modifier, attribute, set_attribute, equipment, set_equipment (apaga o enciende su comportamiento propio).
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(otra).

Un ItemStack guarda id, cantidad, nombre, descripción (lore) y datos propios del mod, y los conserva al pasar por inventarios y cofres. En CraftScript se crea con item("rubies:ruby", 3); en Kotlin, ItemStack.of("rubies:ruby", 3) o con el constructor completo.

stack.enchantments es un mapa del id de cada encantamiento a su nivel (minecraft:sharpness → 3); en un libro encantado, los que otorga. En Kotlin, stack.withEnchantments(mapOf(Identifier.parse("minecraft:sharpness") to 3)) es el mismo stack con esos encantamientos. Un stack leído del juego conserva todo lo que tiene, incluso lo que la API no nombra (el contenido de un mapa, los efectos de una poción), cuando un mod lo mueve o lo cambia con with_count o withEnchantments (el copy de Kotlin no lo conserva).

Efectos, atributos y equipo

Efectos. Cualquier entidad viva puede tener los efectos del juego. e.add_effect("minecraft:speed", 8, 3) recibe el id, los segundos y el nivel (1 es I); un último argumento opcional, true o false, indica si muestra partículas. remove_effect(id), has_effect(id) y effects (un mapa de id a { level, seconds }) lo completan. En Kotlin: addEffect(Identifier.parse("minecraft:speed"), 8.0, 3) y ActiveEffect(level, seconds).

Un mod puede declarar efectos propios (ver Bloques, ítems y recetas); se dan y se leen con estos mismos miembros.

Atributos. attribute("minecraft:movement_speed") devuelve el valor actual, contando armadura y efectos. set_attribute("minecraft:scale", 1.6) cambia el valor base: scale, attack_damage, max_health, jump_strength, armor… En Kotlin: attribute(id) y 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) }
}

Modificadores. Un modificador cambia un atributo sin reemplazar su valor base, así que varios se pueden sumar y cada uno se puede quitar. e.add_modifier("minecraft:movement_speed", "mymod:frozen_slow", -0.3, "percent_of_base") recibe el atributo, un id para el modificador, la cantidad y la operación; e.remove_modifier("minecraft:movement_speed", "mymod:frozen_slow") lo quita. Añadir el mismo id otra vez lo reemplaza. Las operaciones son add (suma la cantidad), percent_of_base (suma la cantidad por el valor base) y multiply_total (multiplica el resultado por 1 más la cantidad). En 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")
}

Montar y efectos de área. entity.vehicle es aquello sobre lo que va montada la entidad, o null. world.living_near(location, radius) lista las entidades vivas alrededor de un lugar, la más cercana primero, que es lo que necesitan los efectos de área:

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) }
    }
}

Equipo. e.equipment("head") es el objeto que lleva puesto ahí, o null; e.set_equipment("main_hand", item("minecraft:iron_sword")) lo cambia. Las ranuras son main_hand, off_hand, head, chest, legs y feet. En Kotlin: EquipmentSlot.HEAD, equipment(slot) y setEquipment(slot, stack).

Dirección y enfriamientos. entity.direction es hacia dónde mira, un vector de un bloque de largo. player.set_cooldown(item, seconds) y player.has_cooldown(item) ponen un objeto en enfriamiento y lo comprueban.

Datos guardados

Jugadores, entidades, bloques y mundos tienen data: un almacén de clave y valor que sobrevive a los reinicios. Guarda textos, números, booleanos, listas y mapas.

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 Qué hace
data.set(k, v) o data[k] = v data[k] = v Guarda un valor (null lo borra).
data[k] data[k] Lee un valor tal como se guardó, o null.
data.get_int(k), get_number, get_string, get_boolean getInt(k), getNumber, getString, getBoolean Lee un valor de ese tipo, o null si no hay.
data.remove(k), data.clear(), data.keys remove(k), clear(), keys Borra una clave, borra todo, lista las claves.
  • Las claves son de todos los mods. Empieza cada clave con el id de tu mod (rubies.visits) para no pisar las de otro.
  • Cuánto dura: los datos de un jugador se quedan con él; los de una entidad se van cuando muere; los de un bloque, cuando un jugador lo rompe o cuando se sustituye a través de la API.
  • Los números se guardan como decimales; get_int los devuelve enteros.
  • Pon las claves y sus funciones en un solo archivo (lib/storage.craft, storage/ en Kotlin): el resto del mod no tiene que conocerlas. Ver Organizar un mod.

El servidor

Miembro Qué hace
players, worlds, motd, tps, is_dedicated Estado del servidor; tps es la media de ticks por segundo (20 es lo ideal).
player(name), world(id) Buscar un jugador conectado o un mundo.
broadcast(msg) Mensaje a todos.
stop() Guarda y detiene el servidor.
run_command(cmd) Salida de emergencia: ejecuta un comando del juego (ver abajo).

Salidas de emergencia

Dos funciones aceptan los formatos del propio juego: run_command (run(…) en CraftScript), que ejecuta un comando del juego, y summon(type, location, nbt), que crea una entidad con datos en el formato interno del juego. Existen para lo que la API aún no cubre, pero esos formatos pertenecen a Minecraft y pueden cambiar con una versión nueva, así que un mod que depende de ellos puede romperse. Úsalas lo menos posible y prefiere siempre la API.

Nada inventado. Ningún miembro de la API devuelve un valor de relleno. Si algo no puede funcionar en el juego que está corriendo, da un error que dice qué y por qué.