API

Blöcke, Gegenstände und Rezepte

Du deklarierst Inhalte als Liste von Eigenschaften. Crafting erstellt die echten Spielobjekte zum richtigen Zeitpunkt und erzeugt die Modelle, Beutetabellen, Tags, Rezepte und Übersetzungen, die sie brauchen. Du schreibst keine Datendateien des Spiels.

Gegenstände

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" }
Eigenschaft Werte Standard
stack oder max_stack 1–99 64
rarity common, uncommon, rare, epic (Farbe des Namens) common
glint Verzauberungsglanz false
durability Zahl, erzwingt stack: 1 0
fireproof verbrennt nicht in Lava oder Feuer false
food Zahl oder { nutrition, saturation, always_edible } —
tool "pickaxe" oder { type, tier, damage, speed }; type: pickaxe, axe, shovel, hoe, sword —
tab Tab im Kreativinventar (siehe unten) ingredients
texture Pfad der Textur item/<id>
on_use fun(player, stack); gibt true zurück, wenn sie die Benutzung übernimmt —
armor { slot, defense, toughness, knockback_resistance, texture } —
on_hit fun(attacker, target, stack) —
cooldown Sekunden 0

Rüstung, Waffen und Abklingzeiten

Ein Gegenstand mit armor lässt sich tragen. slot ist head, chest, legs oder feet. defense, toughness und knockback_resistance (0 bis 1) sind die Rüstungswerte des Spiels: Ein Eisenbrustpanzer hat 6 Verteidigung, Diamant 2 Härte.

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 bestimmt, wie sie getragen aussieht. frost bedeutet textures/entity/equipment/humanoid/frost.png in der Mod und für die Beine textures/entity/equipment/humanoid_leggings/frost.png, mit demselben Aufbau wie die Rüstungstexturen des Spiels. Ohne sie sieht die Rüstung wie Eisen aus.

on_hit läuft, wenn der Gegenstand zum Schlagen benutzt wird, von einem Spieler oder einem 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 (in Sekunden) sperrt den Gegenstand nach jeder Benutzung, die sein on_use übernommen hat, für diese Zeit; die Schnellleiste zeigt es an. Aus dem Code: player.set_cooldown("minecraft:feather", 2) und player.has_cooldown(id). In Kotlin: armor(EquipmentSlot.HEAD, defense = 3, texture = "frost") für Rüstung und onHit = { ctx -> … } für Waffen (ctx.attacker, ctx.target, ctx.stack).

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

Blöcke

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] }
Eigenschaft Werte Standard
hardness Zahl; -1 = unzerstörbar 1.5
resistance Explosionswiderstand = hardness
light 0–15 0
light_when ein Schalter-Zustand wie "lit": Der Block leuchtet nur, solange er an ist (siehe Blockzustände) immer
sound stone, wood, gravel, grass, metal, glass, wool, sand stone
like ein Block, nach dessen Vorbild er gemacht wird, aus dem Spiel ("minecraft:end_stone") oder von dir: Härte, Explosionswiderstand, Geräusch und ob das richtige Werkzeug nötig ist, damit etwas fällt, sind die dieses Blocks —
kind eine der Arten des Spiels: Treppe, Tür, Truhe, Nutzpflanze… (siehe Blockarten) cube
tool, tier Werkzeug, das nötig ist, damit der Block etwas fallen lässt, und das Mindestmaterial dieses Werkzeugs: wood, stone, iron, diamond, netherite —, wood
drops, drop_count ein einzelner Gegenstand: ID; Zahl oder [min, max] der Block selbst, 1
loot mehrere Gegenstände: [{ item, count, chance, tool, fortune }, …]. Jeder wird einzeln ausgewürfelt; count ist eine Zahl oder [min, max], chance geht von 0 bis 1 (Standard 1). tool und fortune: siehe Drops weiter unten —
friction 0.6 normal, 0.98 Eis 0.6
transparent man kann hindurchsehen (Glas, Laub) false
has_item auch den Gegenstand des Blocks registrieren; ohne einen lässt der Block nichts fallen, außer drops oder loot sagen, was true
tab Tab im Kreativinventar building_blocks
on_use fun(player, block); gibt true zurück, wenn sie die Benutzung übernimmt. Ein Spieler, der sich duckt und etwas in der Hand hält, platziert es stattdessen, wie bei den Blöcken des Spiels —

Tabs: building_blocks, colored_blocks, natural_blocks, functional_blocks, redstone_blocks, tools_and_utilities, combat, food_and_drinks, ingredients, spawn_eggs. In Kotlin stehen sie in CreativeTabs.

