API

Bloques, ítems y recetas

El contenido se declara como una lista de propiedades. Crafting crea los objetos reales del juego en el momento adecuado y genera los modelos, tablas de botín, etiquetas, recetas y traducciones que necesitan. Tú no escribes ningún archivo de datos del juego.

Ítems

content/items.craftCraftScript
item "ruby" { rarity: "rare" }

item "ruby_apple" {
    food: { nutrition: 8, saturation: 1.2, always_edible: true }
    glint: true
}

item "ruby_pickaxe" { tool: { type: "pickaxe", tier: "diamond", speed: 9 }, tab: "tools_and_utilities" }
Propiedad Valores Por defecto
stack o max_stack 1–99 64
rarity common, uncommon, rare, epic (color del nombre) common
glint brillo encantado false
durability número; obliga a stack: 1 0
fireproof no se quema en lava ni fuego false
food número, o { nutrition, saturation, always_edible } —
tool "pickaxe", o { type, tier, damage, speed }; type: pickaxe, axe, shovel, hoe, sword —
tab pestaña del inventario creativo (abajo) ingredients
texture ruta de la textura item/<id>
on_use fun(player, stack); devuelve true si gestiona el uso —
armor { slot, defense, toughness, knockback_resistance, texture } —
on_hit fun(attacker, target, stack) —
cooldown segundos 0

Armadura, armas y enfriamientos

Un objeto con armor se puede vestir. slot es head, chest, legs o feet. defense, toughness y knockback_resistance (0 a 1) son los valores de armadura del juego: un peto de hierro tiene 6 de defensa y el diamante 2 de dureza.

content/armor.craftCraftScript
item "frost_helmet" { texture: "minecraft:item/iron_helmet", armor: { slot: "head", defense: 3, texture: "frost" } }
item "frost_chestplate" { armor: { slot: "chest", defense: 8, toughness: 2 }, durability: 400 }

texture es cómo se ve puesta. frost significa textures/entity/equipment/humanoid/frost.png en el mod y, para las piernas, textures/entity/equipment/humanoid_leggings/frost.png, con la misma disposición que las texturas de armadura del juego. Sin ella, la armadura se ve como la de hierro.

on_hit se ejecuta cuando el objeto se usa para golpear, ya sea un jugador o un mob.

content/frost_blade.craftCraftScript
item "frost_blade" {
    texture: "minecraft:item/diamond_sword"
    tool: "sword"
    cooldown: 3
    on_hit: fun(attacker, target, stack) {
        target.add_effect("minecraft:slowness", 4, 4)
        target.world.spawn_particle("minecraft:snowflake", target.location.add(0, 1, 0), 20, 0.4, 0.02)
    }
}

cooldown (en segundos) bloquea el objeto ese tiempo tras cada uso que su on_use aceptó, y la barra de acceso rápido lo muestra. Desde código: player.set_cooldown("minecraft:feather", 2) y player.has_cooldown(id). En Kotlin: armor(EquipmentSlot.HEAD, defense = 3, texture = "frost") para armaduras y onHit = { ctx -> … } para armas (ctx.attacker, ctx.target, ctx.stack).

content/Armor.ktKotlin
item("frost_helmet") { armor(EquipmentSlot.HEAD, defense = 3, texture = "frost") }

Bloques

content/ores.craftCraftScript
block "ruby_ore" {
    hardness: 3
    tool: "pickaxe"
    tier: "iron"
    loot: [
        { item: "rubies:ruby", count: [1, 2] },
        { item: "minecraft:diamond", chance: 0.1 }
    ]
}

block "ruby_block" { hardness: 5, light: 7, tool: "pickaxe", sound: "metal" }

block "ruby_lamp" { hardness: 0.3, light: 15, sound: "glass", transparent: true, tab: "functional_blocks" }

block "ruby_bricks" { hardness: 2, tool: "pickaxe", drops: "ruby", drop_count: [2, 4] }
Propiedad Valores Por defecto
hardness número; -1 = irrompible 1.5
resistance resistencia a explosiones = hardness
light 0–15 0
light_when un estado de interruptor, como "lit": el bloque brilla solo mientras está encendido (ver Estados de bloque) siempre
sound stone, wood, gravel, grass, metal, glass, wool, sand stone
like un bloque con el que se hace igual, del juego ("minecraft:end_stone") o tuyo: su dureza, resistencia, sonido y si necesita la herramienta adecuada para soltar algo son los de ese bloque —
kind uno de los tipos del juego: escaleras, puerta, cofre, cultivo… (ver Tipos de bloque) cube
tool, tier herramienta necesaria para que suelte algo, y material mínimo de esa herramienta: wood, stone, iron, diamond, netherite —, wood
drops, drop_count un solo objeto: id; número o [mín, máx] el propio bloque, 1
loot varios objetos: [{ item, count, chance, tool, fortune }, …]. Cada uno se sortea por separado; count es un número o [mín, máx] y chance va de 0 a 1 (por defecto 1). tool y fortune: ver Lo que suelta más abajo —
friction 0.6 normal, 0.98 hielo 0.6
transparent deja ver a través (cristal, hojas) false
has_item registrar también el ítem del bloque; sin él, el bloque no suelta nada salvo que drops o loot digan qué true
tab pestaña del inventario creativo building_blocks
on_use fun(player, block); devuelve true si gestiona el uso. Un jugador que va agachado con algo en la mano lo coloca en su lugar, como con los bloques del juego —

