API
Blocs, objets et recettes
Tu déclares le contenu sous forme de liste de propriétés. Crafting crée les vrais objets du jeu au bon moment et génère les modèles, les tables de butin, les tags, les recettes et les traductions nécessaires. Tu n’écris aucun fichier de données du jeu.
Objets
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" }| Propriété | Valeurs | Par défaut |
|---|---|---|
stack ou max_stack |
1–99 | 64 |
rarity |
common, uncommon, rare, epic (couleur du nom) |
common |
glint |
reflet d’enchantement | false |
durability |
nombre ; impose stack: 1 |
0 |
fireproof |
ne brûle pas dans la lave ni dans le feu | false |
food |
nombre, ou { nutrition, saturation, always_edible } |
— |
tool |
"pickaxe", ou { type, tier, damage, speed } ; type : pickaxe (pioche), axe (hache), shovel (pelle), hoe (houe), sword (épée) |
— |
tab |
onglet de l’inventaire du mode Créatif (voir plus bas) | ingredients |
texture |
chemin de la texture | item/<id> |
on_use |
fun(player, stack) ; renvoie true si elle gère l’utilisation |
— |
armor |
{ slot, defense, toughness, knockback_resistance, texture } |
— |
on_hit |
fun(attacker, target, stack) |
— |
cooldown |
secondes | 0 |
Armures, armes et temps de recharge
Un objet avec armor peut être porté. slot vaut head, chest, legs ou feet. defense, toughness et knockback_resistance (de 0 à 1) sont les valeurs d'armure du jeu : un plastron en fer a 6 de défense, le diamant 2 de robustesse.
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 est son apparence une fois portée. frost désigne textures/entity/equipment/humanoid/frost.png dans le mod et, pour les jambes, textures/entity/equipment/humanoid_leggings/frost.png, avec la même disposition que les textures d'armure du jeu. Sans elle, l'armure ressemble à du fer.
on_hit s'exécute quand l'objet sert à frapper, que ce soit un joueur ou une créature.
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 secondes) bloque l'objet pendant ce temps après chaque utilisation que son on_use a prise en charge, et la barre d'accès rapide l'affiche. Depuis le code : player.set_cooldown("minecraft:feather", 2) et player.has_cooldown(id). En Kotlin : armor(EquipmentSlot.HEAD, defense = 3, texture = "frost") pour les armures et onHit = { ctx -> … } pour les armes (ctx.attacker, ctx.target, ctx.stack).
item("frost_helmet") { armor(EquipmentSlot.HEAD, defense = 3, texture = "frost") }Blocs
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] }| Propriété | Valeurs | Par défaut |
|---|---|---|
hardness |
nombre ; -1 = incassable |
1.5 |
resistance |
résistance aux explosions | = hardness |
light |
0–15 | 0 |
light_when |
un état interrupteur, comme "lit" : le bloc n’éclaire que lorsqu’il est allumé (voir États de bloc) |
toujours |
sound |
stone, wood, gravel, grass, metal, glass, wool, sand | stone |
like |
un bloc dont il est fait à l'image, celui du jeu ("minecraft:end_stone") ou le vôtre : sa dureté, sa résistance, son son et le fait qu'il faille le bon outil pour qu'il lâche quelque chose sont ceux de ce bloc |
— |
kind |
une des sortes de blocs du jeu : escaliers, porte, coffre, culture… (voir Sortes de blocs) | cube |
tool, tier |
outil nécessaire pour que le bloc lâche quelque chose, et le matériau minimum de cet outil : wood, stone, iron, diamond, netherite | —, wood |
drops, drop_count |
un seul objet : id ; nombre ou [min, max] |
le bloc lui-même, 1 |
loot |
plusieurs objets : [{ item, count, chance, tool, fortune }, …]. Chacun est tiré séparément ; count est un nombre ou [min, max] et chance va de 0 à 1 (1 par défaut). tool et fortune : voir Butin ci-dessous |
— |
friction |
0.6 normal, 0.98 glace | 0.6 |
transparent |
on voit à travers (verre, feuilles) | false |
has_item |
enregistre aussi l’objet du bloc ; sans lui, le bloc ne lâche rien, sauf si drops ou loot disent quoi |
true |
tab |
onglet de l’inventaire du mode Créatif | building_blocks |
on_use |
fun(player, block) ; renvoie true si elle gère l’utilisation. Un joueur qui s'accroupit avec quelque chose en main le pose à la place, comme avec les blocs du jeu |
— |
Onglets : building_blocks, colored_blocks, natural_blocks, functional_blocks, redstone_blocks, tools_and_utilities, combat, food_and_drinks, ingredients, spawn_eggs. En Kotlin, ils sont dans CreativeTabs.
Pour qu’une créature lâche quelque chose en plus à sa mort, ajoute-le à e.drops dans l’événement entity_death (voir Événements).
Les blocs qui ne sont pas des cubes, les blocs des sortes du jeu, les créatures, les minerais, les sons et les particules se déclarent de la même façon et ont leurs propres pages : Formes de blocs, Sortes de blocs, Créatures, Génération du monde, Sons et particules.
Butin : outils et fortune
Un objet de loot peut exiger un outil, et la fortune peut en donner davantage :
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": il n'est lâché que si le bloc est cassé avec Toucher de soie.tool: "shears": seulement avec des cisailles ou Toucher de soie, comme les feuilles et les lianes du jeu se lâchent elles-mêmes.- Quand certains butins exigent un outil, ceux qui n'en exigent pas n'ont lieu que si cet outil n'est pas utilisé : le minerai ci-dessus se lâche lui-même avec Toucher de soie et lâche ses rubis sinon.
fortune: true: la fortune en donne davantage, plus de soncountcomme avec les minerais du jeu, ou une meilleurechancecomme avec les pousses des feuilles.
En Kotlin : drop("ruby", 1..2, tool = null, fortune = true) et drop("ruby_ore", tool = DropTool.SILK_TOUCH).
block("ruby_ore") {
kind = BlockKind.ORE
xp = 1..4
drop("ruby", 1..2, tool = null, fortune = true)
drop("ruby_ore", tool = DropTool.SILK_TOUCH)
}Recettes
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 }Comportement à l’utilisation
on_use est la seule logique qui vit à côté des données. Si elle dépasse deux ou trois lignes, écris la fonction dans lib/ et importe-la :
import { lift } from "/lib/teleport"
item "lift_wand" { stack: 1, rarity: "uncommon", on_use: lift }fun lift(player, stack) {
player.teleport(player.location.add(0, 10, 0))
return true
}Des blocs qui réagissent
Un bloc peut exécuter du code quand il se passe quelque chose sur lui ou autour de lui. Chaque gestionnaire reçoit le bloc et, le cas échéant, l'entité.
| Propriété | S'exécute quand |
|---|---|
on_step: fun(block, entity) |
une entité marche sur le bloc. |
on_inside: fun(block, entity) |
une entité se trouve dans le bloc. Le bloc doit laisser passer les entités : un portail, une plante ou une forme non solide. |
on_random_tick: fun(block) |
de temps en temps, au hasard, comme la pousse des cultures : environ toutes les 68 secondes par bloc. |
on_tick: fun(block) |
le délai demandé avec block.schedule(ticks) est écoulé (20 ticks = 1 seconde). |
on_neighbor_change: fun(block) |
un bloc voisin a changé : il a été posé, cassé ou alimenté. |
on_placed: fun(block, entity) |
quelqu'un a posé le bloc ; entity est cette personne. |
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, les gestionnaires sont onStep, onInside, onRandomTick, onTick, onNeighborChange et onPlaced. Chacun reçoit un BlockEventContext avec block et, s'il y en a une, entity :
block("pad") { onStep = { ctx -> ctx.entity?.velocity = Vector(0.0, 1.1, 0.0) } }Portails
Un bloc avec portal emmène celui qui s'y trouve vers une autre dimension. Indiquez la dimension de destination, ou to et back pour choisir où il mène depuis là :
block "sky_gate" { portal: "gatemod:sky", light: 11 }
block "sky_gate_two_way" { portal: { to: "gatemod:sky", back: "minecraft:overworld" } }L'entité arrive au sol aux mêmes x et z et y trouve un bloc de portail pour revenir ; s'il n'y en a aucun à proximité, on en place un à côté de l'arrivée. Les entités attendent un moment avant de réutiliser un portail. Les blocs de portail laissent passer les entités. La dimension elle-même se déclare avec dimension (voir @dim@). En Kotlin :
block("sky_gate") { portal("gatemod:sky") }États de bloc
states donne à un bloc des valeurs qu'il retient et peut afficher :
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, est, sud ou ouest. Il est orienté vers le joueur qui le pose, et le modèle tourne avec lui."lit": un nom seul est un interrupteur marche/arrêt, éteint par défaut.{ lit: true }le rend allumé par défaut.{ stage: 3 }: un nombre de 0 au maximum indiqué (1 à 15)."facing_all": comme"facing", mais aussi vers le haut et vers le bas. Il est orienté vers le joueur qui pose le bloc, et le modèle est basculé pour le haut et le bas.{ shape: ["top", "middle", "bottom"] }: un nom parmi quelques-uns, le premier par défaut. Les noms sont faits de lettres minuscules, de chiffres et de_.
On les lit et on les change avec block.state("lit") et block.set_state("lit", true). Cela marche aussi pour les blocs du jeu, par exemple le facing et le lit d'un four.
Un état différent de sa valeur par défaut peut avoir un autre aspect. Ajoutez une texture dans textures/block/<id>_<nom>.png (un interrupteur allumé) ou <id>_<nom><n>.png (un nombre) ou <id>_<valeur>.png (un nom), ou un modèle dans models/block/<id>_<nom>.json. La combinaison complète (<id>_lit_stage2) est essayée en premier, puis chaque état seul. Dans l'exemple, lamp.json et lamp_lit.json sont les deux modèles du mod, par exemple avec le parent minecraft:block/orientable et des textures de face, de côté et de dessus.
Lumière selon l’état. light_when: "lit" fait que la light du bloc n’éclaire que lorsque cet interrupteur est allumé, comme une lampe :
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"), et block.state(…) et block.setState(…) dans le code :
block("lamp") {
model = "block/lamp"
facing()
toggle("lit")
number("stage", 3)
}Effets
Un mod peut ajouter ses propres effets de statut. Ils apparaissent à l’écran du joueur comme ceux du jeu et se donnent et se lisent de la même façon.
effect "frozen" {
color: "#88CCFF"
kind: "harmful"
on_tick: fun(e, level) { e.damage(level) }
}color: la couleur de ses particules et du fond de son icône.kind:beneficial,harmfulouneutral.on_tick:fun(e, level), s’exécute chaque seconde tant qu’une entité a l’effet, avec son niveau (1 correspond à I).- L’icône est le fichier
textures/mob_effect/<id>.pngdu mod.
On le donne avec e.add_effect("mymod:frozen", 3, 1) (id, secondes, niveau) et on le vérifie avec e.has_effect("mymod:frozen"), comme pour les effets du jeu (voir Le monde et les joueurs). En Kotlin :
content.effect("frozen") {
color = 0x88CCFF
kind = EffectKind.HARMFUL
onTick = { e, level -> /* … */ }
}Redstone
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 fait émettre au bloc un signal aussi fort que son état power, un nombre de 0 à 15 ajouté automatiquement. b.set_state("power", 15) l'allume, et les fils, lampes et portes autour suivent. block.redstone_power est la puissance que le bloc reçoit de son entourage, et on_neighbor_change s'exécute quand elle change (la lampe ci-dessus l'utilise).
En Kotlin : redstone = true et block.redstonePower.
block("battery") {
texture = "minecraft:block/copper_block"
redstone = true
// in a handler: ctx.block.redstonePower
}Inventaires
block "crate" { texture: "minecraft:block/barrel_side", inventory: 27 }inventory: 27 donne au bloc autant d'emplacements (de 9 à 54, par rangées de 9). Il garde ses objets d'un redémarrage à l'autre, l'utiliser ouvre un écran de coffre (sauf si son on_use a pris le clic), et le casser fait tomber son contenu. De 1 à 8 emplacements, il n'y a pas d'écran : c'est le mod qui y met et en retire les objets.
Dans le code, block.inventory (qui marche aussi pour les coffres et tonneaux du jeu) propose set(slot, item(…)), get(slot), count(id) et add(…). En Kotlin : inventory = 27.
block("crate") {
texture = "minecraft:block/barrel_side"
inventory = 27
}Objets montrés sur un bloc. shows_item: 14 fait flotter et tourner au-dessus du bloc l'objet de son premier emplacement, à ce nombre de pixels au-dessus de sa base. Tous les joueurs le voient, et il disparaît quand l'emplacement se vide ou que le bloc est cassé. Un piédestal prend l'objet que le joueur tient en main et le lui rend :
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) met un objet dans la main principale du joueur, ou la vide avec null. En Kotlin : showsItem = 14 et player.setHeldItem(stack).
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
}
}Textures
Les textures sont livrées dans le mod ; personne n’a besoin d’installer un pack de ressources. Le nom du fichier est l’id :
| Mod | Où |
|---|---|
| CraftScript (dossier) | mods/rubies/textures/item/ruby.png, mods/rubies/textures/block/ruby_ore.png |
| Kotlin ou Java | src/main/resources/assets/rubies/textures/item/ruby.png |
Si un mod fournit ses propres modèles, recettes ou tables de butin dans ces mêmes dossiers, Crafting les utilise.
En Kotlin
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 }
}
}Les ids. Sans espace de noms, un id appartient à ton mod ("ruby" est rubies:ruby). Pour le contenu du jeu, écris l’espace de noms : "minecraft:diamond". Tu ne peux pas enregistrer de contenu dans l’espace de noms minecraft.