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

Что такое экстра?

Как мы знаем, в игре существует множество предметов. И каждый из них может иметь свои данные. Такими предметами являются предметы, которые имеют один и тот же идентификатор, но при этом не могут быть сложены в один стак и чем-то отличаются. Одним из таких предметов является зачарованная книга.

Для чего нужна?​

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

Давайте попробуем создать механику присвоения случайных рун нашему магическому кристаллу. Но что нам для этого нужно? Нам нужно хранилище, куда будут помещены наши данные.

Внесение данных​

ItemExtraData это то, в чём мы и будем хранить наши данные для последующей передачи в поле экстры. Создадим функцию, добавляющую в список текста наших рун, и список:

const runeList = [];
function addRune(text) {
runeList.push(text);
}

Отлично, теперь мы имеем хранилище. Давайте зарегистрируем для нашего примера несколько текстов

addRune("magic");
addRune("twilight");
addRune("fire");

Сделаем функцию, которая будет возвращать экземпляр класса ItemExtraData, содержащий случайную руну из списка;

function giveRandomRune() {
const index = Math.floor(Math.random() * runeList.length);
const extraData = new ItemExtraData();
extraData.putString("rune", runeList(index));
return extraData;
}

Стоит заметить, что ItemExtraData принимает в себя параметр, в который можно передать предыдущие или любые другие данные экстры, чтобы создать экземпляр содержащий эти данные. Однако свои так же можно будет передать, это лишь способ дополнения.

const extraDataOld = new ItemExtraData();
extraDataOld.putString("old_rune", "castle");

const extraDataNew = new ItemExtraData(extraDataOld);
extraDataNew.putString("new_rune", "cave");

Что такое putString? Дело в том, что ItemExtraData реализует способ передачи и получения данных класса CompoundTag. Он позволяет разделять данные на типы, и получать их в зависимости от переданного типа. Первым аргументом идёт название ключа, вторым значение. Рассмотрим некоторые способы передачи и получения данных, которые в нём есть:

const extraData = new ItemExtraData();
extraData.getInt("int_key", 10); // вернется целочисленное число по ключу "int_key", либо же 10 если его нет
extraData.getString("string_key", "random_rune"); // вернется строка по ключу "string_key", либо же "random_rune" если ее нет
extraData.getFloat("float_key", 1.1) // вернется число с дробью по ключу "float_key", либо же 1.1 если его нет
extraData.getBoolean("boolean_key", true); // вернется буль по ключу "boolean_key", либо же true если его нет
extraData.getObject("object_key", { fruit: "apple" }); // вернется объект по ключу "object_key", либо же приведенный объект если его нет
extraData.getLong("long_key", 2147483648); // вернется большое число по ключу "long_key", либо же 2147483648 если его нет

Куда передавать?​

Ранее мы создали список, где хранятся наши руны, и функцию для получения случайной из списка. Но одного хранилища экстры недостаточно, нам нужно их куда-то передать, чтобы они приобрели вес. Так вот. Как мы знаем, предметы хранят в себе объект типа ItemInstance:

interface ItemInstance {
id: int;
count: int;
data: int;
extra?: ItemExtraData;
}

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

Давайте реализуем присвоение случайной руны нашему кристаллу после клика им о камень:

Item.registerUseFunctionForID(
ItemID.magic_crystal,
function (coords, item, block, player) {
if (
block.id == VanillaBlockID.stone &&
(!item.extra || (item.extra && !item.extra.getString("rune")))
) {
Entity.setCarriedItem(player, item.id, item.count, item.data, giveRandomRune());
}
}
);

Теперь, при клике кристаллом по камню, кристаллу присвоится случайная руна, если руна не была присвоена ранее.

Получение данных​

Мы присвоили кристаллу руну, но что, если нам понадобится получить содержимое этой руны? В таком случае, в классе предусмотрены методы по получению данных в зависимости от типа:

const extraData = new ItemExtraData();
extraData.getInt("int_key", 10); //мы получаем число, и если его нет, то получим 10
extraData.getString("string_key", "random_rune"); //мы получаем строку, если её нет, то получим "random_rune"
extraData.getFloat("float_key", 1.1); //мы получаем число с десятичной частью, если его нет, то получим 1.1
extraData.getBoolean("boolean_key", true); //мы получаем булевое значение, если его нет, то получим true
extraData.getObject("object_key", { fruit: "apple" }); //мы получаем объект с данными, если его нет, то получим {fruit: "apple"}
extraData.getLong("long_key", 10000); //мы получаем число вида long, если его нет, то получим 10000

Важно заметить, что второй аргумент необязателен, и если его не будет и значения ключа тоже, то вернётся null.

Давайте улучшим нашу функцию, и если экстра будет отсутствовать, выведем значение в чат.

Item.registerUseFunctionForID(
ItemID.magic_crystal,
function (coords, item, block, player) {
if (block.id == VanillaBlockID.stone) {
if (
!item.extra ||
(item.extra && !item.extra.getString("rune"))
) {
Entity.setCarriedItem(player, item.id, item.count, item.data, giveRandomRune());
} else {
Game.message(
"Название руны: " + (item.extra ? item.extra.getString("rune") : "неизвестно")
);
}
}
}
);

Использование тегов​

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