Pestañas: building_blocks, colored_blocks, natural_blocks, functional_blocks, redstone_blocks, tools_and_utilities, combat, food_and_drinks, ingredients, spawn_eggs. En Kotlin están en CreativeTabs.

Para que una criatura suelte algo más al morir, añádelo a e.drops en el evento entity_death (ver Eventos).

Los bloques que no son cubos, los bloques de los tipos del juego, las criaturas, las menas, los sonidos y las partículas se declaran igual y tienen su propia página: Formas de bloque, Tipos de bloque, Criaturas, Generación de mundo, Sonidos y partículas.

Lo que suelta: herramientas y fortuna

Un objeto de loot puede necesitar una herramienta, y la fortuna puede dar más de él:

content/drops.craftCraftScript
block "ruby_ore" {
    kind: "ore"
    tool: "pickaxe"
    tier: "iron"
    xp: [1, 4]
    loot: [
        { item: "ruby", count: [1, 2], fortune: true },
        { item: "ruby_ore", tool: "silk_touch" }
    ]
}

block "frost_leaves" {
    kind: "leaves"
    loot: [
        { item: "frost_leaves", tool: "shears" },
        { item: "frost_sapling", chance: 0.05, fortune: true }
    ]
}
  • tool: "silk_touch": solo se suelta cuando el bloque se rompe con toque de seda. tool: "shears": solo con tijeras o con toque de seda, como las hojas y enredaderas del juego se sueltan a sí mismas.
  • Cuando algunos objetos necesitan una herramienta, los que no la necesitan se sueltan solo cuando esa herramienta no se usa: la mena de arriba se suelta a sí misma con toque de seda y sus rubíes en caso contrario.
  • fortune: true: la fortuna da más de él, más de su count como con las menas del juego, o una mejor chance como con los brotes que sueltan las hojas.

En Kotlin: drop("ruby", 1..2, tool = null, fortune = true) y drop("ruby_ore", tool = DropTool.SILK_TOUCH).

content/Drops.ktKotlin
block("ruby_ore") {
    kind = BlockKind.ORE
    xp = 1..4
    drop("ruby", 1..2, tool = null, fortune = true)
    drop("ruby_ore", tool = DropTool.SILK_TOUCH)
}

Recetas

content/recipes.craftCraftScript
recipe shaped "ruby_block" {
    pattern: ["RRR", "RRR", "RRR"]
    keys: { R: "ruby" }
    result: "ruby_block"
}

recipe shapeless "rubies_from_block" { ingredients: ["ruby_block"], result: "ruby", count: 9 }

recipe smelting "ruby_from_ore" { input: "ruby_ore", result: "ruby", xp: 1.0 }

Comportamiento al usar

on_use es la única lógica que vive junto a los datos. Si crece más de un par de líneas, escribe la función en lib/ e impórtala:

content/wands.craftCraftScript
import { lift } from "/lib/teleport"

item "lift_wand" { stack: 1, rarity: "uncommon", on_use: lift }
lib/teleport.craftCraftScript
fun lift(player, stack) {
    player.teleport(player.location.add(0, 10, 0))
    return true
}

Bloques que reaccionan

Un bloque puede ejecutar código cuando le pasa algo a él o a su alrededor. Cada manejador recibe el bloque y, cuando corresponde, la entidad.

Propiedad Se ejecuta cuando
on_step: fun(block, entity) una entidad camina sobre el bloque.
on_inside: fun(block, entity) una entidad está dentro del bloque. El bloque debe dejar pasar a las entidades: un portal, una planta o una forma no sólida.
on_random_tick: fun(block) de vez en cuando, al azar, como el crecimiento de los cultivos: cada 68 segundos aproximadamente por bloque.
on_tick: fun(block) pasó el tiempo pedido con block.schedule(ticks) (20 ticks = 1 segundo).
on_neighbor_change: fun(block) cambió un bloque contiguo: lo colocaron, lo rompieron o recibió señal.
on_placed: fun(block, entity) alguien colocó el bloque; entity es quien.
content/reactions.craftCraftScript
block "jump_pad" { on_step: fun(b, e) { e.velocity = vector(0, 1.1, 0) } }

