API
Блоки, предмети й рецепти
Вміст оголошується як список властивостей. Crafting створює справжні ігрові об’єкти в потрібний момент і генерує потрібні їм моделі, таблиці здобичі, теги, рецепти й переклади. Жодних файлів ігрових даних ти не пишеш.
Предмети
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" }| Властивість | Значення | За замовчуванням |
|---|---|---|
stack або max_stack |
1–99 | 64 |
rarity |
common, uncommon, rare, epic (колір назви) |
common |
glint |
сяйво зачарування | false |
durability |
число; примусово задає stack: 1 |
0 |
fireproof |
не горить у лаві чи вогні | false |
food |
число або { nutrition, saturation, always_edible } |
— |
tool |
"pickaxe" або { type, tier, damage, speed }; type: pickaxe, axe, shovel, hoe, sword |
— |
tab |
вкладка інвентарю творчого режиму (нижче) | ingredients |
texture |
шлях до текстури | item/<id> |
on_use |
fun(player, stack); повертає true, якщо обробляє використання |
— |
armor |
{ slot, defense, toughness, knockback_resistance, texture } |
— |
on_hit |
fun(attacker, target, stack) |
— |
cooldown |
секунди | 0 |
Броня, зброя та перезарядка
Предмет з armor можна вдягти. slot — це head, chest, legs або feet. defense, toughness і knockback_resistance (від 0 до 1) — значення броні з гри: залізний нагрудник має 6 захисту, діамант 2 міцності.
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 — вигляд вдягненої броні. frost означає textures/entity/equipment/humanoid/frost.png у моді та, для ніг, textures/entity/equipment/humanoid_leggings/frost.png, з тим самим розташуванням, що й текстури броні гри. Без неї броня виглядає як залізна.
on_hit спрацьовує, коли предметом б'ють, чи то гравець, чи моб.
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 (у секундах) блокує предмет на цей час після кожного використання, яке обробив його on_use, і панель швидкого доступу це показує. З коду: player.set_cooldown("minecraft:feather", 2) і player.has_cooldown(id). У Kotlin: armor(EquipmentSlot.HEAD, defense = 3, texture = "frost") для броні та onHit = { ctx -> … } для зброї (ctx.attacker, ctx.target, ctx.stack).
item("frost_helmet") { armor(EquipmentSlot.HEAD, defense = 3, texture = "frost") }Блоки
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] }| Властивість | Значення | За замовчуванням |
|---|---|---|
hardness |
число; -1 = незламний |
1.5 |
resistance |
вибухостійкість | = hardness |
light |
0–15 | 0 |
light_when |
стан-перемикач, наприклад "lit": блок світиться, лише поки він увімкнений (див. «Стани блока») |
завжди |
sound |
stone, wood, gravel, grass, metal, glass, wool, sand | stone |
like |
блок, за зразком якого він зроблений, ігровий ("minecraft:end_stone") або твій: міцність, вибухостійкість, звук і те, чи потрібен правильний інструмент, щоб щось випало, беруться з цього блока |
— |
kind |
один із видів блоків гри: сходи, двері, скриня, посів… (див. Види блоків) | cube |
tool, tier |
інструмент, без якого з блока нічого не випадає, і мінімальний матеріал цього інструмента: wood, stone, iron, diamond, netherite | —, wood |
drops, drop_count |
один предмет: id; число або [min, max] |
сам блок, 1 |
loot |
кілька предметів: [{ item, count, chance, tool, fortune }, …]. Кожен розігрується окремо; count — число або [min, max], а chance — від 0 до 1 (за замовчуванням 1). tool і fortune: див. «Здобич: інструменти й удача» нижче |
— |
friction |
0.6 звичайне, 0.98 лід | 0.6 |
transparent |
крізь нього видно (скло, листя) | false |
has_item |
також реєструвати предмет блока; без нього блок нічого не дає, якщо drops чи loot не кажуть, що саме |
true |
tab |
вкладка інвентарю творчого режиму | building_blocks |
on_use |
fun(player, block); повертає true, якщо обробляє використання. Гравець, який крадеться з предметом у руці, натомість ставить його, як з ігровими блоками |
— |
Вкладки: building_blocks, colored_blocks, natural_blocks, functional_blocks, redstone_blocks, tools_and_utilities, combat, food_and_drinks, ingredients, spawn_eggs. У Kotlin вони є в CreativeTabs.
Щоб з істоти після смерті випадало щось додаткове, додай це до e.drops у події entity_death (дивись Події).
Блоки не у формі куба, блоки видів гри, істоти, руди, звуки й частинки оголошуються так само й мають власні сторінки: Форми блоків, Види блоків, Істоти, Генерація світу, Звуки й частинки.
Здобич: інструменти й удача
Для предмета в loot може знадобитися інструмент, а удача може дати його більше:
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": випадає, лише коли блок зламано з шовковим дотиком.tool: "shears": лише з ножицями або шовковим дотиком, як випадає саме листя й ліани в грі.- Коли для деяких предметів потрібен інструмент, предмети без нього випадають, лише якщо цей інструмент не використано: руда вище випадає сама з шовковим дотиком, а інакше дає рубіни.
fortune: true: удача дає його більше, більше йогоcount, як в ігрових руд, або кращийchance, як у саджанців із листя.
У Kotlin: drop("ruby", 1..2, tool = null, fortune = true) і 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)
}Рецепти
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 }Поведінка під час використання
on_use — єдина логіка, що живе поруч із даними. Якщо вона розростається понад кілька рядків, напиши функцію в lib/ та імпортуй її:
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
}Блоки, що реагують
Блок може виконувати код, коли щось відбувається з ним або поруч із ним. Кожен обробник отримує блок і, де це доречно, сутність.
| Властивість | Виконується, коли |
|---|---|
on_step: fun(block, entity) |
сутність наступає на блок. |
on_inside: fun(block, entity) |
сутність перебуває всередині блока. Блок має пропускати сутності: портал, рослина або неповна форма. |
on_random_tick: fun(block) |
час від часу, випадково, як ріст посівів: приблизно раз на 68 секунд на блок. |
on_tick: fun(block) |
минув час, замовлений через block.schedule(ticks) (20 тіків = 1 секунда). |
on_neighbor_change: fun(block) |
змінився сусідній блок: його поставили, зламали або подали на нього сигнал. |
on_placed: fun(block, entity) |
хтось поставив блок; entity — це хто. |
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) }
}У Kotlin обробники називаються onStep, onInside, onRandomTick, onTick, onNeighborChange і onPlaced. Кожен отримує BlockEventContext з block і, якщо є, entity:
block("pad") { onStep = { ctx -> ctx.entity?.velocity = Vector(0.0, 1.1, 0.0) } }Портали
Блок із portal переносить кожного, хто всередині, в інший вимір. Вкажіть вимір призначення або to і back, щоб вибрати, куди він веде звідти:
block "sky_gate" { portal: "gatemod:sky", light: 11 }
block "sky_gate_two_way" { portal: { to: "gatemod:sky", back: "minecraft:overworld" } }Сутність з'являється на землі в тих самих x і z та знаходить там блок порталу, щоб повернутися; якщо поблизу його немає, поруч із місцем прибуття ставиться новий. Перш ніж знову увійти в портал, сутності трохи чекають. Блоки порталів пропускають сутності. Сам вимір оголошується через dimension (див. @dim@). У Kotlin:
block("sky_gate") { portal("gatemod:sky") }Стани блока
states дає блоку значення, які він пам'ятає і може показувати:
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": північ, схід, південь або захід. Блок повертається обличчям до гравця, який його ставить, і модель повертається разом із ним."lit": саме ім'я означає перемикач вкл/викл, за замовчуванням вимкнений.{ lit: true }робить його ввімкненим за замовчуванням.{ stage: 3 }: число від 0 до вказаного максимуму (від 1 до 15)."facing_all": як"facing", але ще вгору й униз. Блок дивиться на гравця, який його ставить, а модель перевертається для напрямків угору й униз.{ shape: ["top", "middle", "bottom"] }: одне з кількох імен, за замовчуванням перше. Імена складаються з малих літер, цифр і_.
Читати й змінювати їх можна через block.state("lit") і block.set_state("lit", true). Це працює і для блоків самої гри, наприклад facing та lit печі.
Стан, відмінний від значення за замовчуванням, може виглядати інакше. Додайте текстуру в textures/block/<id>_<ім'я>.png (ввімкнений перемикач) або <id>_<ім'я><n>.png (число) або <id>_<значення>.png (назва) чи модель у models/block/<id>_<ім'я>.json. Спершу пробується вся комбінація (<id>_lit_stage2), потім кожен стан окремо. У прикладі lamp.json і lamp_lit.json — дві моделі мода, наприклад із батьківською minecraft:block/orientable та текстурами лицьового боку, бічного й верху.
Світло за станом. light_when: "lit" робить так, що light блока світиться, лише поки цей перемикач увімкнений, як у лампи:
block "lamp" {
light: 15
light_when: "lit"
states: ["lit"]
on_use: fun(p, b) { b.set_state("lit", !b.state("lit")); return true }
}У Kotlin: facing(), facingAll(), toggle("lit"), number("stage", 3), choice("shape", "top", "middle", "bottom"), а в коді — block.state(…) і block.setState(…):
block("lamp") {
model = "block/lamp"
facing()
toggle("lit")
number("stage", 3)
}Ефекти
Мод може додавати власні ефекти стану. Вони відображаються на екрані гравця так само, як ефекти гри, і накладаються та перевіряються так само.
effect "frozen" {
color: "#88CCFF"
kind: "harmful"
on_tick: fun(e, level) { e.damage(level) }
}color: колір його частинок і тла значка.kind:beneficial,harmfulабоneutral.on_tick:fun(e, level), виконується щосекунди, поки в сутності є ефект, з його рівнем (1 — це I).- Значок — це
textures/mob_effect/<id>.pngмода.
Накладіть його через e.add_effect("mymod:frozen", 3, 1) (id, секунди, рівень) і перевірте через e.has_effect("mymod:frozen"), як з ефектами гри (див. Світ і гравці). У Kotlin:
content.effect("frozen") {
color = 0x88CCFF
kind = EffectKind.HARMFUL
onTick = { e, level -> /* … */ }
}Редстоун
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 змушує блок випромінювати сигнал такої сили, як його стан power — число від 0 до 15, яке додається автоматично. b.set_state("power", 15) вмикає його, а дроти, лампи й двері навколо йдуть за ним. block.redstone_power — потужність, яку блок отримує від оточення, а on_neighbor_change виконується, коли вона змінюється (так працює лампа вище).
У Kotlin: redstone = true і block.redstonePower.
block("battery") {
texture = "minecraft:block/copper_block"
redstone = true
// in a handler: ctx.block.redstonePower
}Інвентарі
block "crate" { texture: "minecraft:block/barrel_side", inventory: 27 }inventory: 27 дає блоку стільки комірок (від 9 до 54, рядами по 9). Предмети зберігаються між перезапусками, під час використання відкривається екран скрині (якщо лише його on_use не забрав клік), а під час руйнування випадає все, що в ньому лежить. Від 1 до 8 комірок екрана немає: мод сам кладе предмети й забирає їх.
У коді block.inventory (працює і для скринь та бочок гри) надає set(slot, item(…)), get(slot), count(id) і add(…). У Kotlin: inventory = 27.
block("crate") {
texture = "minecraft:block/barrel_side"
inventory = 27
}Предмети, показані на блоці. shows_item: 14 змушує предмет із першої комірки блока ширяти над ним, обертаючись, на стільки пікселів вище за його низ. Його бачать усі гравці, і він зникає, коли комірка порожніє або блок ламається. П’єдестал бере предмет із руки гравця й повертає його:
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) кладе предмет в основну руку гравця або спорожнює її через null. У Kotlin: showsItem = 14 і 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
}
}Текстури
Текстури постачаються всередині мода; нікому не треба встановлювати набір ресурсів. Назва файлу — це id:
| Мод | Де |
|---|---|
| CraftScript (тека) | mods/rubies/textures/item/ruby.png, mods/rubies/textures/block/ruby_ore.png |
| Kotlin або Java | src/main/resources/assets/rubies/textures/item/ruby.png |
Якщо мод має власні моделі, рецепти чи таблиці здобичі в тих самих теках, Crafting використовує їх.
У 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 }
}
}Id. Без простору назв id належить твоєму моду ("ruby" — це rubies:ruby). Для вмісту гри вказуй простір назв: "minecraft:diamond". Реєструвати вміст у просторі назв minecraft не можна.