
Rtag
Rtag - это Bukkit-библиотека для удобной работы с NBT-тегами и data components в Minecraft. Позволяет легко читать и изменять данные предметов, блоков и сущностей без NMS, поддерживает кросс-версионность и простое подключение.
Rtag - это библиотека (плагин) для серверов на Bukkit/Spigot/Paper, которая упрощает работу с NBT-данными. Если вы когда-нибудь пытались сохранить кастомные данные на предмете или сущности стандартными средствами Майнкрафт, то знаете, как это муторно. Rtag решает эту проблему: больше не нужно лезть в NMS и писать тонны кода для каждой версии Minecraft.
Для владельцев серверов
Установка
Скачайте .jar файл Rtag и поместите его в папку plugins вашего сервера. Перезагрузите сервер - библиотека готова к работе.
Требования
- Minecraft 1.8.8 и выше (старые версии могут не поддерживаться)
- Java 11 или новее (даже старые версии MC работают на Java 11)
Совместимость
✅ Bukkit, Spigot, Paper (включая Paper с Mojang Mappings), Folia и любые форки без craftbukkit relocation.
Для разработчиков
Что такое Rtag?
Rtag предоставляет простой API для редактирования NBT-тегов без использования NMS, что особенно важно для больших серверов - никакого удара по производительности. Библиотека полностью shadeable: вы можете включить её прямо в свой плагин.
Rtag конвертирует любой Java-объект в NBT-тег и обратно. Примеры:
// Работа с предметом
RtagItem tag = new RtagItem(item);
// Работа с сущностью
RtagEntity tag = new RtagEntity(entity);
// Работа с блоком
RtagBlock tag = new RtagBlock(block);
// --- Запись значений
// Установить значение "Custom Text" по пути "display.Name"
tag.set("Custom Text", "display", "Name");
// Установить целое число по пути "someKey"
tag.set(40, "someKey");
// Поддержка любых объектов, например MyObject
MyObject myobject = new MyObject();
tag.set(myobject, "any", "path");
// Работа со списками
tag.set(new ArrayList(), "list", "path");
tag.add((short) 3, "list", "path");
// Замена значения в списке по индексу
tag.set((short) 5, "list", "path", 0); // индекс 0
// --- Чтение значений
// Значение из пути "display" -> "Name"
String name = tag.get("display", "Name");
// Безопасное получение с дефолтным значением -1
int intValue = tag.getOptional("someKey").or(-1);
int sameValue = tag.getOptional("someKey").asInt(-1); // пытается конвертировать любой тип в int
// Явное получение кастомного объекта
MyObject sameobject = tag.getOptional("any", "path").as(MyObject.class);
// Слияние значений
tag.merge(Map.of("asd", 123, "someKey", 41), true);
// Получение списков
List<Short> list = tag.get("list", "path");
// Элемент списка по индексу
short listValue = tag.get("list", "path", 0); // индекс 0
// Получение всего тега как Map Java-объектов
Map<String, Object> map = tag.get();
// --- Применение изменений к объекту
tag.load();
// RtagItem может создать копию предмета с изменениями
ItemStack itemCopy = tag.loadCopy();
// --- Обновление тега, если исходный объект был изменён извне
tag.update();
Подключение Rtag
Для Gradle Groovy:
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
compileOnly 'com.saicone.rtag:rtag:VERSION'
// Другие модули
compileOnly 'com.saicone.rtag:rtag-block:VERSION'
compileOnly 'com.saicone.rtag:rtag-entity:VERSION'
compileOnly 'com.saicone.rtag:rtag-item:VERSION'
}
Для Gradle Kotlin:
repositories {
maven("https://jitpack.io")
}
dependencies {
compileOnly("com.saicone.rtag:rtag:VERSION")
// Другие модули
compileOnly("com.saicone.rtag:rtag-block:VERSION")
compileOnly("com.saicone.rtag:rtag-entity:VERSION")
compileOnly("com.saicone.rtag:rtag-item:VERSION")
}
Для Maven:
<repositories>
<repository>
<id>Jitpack</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.saicone.rtag</groupId>
<artifactId>rtag</artifactId>
<version>VERSION</version>
<scope>provided</scope>
</dependency>
<!-- Другие модули -->
<dependency>
<groupId>com.saicone.rtag</groupId>
<artifactId>rtag-block</artifactId>
<version>VERSION</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.saicone.rtag</groupId>
<artifactId>rtag-entity</artifactId>
<version>VERSION</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.saicone.rtag</groupId>
<artifactId>rtag-item</artifactId>
<version>VERSION</version>
<scope>provided</scope>
</dependency>
</dependencies>
Возможности Rtag
Почему именно Rtag, а не другие библиотеки?
1. Простота
Не нужно быть экспертом в NBT - простые методы set/get работают с обычными Java-объектами.
Rtag rtag = new Rtag();
rtag.set(compound, "Normal string", "CustomTagPath");
String string = rtag.get(compound, "CustomTagPath");
Встроенные редакторы (RtagItem, RtagEntity, RtagBlock) предлагают удобные методы:
RtagItem tag = new RtagItem(item);
tag.setUnbreakable(true);
tag.setRepairCost(20);
int level = tag.getEnchantmentLevel("unbreaking"); // принимает enum, имя или ID
RtagEntity tag = new RtagEntity(entity);
tag.setAttributeBase("generic.attackDamage", 0.5);
RtagBlock tag = new RtagBlock(block);
tag.setCustomName("§eЦветное имя");
Можно редактировать объекты с помощью лямбд:
ItemStack item = ...;
RtagItem.edit(item, tag -> {
tag.set("Custom Text", "display", "name");
tag.set(30, "someKey");
});
// Вернуть копию
ItemStack copy = RtagItem.edit(item, tag -> {
tag.set(30, "someKey");
return tag.loadCopy();
});
2. Редактирование data components (экспериментально)
Начиная с Minecraft 1.20.5 предметы используют компоненты для хранения ванильных данных. RtagItem позволяет работать с ними так же просто, как с обычными тегами.
RtagItem tag = new RtagItem(item);
if (tag.hasComponent("minecraft:custom_model_data")) {
tag.removeComponent("minecraft:custom_model_data");
} else {
tag.setComponent("minecraft:custom_model_data", 40);
}
Object component = tag.getComponent("minecraft:custom_model_data");
Integer number = ComponentType.encodeJava("minecraft:custom_model_data", component).orElse(null);
3. Сохранение кастомных объектов
По умолчанию Rtag использует встроенную Gson для сериализации, но вы можете зарегистрировать свои (де)сериализаторы для автоматического преобразования.
Rtag rtag = new Rtag();
MyObject myObject = new MyObject();
rtag.set(compound, myObject, "CustomTagPath");
MyObject sameObject = rtag.getOptional(compound, "CustomTagPath").as(MyObject.class);
Пример регистрации сериализатора:
public class MyObjectSerializer implements RtagSerializer<MyObject>, RtagDeserializer<MyObject> {
public MyObjectSerializer(Rtag rtag) {
rtag.putSerializer(MyObject.class, this);
rtag.putDeserializer(this);
}
@Override
public String getInID() {
return "myplugin:MyObject";
}
@Override
public String getOutID() {
return "myplugin:MyObject";
}
@Override
public Map<String, Object> serialize(MyObject object) {
// Преобразуйте объект в Map
}
@Override
public MyObject deserialize(Map<String, Object> compound) {
// Преобразуйте Map в объект
}
}
После регистрации можно получать объекты без явного приведения:
Rtag rtag = new Rtag();
new MyObjectSerializer(rtag);
MyObject myObject = new MyObject();
rtag.set(compound, myObject, "CustomTagPath");
MyObject sameObject = rtag.get(compound, "CustomTagPath");
4. TagStream
ItemTagStream позволяет конвертировать предметы в Base64, файл, байты, Map, строку и обратно. Поддерживается кросс-версионность: сохраните предмет на любой версии и загрузите на другой - материалы, зачарования, зелья и т.д. будут корректно преобразованы.
ItemTagStream tag = ItemTagStream.INSTANCE;
String string = tag.toBase64(item);
ItemStack sameItem = tag.fromBase64(string)[0];
5. Текстурированные головы
С помощью SkullTexture можно получить головы с текстурой по base64, URL, ID текстуры, имени игрока или UUID.
// Base64
ItemStack head = SkullTexture.getTexturedHead("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmVkZmEyZTBmZGVhMGMwNDIzODA0Y2RiNWI2MmFkMDVhNmU5MTRjMDQ2YzRhM2I3ZTM1NWJmODEyNjkxMjVmZCJ9fQ==");
// URL
ItemStack head = SkullTexture.getTexturedHead("http://textures.minecraft.net/texture/fedfa2e0fdea0c0423804cdb5b62ad05a6e914c046c4a3b7e355bf81269125fd");
// ID текстуры
ItemStack head = SkullTexture.getTexturedHead("fedfa2e0fdea0c0423804cdb5b62ad05a6e914c046c4a3b7e355bf81269125fd");
// Имя игрока
ItemStack head = SkullTexture.getTexturedHead("Rubenicos");
// UUID игрока
ItemStack head = SkullTexture.getTexturedHead("7ca003dc-175f-4f1f-b490-5651045311ad");
6. Чат-компоненты
ChatComponent позволяет конвертировать строки (в том числе JSON) в чат-компоненты и обратно.
// В компонент
Object component = ChatComponent.fromJson("{\"bold\":true,\"italic\":false,\"color\":\"dark_purple\",\"text\":\"Colored text!\"}");
Object sameComponent = ChatComponent.fromString("§5§lColored text!");
// Из компонента
String json = ChatComponent.toJson(component);
String string = ChatComponent.toString(component);
// Кросс-совместимость
String json = ChatComponent.toJson("§5§lColored text!");
String string = ChatComponent.toString("{\"bold\":true,\"italic\":false,\"color\":\"dark_purple\",\"text\":\"Colored text!\"}");
Pretty NBT
Форматирование NBT в одну или несколько строк с использованием стандартной, hex или minimessage цветовой палитры (подробнее в вики).