block "blinker" {
    light: 7
    on_tick: fun(b) {
        b.world.spawn_particle("minecraft:end_rod", b.location.add(0.5, 1.2, 0.5), 4, 0.1, 0.01)
        b.schedule(20)
    }
    on_neighbor_change: fun(b) { b.schedule(1) }
}

En Kotlin los manejadores son onStep, onInside, onRandomTick, onTick, onNeighborChange y onPlaced. Cada uno recibe un BlockEventContext con block y, si existe, entity:

content/Reactions.ktKotlin
block("pad") { onStep = { ctx -> ctx.entity?.velocity = Vector(0.0, 1.1, 0.0) } }

Portales

Un bloque con portal lleva a quien esté dentro a otra dimensión. Indica la dimensión de destino, o to y back para elegir adónde lleva desde allí:

content/portals.craftCraftScript
block "sky_gate" { portal: "gatemod:sky", light: 11 }

block "sky_gate_two_way" { portal: { to: "gatemod:sky", back: "minecraft:overworld" } }

La entidad llega al suelo en las mismas x y z y allí encuentra un bloque de portal para volver; si no hay ninguno cerca, se coloca uno junto a la llegada. Las entidades esperan un momento antes de volver a usar un portal. Los bloques de portal dejan pasar a las entidades. La dimensión se declara con dimension (ver @dim@). En Kotlin:

content/Portals.ktKotlin
block("sky_gate") { portal("gatemod:sky") }

Estados de bloque

states da al bloque valores que recuerda y puede mostrar:

content/states.craftCraftScript
block "lamp" {
    model: "block/lamp"
    states: ["facing", "lit"]
    on_use: fun(p, b) { b.set_state("lit", !b.state("lit")); return true }
    on_neighbor_change: fun(b) { b.set_state("lit", b.redstone_power > 0) }
}

block "crop" { states: [{ stage: 3 }, { wet: true }] }
  • "facing": norte, este, sur u oeste. Se orienta hacia el jugador que coloca el bloque, y el modelo gira con él.
  • "lit": un nombre solo es un interruptor encendido/apagado, apagado por defecto. { lit: true } lo deja encendido por defecto.
  • { stage: 3 }: un número de 0 al máximo que indiques (de 1 a 15).
  • "facing_all": como "facing", pero también hacia arriba y hacia abajo. Se orienta hacia el jugador que lo coloca, y el modelo se inclina para arriba y para abajo.
  • { shape: ["top", "middle", "bottom"] }: uno de unos pocos nombres, el primero por defecto. Los nombres son letras minúsculas, dígitos y _.

Se leen y cambian con block.state("lit") y block.set_state("lit", true). También funcionan con los bloques del juego, por ejemplo el facing y el lit de un horno.

Un estado distinto del valor por defecto puede verse diferente. Añade una textura en textures/block/<id>_<nombre>.png (un interruptor encendido) o <id>_<nombre><n>.png (un número) o <id>_<valor>.png (un nombre), o un modelo en models/block/<id>_<nombre>.json. Primero se prueba la combinación completa (<id>_lit_stage2) y luego cada estado por separado. En el ejemplo, lamp.json y lamp_lit.json son los dos modelos del mod, por ejemplo con el padre minecraft:block/orientable y texturas de frente, lado y arriba.

Luz según el estado. light_when: "lit" hace que el light del bloque brille solo mientras ese interruptor está encendido, como en una lámpara:

content/lamp.craftCraftScript
block "lamp" {
    light: 15
    light_when: "lit"
    states: ["lit"]
    on_use: fun(p, b) { b.set_state("lit", !b.state("lit")); return true }
}

En Kotlin: facing(), facingAll(), toggle("lit"), number("stage", 3), choice("shape", "top", "middle", "bottom"), y block.state(…) y block.setState(…) en el código:

content/States.ktKotlin
block("lamp") {
    model = "block/lamp"
    facing()
    toggle("lit")
    number("stage", 3)
}

Efectos

Un mod puede añadir sus propios efectos de estado. Aparecen en la pantalla del jugador como los del juego y se dan y se leen de la misma manera.

content/frozen.craftCraftScript
effect "frozen" {
    color: "#88CCFF"
    kind: "harmful"
    on_tick: fun(e, level) { e.damage(level) }
}
  • color: el color de sus partículas y del fondo de su icono.
  • kind: beneficial, harmful o neutral.
  • on_tick: fun(e, level), se ejecuta cada segundo mientras una entidad tiene el efecto, con su nivel (1 es I).
  • El icono es textures/mob_effect/<id>.png del mod.