Damit eine Kreatur beim Tod zusätzlich etwas fallen lässt, füg es im Event entity_death zu e.drops hinzu (siehe Events).

Blöcke, die keine Würfel sind, Blöcke der Arten des Spiels, Kreaturen, Erze, Geräusche und Partikel werden genauso deklariert und haben eigene Seiten: Blockformen, Blockarten, Kreaturen, Weltgenerierung, Geräusche und Partikel.

Drops: Werkzeuge und Glück

Ein Drop in loot kann ein Werkzeug verlangen, und Glück kann mehr davon geben:

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": Er fällt nur, wenn der Block mit Behutsamkeit abgebaut wird. tool: "shears": nur mit einer Schere oder Behutsamkeit, so wie die Blätter und Ranken des Spiels sich selbst fallen lassen.
  • Wenn manche Drops ein Werkzeug verlangen, fallen die Drops ohne eines nur, wenn dieses Werkzeug nicht benutzt wird: Das Erz oben lässt sich selbst mit Behutsamkeit fallen und sonst seine Rubine.
  • fortune: true: Glück gibt mehr davon, mehr von seinem count wie bei den Erzen des Spiels oder eine bessere chance wie bei Setzlingen aus Blättern.

In Kotlin: drop("ruby", 1..2, tool = null, fortune = true) und 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)
}

Rezepte

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 }

Verhalten beim Benutzen

on_use ist die einzige Logik, die neben den Daten steht. Wird sie länger als ein paar Zeilen, schreib die Funktion in lib/ und importiere sie:

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
}

Blöcke, die reagieren

Ein Block kann Code ausführen, wenn mit ihm oder in seiner Umgebung etwas geschieht. Jeder Handler erhält den Block und, wo es passt, die Entität.

Eigenschaft Läuft, wenn
on_step: fun(block, entity) eine Entität auf den Block tritt.
on_inside: fun(block, entity) eine Entität sich im Block befindet. Der Block muss Entitäten durchlassen: ein Portal, eine Pflanze oder eine nicht feste Form.
on_random_tick: fun(block) hin und wieder zufällig, wie wachsende Feldfrüchte: etwa alle 68 Sekunden pro Block.
on_tick: fun(block) die mit block.schedule(ticks) angeforderte Zeit verstrichen ist (20 Ticks = 1 Sekunde).
on_neighbor_change: fun(block) sich ein benachbarter Block geändert hat: gesetzt, abgebaut oder mit Signal versorgt.
on_placed: fun(block, entity) jemand den Block platziert hat; entity ist die Person.
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) }
}

In Kotlin heißen die Handler onStep, onInside, onRandomTick, onTick, onNeighborChange und onPlaced. Jeder erhält einen BlockEventContext mit block und, falls vorhanden, entity:

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

Portale

Ein Block mit portal bringt jeden, der darin steht, in eine andere Dimension. Gib die Zieldimension an, oder to und back, um zu wählen, wohin es von dort aus zurückgeht:

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

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

Die Entität landet am Boden bei denselben x und z und findet dort einen Portalblock für den Rückweg; ist keiner in der Nähe, wird neben der Ankunft einer gesetzt. Entitäten warten einen Moment, bevor sie ein Portal erneut nutzen. Portalblöcke lassen Entitäten durch. Die Dimension selbst deklarierst du mit dimension (siehe @dim@). In Kotlin:

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

Blockzustände

states gibt einem Block Werte, die er sich merkt und anzeigen kann:

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": Nord, Ost, Süd oder West. Er wird zum platzierenden Spieler ausgerichtet, und das Modell dreht sich mit.
  • "lit": Ein Name allein ist ein Ein/Aus-Schalter, standardmäßig aus. { lit: true } macht ihn standardmäßig an.
  • { stage: 3 }: eine Zahl von 0 bis zum angegebenen Maximum (1 bis 15).
  • "facing_all": wie "facing", aber auch nach oben und unten. Er wird zum platzierenden Spieler ausgerichtet, und das Modell wird für oben und unten gekippt.
  • { shape: ["top", "middle", "bottom"] }: einer von wenigen Namen, standardmäßig der erste. Namen bestehen aus Kleinbuchstaben, Ziffern und _.

Lesen und ändern kannst du sie mit block.state("lit") und block.set_state("lit", true). Das funktioniert auch bei den Blöcken des Spiels, etwa facing und lit eines Ofens.

