Перейти к основному содержанию

Первый предмет

Мы называем предметами вещи, которые находятся в инвентаре или контейнере. Эта обширная категория включает в себя материалы для крафта, еду, инструменты, броню и подобные. Существуют даже бесполезные предметы, вроде гнилой картошки. Игрок может взаимодействовать с ними, надевать на себя, кидать или съедать, это основные игровые объекты для мира и начала изучения.

Создадим текстуру

Это первый и самый главный шаг к созданию предмета, от визуально приятной текстуры зависит многое, и возможно даже, общее впечатление от нововведения. Внутреигровые тексуры предметов представляют собой растровые изображения (.png или .tga) размером 16x16 пикселей. И если размер, при необходимости, может быть каким угодно, то расширения файлов ограничены лишь этими двумя.

Создайте новую текстуру или используйте существующую, во втором случае убедитесь что она представлена в поддерживаемом формате. Для примера мы перекрасили стандартную текстуру палки, это вполне распространенная практика — например, текстуры руд и инструментов в некоторых модах созданы именно так.

stick_0.png -> oxidized_stick_0.png

Поместим ее в ресурсы

Текстуры для предметов располагаются в подпапке items-opaque в одной или нескольких папках ваших ресурсов. Прежде всего, убедитесь что build.config содержит хотя бы один ресурс с типом resource:

build.config
{
...
"resources": [
...
{
"path": "assets/resources/",
"resourceType": "resource"
}
]
}

Так выглядит часть содержимого папки с текстурами предметов в игре:

/assets/resource_packs/vanilla/textures/items
├─ apple.png
├─ apple_golden.png
├─ armor_stand.png
└─ ...

Формат именования файлов текстур предметов в Inner Core немного отличается от него: some_texture_<мета>.png, где мета - целочисленное число, определяющее вариацию текстуры. Оставим ее нулем.

Создали папку items-opaque в одной из папок ресурсов? Теперь поместите текстуру с правильным названием в нее. В примере полным путем будет что-то вроде assets/resources/items-opaque/oxidized_stick_0.png. Все готово!

Зарегистрируем предмет

Перед этим создайте файл в вашей рабочей директории мода (например, папке dev/) или откройте существующий скрипт. Не забудьте включить его в .includes если это необходимо. Мы будем работать в файле oxidized_stick.js.

Для начала нам необходимо зарезервировать за собой идентификатор:

IDRegistry.genItemID("oxidized_stick");

А теперь мы можем создать и сам предмет:

Item.createItem("oxidized_stick", "item.oxidized_stick.name", {
name: "oxidized_stick", data: 0
}, { stack: 64 });

Дополним получившийся код переводом, итоговый вариант будет выглядеть так:

oxidized_stick.js
Translation.addTranslation("item.oxidized_stick.name", {
en: "Oxidized Stick",
ru: "Окислившаяся палка"
});
IDRegistry.genItemID("oxidized_stick");
Item.createItem("oxidized_stick", "item.oxidized_stick.name", {
name: "oxidized_stick", data: 0
}, { stack: 64 });

Разберем происходящее

Все начинается с создания перевода. Это одна из практик хорошего тона.

Прежде чем создать предмет, мы генерируем числовой идентификатор для строкового. В игре он будет представлен как minecraft:item_<идентификатор>, в нашем случае minecraft:item_oxidized_stick.

И наконец, вызывается комплексный метод Item.createItem, вот его параметры:

  1. Зарегистрированный строковый идентификатор.
  2. Имя предмета; мы не обязаны использовать формат item.<идентификатор>[.<состояние>].name здесь, и могли бы просто назвать предмет "Oxidized Stick" или "Окислившаяся палка", но тогда потеряется смысл локализации.
  3. Объект, представляющий текстуру; текстура это исключительно имя файла без расширения, подпапки вроде assets/resources/category в нее не входят. Мета это и есть наше число после слеша в конце.
  4. Дополнительные свойства предмета, в данном случае мы задаем стандартный размер стака (максимального количества предметов в одной ячейке инвентаря или контейнера).
Составляйте правильные идентификаторы

Игровые идентификаторы могут описывать материал, тип предмета и свойство или цвет в одном месте. Для реализации новых идентификаторов должна быть использована именно подобная последовательность, например diamond_pickaxe или minecart_command_block. Разделяйте элементы описания с помощью _.

Однако, существуют и исключения вроде appleEnchanted, muttonCooked, muttonRaw. Состояния предмета должны быть приписаны в конце основного идентификатора с заглавной буквы.

Технические предметы

По умолчанию, любые предметы которые вы создаете добавляются в инвентарь творческого режима. Если же нам необходимо изменить логику этого поведения, для каждого типа предметов можно дополнить последний параметр регистрации:

Item.createItem("oxidized_stick", "item.oxidized_stick.name", {
name: "oxidized_stick", data: 0
}, {
stack: 64,
isTech: true
});

Пример такого технического предмета — яйцо дракона. Его нет в творческом инвентаре, но его все еще можно получить с помощью команды /give.

Привяжем событие

Пока мы лишь создали предмет, он не имеет функционала, и является тем самым бесполезным предметом из начала статьи. Обратимся к калбекам, на их основе можно реализовать большую, если не всю логику взаимодействия.

Следующая функция привяжет калбек ItemUse к предмету:

Item.registerUseFunction("oxidized_stick", function(coords, item, block, playerUid) {
Entity.addVelocity(playerUid, 0, 0.5 * Math.random(), 0);
});

Под использованием предмета подразумевается нажатие им по любому блоку или его удержание в воздухе, как например при поедании еды. В нашем случае палка якобы будет отталкивать игрока со случайной скоростью, если тот воспользуется ей.

Ускорение задается в блоках за тик, где в одной секунде 20 тиков. То есть, максимальное ускорение за секунду может достичь 10 блоков в секунду (0.5 блоков/сек. * 20 тиков). Мы еще рассмотрим ускорение подробнее в будущем.

Метод приравнивается к вызову другого метода, который регистрирует событие уже по числовому идентификатору:

Item.registerUseFunctionForID(ItemID.oxidized_stick, function(coords, item, block, playerUid) {
Entity.addVelocity(playerUid, 0, 0.5 * Math.random(), 0);
});

Объект ItemID предоставляет числовые идентификаторы для идентификаторов предметов, которые были созданы в следствии вызова метода IDRegistry.genItemID. Для игры основными являются именно числовые идентификаторы, строковые же отображаются в различных интерфейсах и используются нами для удобства.

Почему просто не воспользоваться калбеком?

Вариант со схожим функционалом выглядит так:

Callback.addCallback("ItemUse", function(coords, item, block, isExternal, playerUid) {
if (item.id == ItemID.oxidized_stick) {
Entity.addVelocity(playerUid, 0, 0.5 * Math.random(), 0);
}
});

Вот список дополнительных проверок, которые осуществляет функция Item.registerUseFunction перед вызовом вашего события:

  1. Проверяется является ли блок тайлом, мы еще рассмотрим их, главное здесь лишь знать что они могут прервать дальнейший вызов события.
  2. В случае если у блока есть интерфейс (например открылся верстак или сундук), событие будет остановлено.
  3. Если же интерфейс не открылся или игрок находится на шифте (в таком случае интерфейс не открывается) событие будет вызвано.

В случае регистрации калбека эти проверки необходимо будет реализовывать самостоятельно, так что мы не использовали прямую регистрацию этого калбека в примере. Ну и не забывайте о проверке идентификатора, калбек вызывается при использовании любого предмета.