Se da con e.add_effect("mymod:frozen", 3, 1) (id, segundos, nivel) y se comprueba con e.has_effect("mymod:frozen"), como los efectos del juego (ver El mundo y los jugadores). En Kotlin:

content/Frozen.ktKotlin
content.effect("frozen") {
    color = 0x88CCFF
    kind = EffectKind.HARMFUL
    onTick = { e, level -> /* … */ }
}

Redstone

content/battery.craftCraftScript
block "battery" {
    texture: "minecraft:block/copper_block"
    redstone: true
    on_use: fun(p, b) { if b.state("power") > 0 { b.set_state("power", 0) } else { b.set_state("power", 15) }; return true }
}

redstone: true hace que el bloque emita una señal tan fuerte como su estado power, un número de 0 a 15 que se añade automáticamente. b.set_state("power", 15) lo enciende, y los cables, lámparas y puertas de alrededor lo siguen. block.redstone_power es la potencia que el bloque recibe de su alrededor, y on_neighbor_change se ejecuta cuando cambia (la lámpara de arriba lo usa).

En Kotlin: redstone = true y block.redstonePower.

content/Battery.ktKotlin
block("battery") {
    texture = "minecraft:block/copper_block"
    redstone = true
    // in a handler: ctx.block.redstonePower
}

Inventarios

content/crate.craftCraftScript
block "crate" { texture: "minecraft:block/barrel_side", inventory: 27 }

inventory: 27 da al bloque ese número de casillas (de 9 a 54, en filas de 9). Conserva sus objetos al reiniciar, al usarlo se abre una pantalla de cofre (salvo que su on_use se haya quedado con el clic) y al romperlo suelta lo que contiene. Con 1 a 8 casillas no hay pantalla: es el propio mod quien mete y saca los objetos.

Desde el código, block.inventory (también funciona con los cofres y barriles del juego) ofrece set(slot, item(…)), get(slot), count(id) y add(…). En Kotlin: inventory = 27.

content/Crate.ktKotlin
block("crate") {
    texture = "minecraft:block/barrel_side"
    inventory = 27
}

Objetos mostrados sobre un bloque. shows_item: 14 hace que el objeto de la primera casilla del bloque flote sobre él, girando, a tantos píxeles sobre su base. Todos los jugadores lo ven, y desaparece cuando la casilla se vacía o el bloque se rompe. Un pedestal toma el objeto de la mano del jugador y se lo devuelve:

content/pedestal.craftCraftScript
block "pedestal" {
    shape: [[2, 0, 2, 14, 12, 14]]
    inventory: 1
    shows_item: 14
    on_use: fun(p, b) {
        let inv = b.inventory
        if inv.get(0) == null and p.held_item != null {
            inv.set(0, p.held_item)
            p.set_held_item(null)
        } else if inv.get(0) != null {
            p.give(inv.get(0))
            inv.set(0, null)
        }
        return true
    }
}

player.set_held_item(stack) pone un objeto en la mano principal del jugador, o la vacía con null. En Kotlin: showsItem = 14 y player.setHeldItem(stack).

content/Pedestal.ktKotlin
block("pedestal") {
    box(2, 0, 2, 14, 12, 14)
    inventory = 1
    showsItem = 14
    onUse { ctx ->
        val inv = ctx.block.inventory!!
        val held = ctx.player.heldItem
        val shown = inv[0]
        if (shown == null && held != null) { inv[0] = held; ctx.player.setHeldItem(null) }
        else if (shown != null) { ctx.player.give(shown); inv[0] = null }
        true
    }
}

Texturas

Las texturas viajan dentro del mod; nadie tiene que instalar un paquete de recursos. El nombre del archivo es el id:

Mod Dónde
CraftScript (carpeta) mods/rubies/textures/item/ruby.png, mods/rubies/textures/block/ruby_ore.png
Kotlin o Java src/main/resources/assets/rubies/textures/item/ruby.png

Si un mod trae sus propios modelos, recetas o tablas de botín en esas mismas carpetas, Crafting los respeta.

En Kotlin

content/Blocks.ktKotlin
package com.example.rubies.content

object Blocks {
    fun register(content: ContentBuilder) {
        content.block("ruby_ore") {
            hardness = 3f
            requiresTool = ToolType.PICKAXE
            minTier = ToolTier.IRON
            drop("ruby", 1..2)
            drop("minecraft:diamond", chance = 0.1)
        }
        content.block("ruby_block") { hardness = 5f; luminance = 7; sound = SoundGroup.METAL }
    }
}

Ids. Sin namespace, un id es de tu mod ("ruby" es rubies:ruby). Para lo del juego escribe el namespace: "minecraft:diamond". No se puede registrar contenido en el namespace minecraft.