API
Интерфейс
Формы, которые заполняет игрок, и элементы на экране: полосы босса и боковая панель. Всё это работает на любом клиенте, установлен на нём Crafting или нет.
Формы
У формы есть заголовок, основной текст, поля и кнопки. Ты объявляешь её в файле в ui/ и показываешь там, где нужно (в команде, в событии, при использовании предмета):
import { give_rubies } from "/lib/rewards"
const SHOP = form("Ruby shop", {
body: "Rubies cost 10 emeralds each.",
fields: [
{ slider: "amount", label: "Rubies", min: 1, max: 16, default: 1 },
{ toggle: "gift", label: "Wrap as a gift" },
{ choice: "pouch", label: "Pouch", options: ["leather", "silk"] },
{ text: "note", label: "Note" }
],
buttons: [{ id: "buy", label: "Buy" }, "cancel"]
})
fun open_shop(p: Player) {
p.show_form(SHOP, fun(r) {
if r.button != "buy" { return } // closed with Esc or cancelled
let n = int(r.number("amount") ?? 1)
if p.inventory.count("minecraft:emerald") < n * 10 { p.send("&cNot enough emeralds"); return }
give_rubies(p, n)
if r.toggle("gift") { p.send("&dWrapped in {r.choice("pouch")}: {r.text("note")}") }
})
}import { open_shop } from "/ui/shop"
command shop describe "Buy rubies" {
if player == null { return "Players only" }
open_shop(player)
}| Поле | Как записать | Как прочитать |
|---|---|---|
| Текст | { text: "note", label: "Заметка", default: "" } |
r.text("note") |
| Переключатель | { toggle: "gift", label: "Это подарок", default: false } |
r.toggle("gift") |
| Ползунок | { slider: "amount", label: "Количество", min: 1, max: 64, step: 1, default: 8 } |
r.number("amount") |
| Выбор | { choice: "color", label: "Цвет", options: ["red", "blue"], default: "red" } |
r.choice("color") |
- Ключ каждого поля состоит из строчных букв, цифр и
_.label— то, что видит игрок; если его нет, используется ключ. buttons— список{ id, label }или просто id. Форма без кнопок получает кнопку «OK».- В ответе
r.button— id нажатой кнопки илиnull, если игрок закрыл форму (Esc).r.values— словарь со всеми полями. - Ответ приходит в функцию, которую ты передаёшь в
show_form; пока игрок решает, остальной сервер продолжает работать.
На Kotlin
package com.example.rubies.ui
object ShopForm {
private val form = Form("Ruby shop").apply {
body = "Rubies cost 10 emeralds each."
slider("amount", "Rubies", 1.0, 16.0, default = 1.0)
toggle("gift", "Wrap as a gift")
choice("pouch", "Pouch", listOf("leather", "silk"))
text("note", "Note")
button("buy", "Buy")
button("cancel", "Cancel")
}
fun show(player: Player) = player.showForm(form) { r ->
if (r.button != "buy") return@showForm // closed with Esc or cancelled
val n = (r.number("amount") ?: 1.0).toInt()
if (player.inventory.count(Identifier.parse("minecraft:emerald")) < n * 10) { player.send("&cNot enough emeralds"); return@showForm }
player.give(ItemStack.of(Items.RUBY, n))
if (r.toggle("gift") == true) player.send("&dWrapped in ${r.choice("pouch")}: ${r.text("note")}")
}
}Form(title) с body, text(key, label, default, maxLength), toggle(key, label, default), slider(key, label, min, max, step, default), choice(key, label, options, default) и button(id, label). player.showForm(form) { r -> … } получает FormResponse с button, values и text, toggle, number, choice.
Полосы босса
Полоса вверху экрана с заголовком, цветом, прогрессом и стилем. Используй её для таймера, серверного события или здоровья чего-либо:
const TIMER = server.boss_bar("rubies:countdown", "&cРубиновая лихорадка", "red", "segments_10")
let left = 60
on join { TIMER.show(player) }
every 1 second {
left = max(0, left - 1)
TIMER.progress = left / 60
TIMER.title = "&cРубиновая лихорадка: {left} с"
if left == 0 { TIMER.remove() }
}| Член | Что делает |
|---|---|
server.boss_bar(id, title?, color?, style?) |
Создаёт полосу или возвращает существующую с этим id. Один id на полосу: перезагрузка мода её не дублирует. |
bar.progress |
От 0 до 1. |
bar.title |
Текст, с цветами через &. |
bar.color |
pink, blue, red, green, yellow, purple, white. |
bar.style |
solid, segments_6, segments_10, segments_12, segments_20. |
bar.show(player), bar.hide(player) |
Кто её видит. bar.players перечисляет их. |
bar.remove() |
Убирает её у всех и освобождает id. |
На Kotlin: Crafting.server?.bossBar("rubies:countdown", "Время", BarColor.RED, BarStyle.SEGMENTS_10), с теми же свойствами в camelCase.
Боковая панель
Список до 15 строк в правой части экрана, свой для каждого игрока. Вызови снова, чтобы обновить:
import { visits } from "/lib/storage"
on join {
player.set_sidebar("&6Рубины", [
"&fВизиты: &e{visits(player)}",
"&fРубины: &c{player.inventory.count("rubies:ruby")}"
])
}player.set_sidebar(title, lines)показывает или обновляет её; видит её только этот игрок. Цвета через&.player.clear_sidebar()убирает её.- На Kotlin:
player.setSidebar(title, lines)иplayer.clearSidebar().
Клавиши мода
Мод может добавлять собственные клавиши. Их объявляют через key, а реагируют через on key, который выполняется на сервере для игрока, нажавшего клавишу. e.key — это id с пространством имён мода (dashmod:dash).
key "dash" { label: "Dash", default: "R" }
key "heal" { label: "Second wind", default: "G" }
on key(e) {
let p = e.player
if e.key == "dashmod:dash" && !p.has_cooldown("minecraft:feather") {
let d = p.direction
p.velocity = vector(d.x * 1.6, 0.35, d.z * 1.6)
p.set_cooldown("minecraft:feather", 2)
}
if e.key == "dashmod:heal" { p.heal(6) }
}Клавиши появляются в Настройки > Управление > Привязка клавиш, в разделе с названием мода. Игроки могут их менять, и их выбор сохраняется. default — название клавиши, например "R", "G", "F6" или "LEFT_ALT".
Чтобы клавиши были доступны, у игроков в игре должен быть установлен Crafting. В Kotlin: ContentBuilder.key("dash", label = "Dash", default = "R") и Crafting.events.on<PlayerKeyEvent> { e -> … }.
Полезно знать
- Формы, полосы и боковую панель видит любой клиент Minecraft Java 26.3, с Crafting или без. Серверный мод может использовать их, и никому не нужно ничего устанавливать.
- Титры, панель действий и сообщения в чате описаны на странице Мир и игроки.
- Собственных экранов со своей раскладкой (меню, инвентари механизмов) пока нет; смотри дорожную карту.