Ein vom Standard abweichender Zustand kann anders aussehen. Lege eine Textur unter textures/block/<id>_<name>.png (ein eingeschalteter Schalter) oder <id>_<name><n>.png (eine Zahl) oder <id>_<value>.png (ein Name) ab, oder ein Modell unter models/block/<id>_<name>.json. Zuerst wird die ganze Kombination (<id>_lit_stage2) versucht, dann jeder Zustand einzeln. Im Beispiel sind lamp.json und lamp_lit.json die zwei Modelle der Mod, etwa mit dem Parent minecraft:block/orientable und Texturen für Vorderseite, Seite und Oberseite.

Licht je nach Zustand. light_when: "lit" lässt das light des Blocks nur leuchten, solange dieser Schalter an ist, wie bei einer Lampe:

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

In Kotlin: facing(), facingAll(), toggle("lit"), number("stage", 3), choice("shape", "top", "middle", "bottom") sowie block.state(…) und block.setState(…) im Code:

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

Effekte

Ein Mod kann eigene Statuseffekte hinzufügen. Sie erscheinen wie die des Spiels auf dem Bildschirm des Spielers und werden auf dieselbe Weise vergeben und gelesen.

content/frozen.craftCraftScript
effect "frozen" {
    color: "#88CCFF"
    kind: "harmful"
    on_tick: fun(e, level) { e.damage(level) }
}
  • color: die Farbe seiner Partikel und des Hintergrunds seines Symbols.
  • kind: beneficial, harmful oder neutral.
  • on_tick: fun(e, level), läuft jede Sekunde, solange eine Entität den Effekt hat, mit dessen Stufe (1 ist I).
  • Das Symbol ist textures/mob_effect/<id>.png der Mod.

Vergib ihn mit e.add_effect("mymod:frozen", 3, 1) (Id, Sekunden, Stufe) und prüfe ihn mit e.has_effect("mymod:frozen"), wie bei den Effekten des Spiels (siehe Die Welt und die Spieler). In 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 lässt den Block ein Signal abgeben, so stark wie sein Zustand power, eine Zahl von 0 bis 15, die automatisch hinzukommt. b.set_state("power", 15) schaltet ihn ein, und Leitungen, Lampen und Türen ringsum folgen. block.redstone_power ist die Stärke, die der Block aus der Umgebung erhält, und on_neighbor_change läuft, wenn sie sich ändert (die Lampe oben nutzt das).

In Kotlin: redstone = true und block.redstonePower.

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

Inventare

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

inventory: 27 gibt dem Block so viele Plätze (9 bis 54, in Reihen zu 9). Er behält seine Gegenstände über Neustarts hinweg, beim Benutzen öffnet sich eine Truhenoberfläche (es sei denn, sein on_use hat den Klick übernommen), und beim Abbauen fällt der Inhalt heraus. Bei 1 bis 8 Plätzen gibt es keine Oberfläche: Die Mod legt Gegenstände selbst hinein und nimmt sie heraus.

Im Code bietet block.inventory (funktioniert auch bei den Truhen und Fässern des Spiels) set(slot, item(…)), get(slot), count(id) und add(…). In Kotlin: inventory = 27.

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

Gegenstände auf einem Block anzeigen. shows_item: 14 lässt den Gegenstand im ersten Platz des Blocks sich drehend über ihm schweben, so viele Pixel über seiner Unterseite. Jeder Spieler sieht ihn, und er verschwindet, wenn der Platz leer wird oder der Block abgebaut wird. Ein Podest nimmt den Gegenstand aus der Hand des Spielers und gibt ihn zurück:

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) legt einen Gegenstand in die Haupthand des Spielers oder leert sie mit null. In Kotlin: showsItem = 14 und 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
    }
}

Texturen

Texturen werden mit der Mod ausgeliefert, niemand muss ein Ressourcenpaket installieren. Der Dateiname ist die ID:

Mod Wo
CraftScript (Ordner) mods/rubies/textures/item/ruby.png, mods/rubies/textures/block/ruby_ore.png
Kotlin oder Java src/main/resources/assets/rubies/textures/item/ruby.png

Liefert eine Mod in denselben Ordnern eigene Modelle, Rezepte oder Beutetabellen mit, nutzt Crafting diese.

In 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. Ohne Namensraum gehört eine ID deiner Mod ("ruby" ist rubies:ruby). Für Inhalte des Spiels schreibst du den Namensraum: "minecraft:diamond". Im Namensraum minecraft kannst du keine Inhalte registrieren.