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
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")
}
}
}
}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).
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).
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:
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.
// 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 | 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_intlos 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é.