feat: initial conversion to adventure nbt. no tests, no anvil

This commit is contained in:
mworzala 2024-03-17 16:07:29 -04:00
parent 54212ebc97
commit 687968eea0
No known key found for this signature in database
GPG Key ID: B148F922E64797C7
65 changed files with 1195 additions and 1230 deletions

View File

@ -72,10 +72,7 @@ dependencies {
api(libs.jetbrainsAnnotations) api(libs.jetbrainsAnnotations)
api(libs.bundles.adventure) api(libs.bundles.adventure)
api(libs.hydrazine) api(libs.hydrazine)
api(libs.bundles.kotlin)
api(libs.bundles.hephaistos)
implementation(libs.minestomData) implementation(libs.minestomData)
implementation(libs.dependencyGetter)
// Performance/data structures // Performance/data structures
implementation(libs.caffeine) implementation(libs.caffeine)

View File

@ -1,5 +1,9 @@
package net.minestom.demo.block; package net.minestom.demo.block;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.BinaryTagTypes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.ListBinaryTag;
import net.minestom.server.instance.block.BlockHandler; import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
@ -10,10 +14,6 @@ import net.minestom.server.tag.TagWritable;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -22,16 +22,17 @@ import java.util.List;
public class CampfireHandler implements BlockHandler { public class CampfireHandler implements BlockHandler {
public static final Tag<List<ItemStack>> ITEMS = Tag.View(new TagSerializer<>() { public static final Tag<List<ItemStack>> ITEMS = Tag.View(new TagSerializer<>() {
private final Tag<NBT> internal = Tag.NBT("Items"); private final Tag<BinaryTag> internal = Tag.NBT("Items");
@Override @Override
public @Nullable List<ItemStack> read(@NotNull TagReadable reader) { public @Nullable List<ItemStack> read(@NotNull TagReadable reader) {
NBTList<NBTCompound> item = (NBTList<NBTCompound>) reader.getTag(internal); ListBinaryTag item = (ListBinaryTag) reader.getTag(internal);
if (item == null) if (item == null)
return null; return null;
List<ItemStack> result = new ArrayList<>(); List<ItemStack> result = new ArrayList<>();
item.forEach(nbtCompound -> { item.forEach(childTag -> {
int amount = nbtCompound.getAsByte("Count"); CompoundBinaryTag nbtCompound = (CompoundBinaryTag) childTag;
int amount = nbtCompound.getByte("Count");
String id = nbtCompound.getString("id"); String id = nbtCompound.getString("id");
Material material = Material.fromNamespaceId(id); Material material = Material.fromNamespaceId(id);
result.add(ItemStack.of(material, amount)); result.add(ItemStack.of(material, amount));
@ -45,14 +46,14 @@ public class CampfireHandler implements BlockHandler {
writer.removeTag(internal); writer.removeTag(internal);
return; return;
} }
writer.setTag(internal, NBT.List( writer.setTag(internal, ListBinaryTag.listBinaryTag(
NBTType.TAG_Compound, BinaryTagTypes.COMPOUND,
value.stream() value.stream()
.map(item -> NBT.Compound(nbt -> { .map(item -> (BinaryTag) CompoundBinaryTag.builder()
nbt.setByte("Count", (byte) item.amount()); .putByte("Count", (byte) item.amount())
nbt.setByte("Slot", (byte) 1); .putByte("Slot", (byte) 1)
nbt.setString("id", item.material().name()); .putString("id", item.material().name())
})) .build())
.toList() .toList()
)); ));
} }

View File

@ -4,7 +4,7 @@ metadata.format.version = "1.1"
# Important dependencies # Important dependencies
data = "1.20.4-rv4" data = "1.20.4-rv4"
adventure = "4.15.0" adventure = "4.16.0"
kotlin = "1.7.22" kotlin = "1.7.22"
dependencyGetter = "v1.0.1" dependencyGetter = "v1.0.1"
hydrazine = "1.7.2" hydrazine = "1.7.2"
@ -41,22 +41,16 @@ nexuspublish = "1.3.0"
# Important Dependencies # Important Dependencies
# Adventure # Adventure
adventure-api = { group = "net.kyori", name = "adventure-api", version.ref = "adventure" } adventure-api = { group = "net.kyori", name = "adventure-api", version.ref = "adventure" }
adventure-nbt = { group = "net.kyori", name = "adventure-nbt", version.ref = "adventure" }
adventure-serializer-gson = { group = "net.kyori", name = "adventure-text-serializer-gson", version.ref = "adventure" } adventure-serializer-gson = { group = "net.kyori", name = "adventure-text-serializer-gson", version.ref = "adventure" }
adventure-serializer-legacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" } adventure-serializer-legacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" }
adventure-serializer-plain = { group = "net.kyori", name = "adventure-text-serializer-plain", version.ref = "adventure" } adventure-serializer-plain = { group = "net.kyori", name = "adventure-text-serializer-plain", version.ref = "adventure" }
adventure-text-logger-slf4j = { group = "net.kyori", name = "adventure-text-logger-slf4j", version.ref = "adventure" } adventure-text-logger-slf4j = { group = "net.kyori", name = "adventure-text-logger-slf4j", version.ref = "adventure" }
# Kotlin
kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" }
kotlin-stdlib-jdk8 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" }
# Miscellaneous # Miscellaneous
hydrazine = { group = "com.github.MadMartian", name = "hydrazine-path-finding", version.ref = "hydrazine" } hydrazine = { group = "com.github.MadMartian", name = "hydrazine-path-finding", version.ref = "hydrazine" }
minestomData = { group = "net.minestom", name = "data", version.ref = "data" } minestomData = { group = "net.minestom", name = "data", version.ref = "data" }
dependencyGetter = { group = "com.github.Minestom", name = "DependencyGetter", version.ref = "dependencyGetter" }
jetbrainsAnnotations = { group = "org.jetbrains", name = "annotations", version.ref = "jetbrainsAnnotations" } jetbrainsAnnotations = { group = "org.jetbrains", name = "annotations", version.ref = "jetbrainsAnnotations" }
hephaistos-common = { group = "io.github.jglrxavpok.hephaistos", name = "common", version.ref = "hephaistos" }
hephaistos-gson = { group = "io.github.jglrxavpok.hephaistos", name = "gson", version.ref = "hephaistos" }
slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j"} slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j"}
# Performance / Data Structures # Performance / Data Structures
@ -86,11 +80,9 @@ logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.
[bundles] [bundles]
kotlin = ["kotlin-stdlib-jdk8", "kotlin-reflect"]
flare = ["flare", "flare-fastutil"] flare = ["flare", "flare-fastutil"]
adventure = ["adventure-api", "adventure-serializer-gson", "adventure-serializer-legacy", "adventure-serializer-plain", "adventure-text-logger-slf4j"] adventure = ["adventure-api", "adventure-nbt", "adventure-serializer-gson", "adventure-serializer-legacy", "adventure-serializer-plain", "adventure-text-logger-slf4j"]
junit = ["junit-api", "junit-engine", "junit-params", "junit-suite-api", "junit-suite-engine"] junit = ["junit-api", "junit-engine", "junit-params", "junit-suite-api", "junit-suite-engine"]
hephaistos = ["hephaistos-common", "hephaistos-gson"]
logback = ["logback-core", "logback-classic"] logback = ["logback-core", "logback-classic"]
[plugins] [plugins]

View File

@ -1,21 +1,18 @@
package net.minestom.server.adventure; package net.minestom.server.adventure;
import java.io.StringReader; import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.TagStringIO;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.translation.GlobalTranslator; import net.kyori.adventure.translation.GlobalTranslator;
import net.kyori.adventure.util.Codec; import net.kyori.adventure.util.Codec;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.parser.SNBTParser;
/** /**
* Adventure related constants, etc. * Adventure related constants, etc.
*/ */
@ -23,8 +20,8 @@ public final class MinestomAdventure {
/** /**
* A codec to convert between strings and NBT. * A codec to convert between strings and NBT.
*/ */
public static final Codec<NBT, String, NBTException, RuntimeException> NBT_CODEC public static final Codec<CompoundBinaryTag, String, IOException, IOException> NBT_CODEC
= Codec.codec(encoded -> new SNBTParser(new StringReader(encoded)).parse(), NBT::toSNBT); = Codec.codec(TagStringIO.get()::asCompound, TagStringIO.get()::asString);
/** /**
* If components should be automatically translated in outgoing packets. * If components should be automatically translated in outgoing packets.

View File

@ -1,6 +1,7 @@
package net.minestom.server.adventure.provider; package net.minestom.server.adventure.provider;
import net.kyori.adventure.key.Key; import net.kyori.adventure.key.Key;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.api.BinaryTagHolder; import net.kyori.adventure.nbt.api.BinaryTagHolder;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.event.HoverEvent;
@ -9,14 +10,10 @@ import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.kyori.adventure.util.Codec; import net.kyori.adventure.util.Codec;
import net.minestom.server.adventure.MinestomAdventure; import net.minestom.server.adventure.MinestomAdventure;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import java.io.IOException; import java.io.IOException;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer { final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer {
static final NBTLegacyHoverEventSerializer INSTANCE = new NBTLegacyHoverEventSerializer(); static final NBTLegacyHoverEventSerializer INSTANCE = new NBTLegacyHoverEventSerializer();
@ -30,76 +27,46 @@ final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer
@Override @Override
public HoverEvent.@NotNull ShowItem deserializeShowItem(@NotNull Component input) throws IOException { public HoverEvent.@NotNull ShowItem deserializeShowItem(@NotNull Component input) throws IOException {
final String raw = PlainTextComponentSerializer.plainText().serialize(input); final String raw = PlainTextComponentSerializer.plainText().serialize(input);
try { // attempt the parse
// attempt the parse final CompoundBinaryTag contents = MinestomAdventure.NBT_CODEC.decode(raw);
final NBT nbt = MinestomAdventure.NBT_CODEC.decode(raw); final CompoundBinaryTag tag = contents.getCompound(ITEM_TAG);
if (!(nbt instanceof NBTCompound contents)) throw new IOException("contents were not a compound");
final NBTCompound tag = contents.getCompound(ITEM_TAG);
// create the event // create the event
return HoverEvent.ShowItem.showItem( return HoverEvent.ShowItem.showItem(
Key.key(Objects.requireNonNullElse(contents.getString(ITEM_TYPE), "")), Key.key(contents.getString(ITEM_TYPE, "")),
Objects.requireNonNullElse(contents.getByte(ITEM_COUNT), (byte) 1), contents.getByte(ITEM_COUNT, (byte) 1),
tag == null ? null : BinaryTagHolder.encode(tag, MinestomAdventure.NBT_CODEC) tag.size() == 0 ? null : BinaryTagHolder.encode(tag, MinestomAdventure.NBT_CODEC)
); );
} catch (final NBTException e) {
throw new IOException(e);
}
} }
@Override @Override
public HoverEvent.@NotNull ShowEntity deserializeShowEntity(@NotNull Component input, Codec.Decoder<Component, String, ? extends RuntimeException> componentDecoder) throws IOException { public HoverEvent.@NotNull ShowEntity deserializeShowEntity(@NotNull Component input, Codec.Decoder<Component, String, ? extends RuntimeException> componentDecoder) throws IOException {
final String raw = PlainTextComponentSerializer.plainText().serialize(input); final String raw = PlainTextComponentSerializer.plainText().serialize(input);
try { final CompoundBinaryTag contents = MinestomAdventure.NBT_CODEC.decode(raw);
final NBT nbt = MinestomAdventure.NBT_CODEC.decode(raw); return HoverEvent.ShowEntity.showEntity(
if (!(nbt instanceof NBTCompound contents)) throw new IOException("contents were not a compound"); Key.key(contents.getString(ENTITY_TYPE, "")),
UUID.fromString(Objects.requireNonNullElse(contents.getString(ENTITY_ID), "")),
return HoverEvent.ShowEntity.showEntity( componentDecoder.decode(Objects.requireNonNullElse(contents.getString(ENTITY_NAME), ""))
Key.key(Objects.requireNonNullElse(contents.getString(ENTITY_TYPE), "")), );
UUID.fromString(Objects.requireNonNullElse(contents.getString(ENTITY_ID), "")),
componentDecoder.decode(Objects.requireNonNullElse(contents.getString(ENTITY_NAME), ""))
);
} catch (NBTException e) {
throw new IOException(e);
}
} }
@Override @Override
public @NotNull Component serializeShowItem(HoverEvent.@NotNull ShowItem input) throws IOException { public @NotNull Component serializeShowItem(HoverEvent.@NotNull ShowItem input) throws IOException {
AtomicReference<NBTException> exception = new AtomicReference<>(null); CompoundBinaryTag.Builder tag = CompoundBinaryTag.builder();
final NBTCompound tag = NBT.Compound(t -> { tag.putString(ITEM_TYPE, input.item().asString());
t.setString(ITEM_TYPE, input.item().asString()); tag.putByte(ITEM_COUNT, (byte) input.count());
t.setByte(ITEM_COUNT, (byte) input.count()); final BinaryTagHolder nbt = input.nbt();
if (nbt != null) tag.put(ITEM_TAG, nbt.get(MinestomAdventure.NBT_CODEC));
final BinaryTagHolder nbt = input.nbt(); return Component.text(MinestomAdventure.NBT_CODEC.encode(tag.build()));
if (nbt != null) {
try {
t.set(ITEM_TAG, nbt.get(MinestomAdventure.NBT_CODEC));
} catch (NBTException e) {
exception.set(e);
}
}
});
if (exception.get() != null) {
throw new IOException(exception.get());
}
return Component.text(MinestomAdventure.NBT_CODEC.encode(tag));
} }
@Override @Override
public @NotNull Component serializeShowEntity(HoverEvent.@NotNull ShowEntity input, Codec.Encoder<Component, String, ? extends RuntimeException> componentEncoder) { public @NotNull Component serializeShowEntity(HoverEvent.@NotNull ShowEntity input, Codec.Encoder<Component, String, ? extends RuntimeException> componentEncoder) throws IOException {
final NBTCompound tag = NBT.Compound(t -> { CompoundBinaryTag.Builder tag = CompoundBinaryTag.builder();
t.setString(ENTITY_ID, input.id().toString()); tag.putString(ENTITY_ID, input.id().toString());
t.setString(ENTITY_TYPE, input.type().asString()); tag.putString(ENTITY_TYPE, input.type().asString());
final Component name = input.name();
final Component name = input.name(); if (name != null) tag.putString(ENTITY_NAME, componentEncoder.encode(name));
if (name != null) { return Component.text(MinestomAdventure.NBT_CODEC.encode(tag.build()));
t.setString(ENTITY_NAME, componentEncoder.encode(name));
}
});
return Component.text(MinestomAdventure.NBT_CODEC.encode(tag));
} }
} }

View File

@ -1,11 +1,11 @@
package net.minestom.server.adventure.serializer.nbt; package net.minestom.server.adventure.serializer.nbt;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.ComponentSerializer; import net.kyori.adventure.text.serializer.ComponentSerializer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
public interface NbtComponentSerializer extends ComponentSerializer<Component, Component, NBT> { public interface NbtComponentSerializer extends ComponentSerializer<Component, Component, BinaryTag> {
static @NotNull NbtComponentSerializer nbt() { static @NotNull NbtComponentSerializer nbt() {
return NbtComponentSerializerImpl.INSTANCE; return NbtComponentSerializerImpl.INSTANCE;
} }

View File

@ -1,6 +1,7 @@
package net.minestom.server.adventure.serializer.nbt; package net.minestom.server.adventure.serializer.nbt;
import net.kyori.adventure.key.Key; import net.kyori.adventure.key.Key;
import net.kyori.adventure.nbt.*;
import net.kyori.adventure.nbt.api.BinaryTagHolder; import net.kyori.adventure.nbt.api.BinaryTagHolder;
import net.kyori.adventure.text.*; import net.kyori.adventure.text.*;
import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.ClickEvent;
@ -12,14 +13,10 @@ import net.kyori.adventure.text.format.TextDecoration;
import net.minestom.server.utils.validate.Check; import net.minestom.server.utils.validate.Check;
import org.intellij.lang.annotations.Subst; import org.intellij.lang.annotations.Subst;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
//todo write tests for me!! //todo write tests for me!!
@ -27,19 +24,19 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
static final NbtComponentSerializer INSTANCE = new NbtComponentSerializerImpl(); static final NbtComponentSerializer INSTANCE = new NbtComponentSerializerImpl();
@Override @Override
public @NotNull Component deserialize(@NotNull NBT input) { public @NotNull Component deserialize(@NotNull BinaryTag input) {
return deserializeAnyComponent(input); return deserializeAnyComponent(input);
} }
@Override @Override
public @NotNull NBT serialize(@NotNull Component component) { public @NotNull BinaryTag serialize(@NotNull Component component) {
return serializeComponent(component); return serializeComponent(component);
} }
// DESERIALIZATION // DESERIALIZATION
private @NotNull Component deserializeAnyComponent(@NotNull NBT nbt) { private @NotNull Component deserializeAnyComponent(@NotNull BinaryTag nbt) {
if (nbt instanceof NBTCompound compound) { if (nbt instanceof CompoundBinaryTag compound) {
return deserializeComponent(compound); return deserializeComponent(compound);
} else { } else {
//todo raw string + list //todo raw string + list
@ -47,12 +44,12 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
} }
} }
private @NotNull Component deserializeComponent(@NotNull NBTCompound compound) { private @NotNull Component deserializeComponent(@NotNull CompoundBinaryTag compound) {
ComponentBuilder<?, ?> builder; ComponentBuilder<?, ?> builder;
var type = compound.getString("type"); var type = compound.get("type");
if (type != null) { if (type instanceof StringBinaryTag sType) {
// If type is specified, use that // If type is specified, use that
builder = switch (type) { builder = switch (sType.value()) {
case "text" -> deserializeTextComponent(compound); case "text" -> deserializeTextComponent(compound);
case "translatable" -> deserializeTranslatableComponent(compound); case "translatable" -> deserializeTranslatableComponent(compound);
case "score" -> deserializeScoreComponent(compound); case "score" -> deserializeScoreComponent(compound);
@ -63,26 +60,25 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
}; };
} else { } else {
// Try to infer the type from the fields present. // Try to infer the type from the fields present.
if (compound.containsKey("text")) { Set<String> keys = compound.keySet();
if (keys.contains("text")) {
builder = deserializeTextComponent(compound); builder = deserializeTextComponent(compound);
} else if (compound.containsKey("translate")) { } else if (keys.contains("translate")) {
builder = deserializeTranslatableComponent(compound); builder = deserializeTranslatableComponent(compound);
} else if (compound.containsKey("score")) { } else if (keys.contains("score")) {
builder = deserializeScoreComponent(compound); builder = deserializeScoreComponent(compound);
} else if (compound.containsKey("selector")) { } else if (keys.contains("selector")) {
builder = deserializeSelectorComponent(compound); builder = deserializeSelectorComponent(compound);
} else if (compound.containsKey("keybind")) { } else if (keys.contains("keybind")) {
builder = deserializeKeybindComponent(compound); builder = deserializeKeybindComponent(compound);
} else if (compound.containsKey("nbt")) { } else if (keys.contains("nbt")) {
builder = deserializeNbtComponent(compound); builder = deserializeNbtComponent(compound);
} else throw new UnsupportedOperationException("Unable to infer component type"); } else throw new UnsupportedOperationException("Unable to infer component type");
} }
// Children // Children
var extra = compound.getList("extra"); var extra = compound.getList("extra", BinaryTagTypes.COMPOUND);
Check.argCondition(extra != null && !extra.getSubtagType().equals(NBTType.TAG_Compound), if (extra.size() > 0) {
"Extra field must be a list of compounds");
if (extra != null) {
var list = new ArrayList<ComponentLike>(); var list = new ArrayList<ComponentLike>();
for (var child : extra) list.add(deserializeAnyComponent(child)); for (var child : extra) list.add(deserializeAnyComponent(child));
builder.append(list); builder.append(list);
@ -91,7 +87,7 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
// Formatting // Formatting
var style = Style.style(); var style = Style.style();
var color = compound.getString("color"); var color = compound.getString("color");
if (color != null) { if (!color.isEmpty()) {
var hexColor = TextColor.fromHexString(color); var hexColor = TextColor.fromHexString(color);
if (hexColor != null) { if (hexColor != null) {
style.color(hexColor); style.color(hexColor);
@ -105,57 +101,60 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
} }
} }
@Subst("minecraft:default") var font = compound.getString("font"); @Subst("minecraft:default") var font = compound.getString("font");
if (font != null) style.font(Key.key(font)); if (!font.isEmpty()) style.font(Key.key(font));
var bold = compound.getByte("bold"); BinaryTag bold = compound.get("bold");
if (bold != null) style.decoration(TextDecoration.BOLD, bold == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE); if (bold instanceof ByteBinaryTag b)
var italic = compound.getByte("italic"); style.decoration(TextDecoration.BOLD, b.value() == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
if (italic != null) style.decoration(TextDecoration.ITALIC, italic == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE); BinaryTag italic = compound.get("italic");
var underlined = compound.getByte("underlined"); if (italic instanceof ByteBinaryTag b)
if (underlined != null) style.decoration(TextDecoration.UNDERLINED, underlined == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE); style.decoration(TextDecoration.ITALIC, b.value() == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
var strikethrough = compound.getByte("strikethrough"); BinaryTag underlined = compound.get("underlined");
if (strikethrough != null) style.decoration(TextDecoration.STRIKETHROUGH, strikethrough == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE); if (underlined instanceof ByteBinaryTag b)
var obfuscated = compound.getByte("obfuscated"); style.decoration(TextDecoration.UNDERLINED, b.value() == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
if (obfuscated != null) style.decoration(TextDecoration.OBFUSCATED, obfuscated == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE); BinaryTag strikethrough = compound.get("strikethrough");
if (strikethrough instanceof ByteBinaryTag b)
style.decoration(TextDecoration.STRIKETHROUGH, b.value() == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
BinaryTag obfuscated = compound.get("obfuscated");
if (obfuscated instanceof ByteBinaryTag b)
style.decoration(TextDecoration.OBFUSCATED, b.value() == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
builder.style(style.build()); builder.style(style.build());
// Interactivity // Interactivity
var insertion = compound.getString("insertion"); var insertion = compound.getString("insertion");
if (insertion != null) builder.insertion(insertion); if (!insertion.isEmpty()) builder.insertion(insertion);
var clickEvent = compound.getCompound("clickEvent"); var clickEvent = compound.getCompound("clickEvent");
if (clickEvent != null) builder.clickEvent(deserializeClickEvent(clickEvent)); if (clickEvent.size() > 0) builder.clickEvent(deserializeClickEvent(clickEvent));
var hoverEvent = compound.getCompound("hoverEvent"); var hoverEvent = compound.getCompound("hoverEvent");
if (hoverEvent != null) builder.hoverEvent(deserializeHoverEvent(hoverEvent)); if (hoverEvent.size() > 0) builder.hoverEvent(deserializeHoverEvent(hoverEvent));
return builder.build(); return builder.build();
} }
private @NotNull ComponentBuilder<?, ?> deserializeTextComponent(@NotNull NBTCompound compound) { private @NotNull ComponentBuilder<?, ?> deserializeTextComponent(@NotNull CompoundBinaryTag compound) {
var text = compound.getString("text"); var text = compound.getString("text");
Check.notNull(text, "Text component must have a text field"); Check.notNull(text, "Text component must have a text field");
return Component.text().content(text); return Component.text().content(text);
} }
private @NotNull ComponentBuilder<?, ?> deserializeTranslatableComponent(@NotNull NBTCompound compound) { private @NotNull ComponentBuilder<?, ?> deserializeTranslatableComponent(@NotNull CompoundBinaryTag compound) {
var key = compound.getString("translate"); var key = compound.getString("translate");
Check.notNull(key, "Translatable component must have a translate field"); Check.notNull(key, "Translatable component must have a translate field");
var builder = Component.translatable().key(key); var builder = Component.translatable().key(key);
var fallback = compound.getString("fallback"); var fallback = compound.get("fallback");
if (fallback != null) builder.fallback(fallback); if (fallback instanceof StringBinaryTag s) builder.fallback(s.value());
NBTList<NBTCompound> args = compound.getList("with"); ListBinaryTag args = compound.getList("with", BinaryTagTypes.COMPOUND);
Check.argCondition(args != null && !args.getSubtagType().equals(NBTType.TAG_Compound), if (args.size() > 0) {
"Translatable component with field must be a list of compounds");
if (args != null) {
var list = new ArrayList<ComponentLike>(); var list = new ArrayList<ComponentLike>();
for (var arg : args) list.add(deserializeComponent(arg)); for (var arg : args) list.add(deserializeComponent((CompoundBinaryTag) arg));
builder.arguments(list); builder.arguments(list);
} }
return builder; return builder;
} }
private @NotNull ComponentBuilder<?, ?> deserializeScoreComponent(@NotNull NBTCompound compound) { private @NotNull ComponentBuilder<?, ?> deserializeScoreComponent(@NotNull CompoundBinaryTag compound) {
var scoreCompound = compound.getCompound("score"); var scoreCompound = compound.getCompound("score");
Check.notNull(scoreCompound, "Score component must have a score field"); Check.notNull(scoreCompound, "Score component must have a score field");
var name = scoreCompound.getString("name"); var name = scoreCompound.getString("name");
@ -165,14 +164,14 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
var builder = Component.score().name(name).objective(objective); var builder = Component.score().name(name).objective(objective);
var value = scoreCompound.getString("value"); var value = scoreCompound.getString("value");
if (value != null) if (!value.isEmpty())
//noinspection deprecation //noinspection deprecation
builder.value(value); builder.value(value);
return builder; return builder;
} }
private @NotNull ComponentBuilder<?, ?> deserializeSelectorComponent(@NotNull NBTCompound compound) { private @NotNull ComponentBuilder<?, ?> deserializeSelectorComponent(@NotNull CompoundBinaryTag compound) {
var selector = compound.getString("selector"); var selector = compound.getString("selector");
Check.notNull(selector, "Selector component must have a selector field"); Check.notNull(selector, "Selector component must have a selector field");
var builder = Component.selector().pattern(selector); var builder = Component.selector().pattern(selector);
@ -183,17 +182,17 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
return builder; return builder;
} }
private @NotNull ComponentBuilder<?, ?> deserializeKeybindComponent(@NotNull NBTCompound compound) { private @NotNull ComponentBuilder<?, ?> deserializeKeybindComponent(@NotNull CompoundBinaryTag compound) {
var keybind = compound.getString("keybind"); var keybind = compound.getString("keybind");
Check.notNull(keybind, "Keybind component must have a keybind field"); Check.notNull(keybind, "Keybind component must have a keybind field");
return Component.keybind().keybind(keybind); return Component.keybind().keybind(keybind);
} }
private @NotNull ComponentBuilder<?, ?> deserializeNbtComponent(@NotNull NBTCompound compound) { private @NotNull ComponentBuilder<?, ?> deserializeNbtComponent(@NotNull CompoundBinaryTag compound) {
throw new UnsupportedOperationException("NBTComponent is not implemented yet"); throw new UnsupportedOperationException("NBTComponent is not implemented yet");
} }
private @NotNull ClickEvent deserializeClickEvent(@NotNull NBTCompound compound) { private @NotNull ClickEvent deserializeClickEvent(@NotNull CompoundBinaryTag compound) {
var actionName = compound.getString("action"); var actionName = compound.getString("action");
Check.notNull(actionName, "Click event must have an action field"); Check.notNull(actionName, "Click event must have an action field");
var action = ClickEvent.Action.NAMES.value(actionName); var action = ClickEvent.Action.NAMES.value(actionName);
@ -203,7 +202,7 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
return ClickEvent.clickEvent(action, value); return ClickEvent.clickEvent(action, value);
} }
private @NotNull HoverEvent<?> deserializeHoverEvent(@NotNull NBTCompound compound) { private @NotNull HoverEvent<?> deserializeHoverEvent(@NotNull CompoundBinaryTag compound) {
var actionName = compound.getString("action"); var actionName = compound.getString("action");
Check.notNull(actionName, "Hover event must have an action field"); Check.notNull(actionName, "Hover event must have an action field");
var contents = compound.getCompound("contents"); var contents = compound.getCompound("contents");
@ -216,13 +215,12 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
@Subst("minecraft:stick") var id = contents.getString("id"); @Subst("minecraft:stick") var id = contents.getString("id");
Check.notNull(id, "Show item hover event must have an id field"); Check.notNull(id, "Show item hover event must have an id field");
var count = contents.getInt("count"); var count = contents.getInt("count");
var countInt = count == null ? 1 : count;
var tag = contents.getString("tag"); var tag = contents.getString("tag");
var binaryTag = tag == null ? null : BinaryTagHolder.binaryTagHolder(tag); var binaryTag = tag.isEmpty() ? null : BinaryTagHolder.binaryTagHolder(tag);
return HoverEvent.showItem(Key.key(id), countInt, binaryTag); return HoverEvent.showItem(Key.key(id), count, binaryTag);
} else if (action == HoverEvent.Action.SHOW_ENTITY) { } else if (action == HoverEvent.Action.SHOW_ENTITY) {
var name = contents.getCompound("name"); var name = contents.getCompound("name");
var nameComponent = name == null ? null : deserializeComponent(name); var nameComponent = name.size() == 0 ? null : deserializeComponent(name);
@Subst("minecraft:pig") var type = contents.getString("type"); @Subst("minecraft:pig") var type = contents.getString("type");
Check.notNull(type, "Show entity hover event must have a type field"); Check.notNull(type, "Show entity hover event must have a type field");
var id = contents.getString("id"); var id = contents.getString("id");
@ -235,36 +233,36 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
// SERIALIZATION // SERIALIZATION
private @NotNull NBT serializeComponent(@NotNull Component component) { private @NotNull CompoundBinaryTag serializeComponent(@NotNull Component component) {
MutableNBTCompound compound = new MutableNBTCompound(); CompoundBinaryTag.Builder compound = CompoundBinaryTag.builder();
// Base component types // Base component types
if (component instanceof TextComponent text) { if (component instanceof TextComponent text) {
compound.setString("type", "text"); compound.putString("type", "text");
compound.setString("text", text.content()); compound.putString("text", text.content());
} else if (component instanceof TranslatableComponent translatable) { } else if (component instanceof TranslatableComponent translatable) {
compound.setString("type", "translatable"); compound.putString("type", "translatable");
compound.setString("translate", translatable.key()); compound.putString("translate", translatable.key());
var fallback = translatable.fallback(); var fallback = translatable.fallback();
if (fallback != null) compound.setString("fallback", fallback); if (fallback != null) compound.putString("fallback", fallback);
var args = translatable.arguments(); var args = translatable.arguments();
if (!args.isEmpty()) compound.set("with", serializeTranslationArgs(args)); if (!args.isEmpty()) compound.put("with", serializeTranslationArgs(args));
} else if (component instanceof ScoreComponent score) { } else if (component instanceof ScoreComponent score) {
compound.setString("type", "score"); compound.putString("type", "score");
var scoreCompound = new MutableNBTCompound(); CompoundBinaryTag.Builder scoreCompound = CompoundBinaryTag.builder();
scoreCompound.setString("name", score.name()); scoreCompound.putString("name", score.name());
scoreCompound.setString("objective", score.objective()); scoreCompound.putString("objective", score.objective());
@SuppressWarnings("deprecation") var value = score.value(); @SuppressWarnings("deprecation") var value = score.value();
if (value != null) scoreCompound.setString("value", value); if (value != null) scoreCompound.putString("value", value);
compound.set("score", scoreCompound.toCompound()); compound.put("score", scoreCompound.build());
} else if (component instanceof SelectorComponent selector) { } else if (component instanceof SelectorComponent selector) {
compound.setString("type", "selector"); compound.putString("type", "selector");
compound.setString("selector", selector.pattern()); compound.putString("selector", selector.pattern());
var separator = selector.separator(); var separator = selector.separator();
if (separator != null) compound.set("separator", serializeComponent(separator)); if (separator != null) compound.put("separator", serializeComponent(separator));
} else if (component instanceof KeybindComponent keybind) { } else if (component instanceof KeybindComponent keybind) {
compound.setString("type", "keybind"); compound.putString("type", "keybind");
compound.setString("keybind", keybind.keybind()); compound.putString("keybind", keybind.keybind());
} else if (component instanceof NBTComponent<?, ?> nbt) { } else if (component instanceof NBTComponent<?, ?> nbt) {
//todo //todo
throw new UnsupportedOperationException("NBTComponent is not implemented yet"); throw new UnsupportedOperationException("NBTComponent is not implemented yet");
@ -274,10 +272,10 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
// Children // Children
if (!component.children().isEmpty()) { if (!component.children().isEmpty()) {
var children = new ArrayList<NBT>(); ListBinaryTag.Builder<CompoundBinaryTag> children = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
for (var child : component.children()) for (var child : component.children())
children.add(serializeComponent(child)); children.add(serializeComponent(child));
compound.set("extra", new NBTList<>(NBTType.TAG_Compound, children)); compound.put("extra", children.build());
} }
// Formatting // Formatting
@ -285,94 +283,89 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
var color = style.color(); var color = style.color();
if (color != null) { if (color != null) {
if (color instanceof NamedTextColor named) { if (color instanceof NamedTextColor named) {
compound.setString("color", named.toString()); compound.putString("color", named.toString());
} else { } else {
compound.setString("color", color.asHexString()); compound.putString("color", color.asHexString());
} }
} }
var font = style.font(); var font = style.font();
if (font != null) if (font != null)
compound.setString("font", font.toString()); compound.putString("font", font.toString());
var bold = style.decoration(TextDecoration.BOLD); var bold = style.decoration(TextDecoration.BOLD);
if (bold != TextDecoration.State.NOT_SET) if (bold != TextDecoration.State.NOT_SET)
setBool(compound, "bold", bold == TextDecoration.State.TRUE); compound.putBoolean("bold", bold == TextDecoration.State.TRUE);
var italic = style.decoration(TextDecoration.ITALIC); var italic = style.decoration(TextDecoration.ITALIC);
if (italic != TextDecoration.State.NOT_SET) if (italic != TextDecoration.State.NOT_SET)
setBool(compound, "italic", italic == TextDecoration.State.TRUE); compound.putBoolean("italic", italic == TextDecoration.State.TRUE);
var underlined = style.decoration(TextDecoration.UNDERLINED); var underlined = style.decoration(TextDecoration.UNDERLINED);
if (underlined != TextDecoration.State.NOT_SET) if (underlined != TextDecoration.State.NOT_SET)
setBool(compound, "underlined", underlined == TextDecoration.State.TRUE); compound.putBoolean("underlined", underlined == TextDecoration.State.TRUE);
var strikethrough = style.decoration(TextDecoration.STRIKETHROUGH); var strikethrough = style.decoration(TextDecoration.STRIKETHROUGH);
if (strikethrough != TextDecoration.State.NOT_SET) if (strikethrough != TextDecoration.State.NOT_SET)
setBool(compound, "strikethrough", strikethrough == TextDecoration.State.TRUE); compound.putBoolean("strikethrough", strikethrough == TextDecoration.State.TRUE);
var obfuscated = style.decoration(TextDecoration.OBFUSCATED); var obfuscated = style.decoration(TextDecoration.OBFUSCATED);
if (obfuscated != TextDecoration.State.NOT_SET) if (obfuscated != TextDecoration.State.NOT_SET)
setBool(compound, "obfuscated", obfuscated == TextDecoration.State.TRUE); compound.putBoolean("obfuscated", obfuscated == TextDecoration.State.TRUE);
// Interactivity // Interactivity
var insertion = component.insertion(); var insertion = component.insertion();
if (insertion != null) compound.setString("insertion", insertion); if (insertion != null) compound.putString("insertion", insertion);
var clickEvent = component.clickEvent(); var clickEvent = component.clickEvent();
if (clickEvent != null) compound.set("clickEvent", serializeClickEvent(clickEvent)); if (clickEvent != null) compound.put("clickEvent", serializeClickEvent(clickEvent));
var hoverEvent = component.hoverEvent(); var hoverEvent = component.hoverEvent();
if (hoverEvent != null) compound.set("hoverEvent", serializeHoverEvent(hoverEvent)); if (hoverEvent != null) compound.put("hoverEvent", serializeHoverEvent(hoverEvent));
return compound.toCompound(); return compound.build();
} }
private @NotNull NBT serializeTranslationArgs(@NotNull Collection<TranslationArgument> args) { private @NotNull BinaryTag serializeTranslationArgs(@NotNull Collection<TranslationArgument> args) {
var list = new ArrayList<NBT>(); ListBinaryTag.Builder<CompoundBinaryTag> argList = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
for (var arg : args) for (var arg : args)
list.add(serializeComponent(arg.asComponent())); argList.add(serializeComponent(arg.asComponent()));
return new NBTList<>(NBTType.TAG_Compound, list); return argList.build();
} }
private @NotNull NBT serializeClickEvent(@NotNull ClickEvent event) { private @NotNull BinaryTag serializeClickEvent(@NotNull ClickEvent event) {
var compound = new MutableNBTCompound(); return CompoundBinaryTag.builder()
compound.setString("action", event.action().toString()); .putString("action", event.action().toString())
compound.setString("value", event.value()); .putString("value", event.value())
return compound.toCompound(); .build();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private @NotNull NBT serializeHoverEvent(@NotNull HoverEvent<?> event) { private @NotNull BinaryTag serializeHoverEvent(@NotNull HoverEvent<?> event) {
var compound = new MutableNBTCompound(); CompoundBinaryTag.Builder compound = CompoundBinaryTag.builder();
//todo surely there is a better way to do this? //todo surely there is a better way to do this?
compound.setString("action", event.action().toString()); compound.putString("action", event.action().toString());
if (event.action() == HoverEvent.Action.SHOW_TEXT) { if (event.action() == HoverEvent.Action.SHOW_TEXT) {
var value = ((HoverEvent<Component>) event).value(); var value = ((HoverEvent<Component>) event).value();
compound.set("contents", serializeComponent(value)); compound.put("contents", serializeComponent(value));
} else if (event.action() == HoverEvent.Action.SHOW_ITEM) { } else if (event.action() == HoverEvent.Action.SHOW_ITEM) {
var value = ((HoverEvent<HoverEvent.ShowItem>) event).value(); var value = ((HoverEvent<HoverEvent.ShowItem>) event).value();
var itemCompound = new MutableNBTCompound(); CompoundBinaryTag.Builder itemCompound = CompoundBinaryTag.builder();
itemCompound.setString("id", value.item().asString()); itemCompound.putString("id", value.item().asString());
if (value.count() != 1) itemCompound.setInt("count", value.count()); if (value.count() != 1) itemCompound.putInt("count", value.count());
var tag = value.nbt(); var tag = value.nbt();
if (tag != null) itemCompound.setString("tag", tag.string()); if (tag != null) itemCompound.putString("tag", tag.string());
compound.set("contents", itemCompound.toCompound()); compound.put("contents", itemCompound.build());
} else if (event.action() == HoverEvent.Action.SHOW_ENTITY) { } else if (event.action() == HoverEvent.Action.SHOW_ENTITY) {
var value = ((HoverEvent<HoverEvent.ShowEntity>) event).value(); var value = ((HoverEvent<HoverEvent.ShowEntity>) event).value();
var entityCompound = new MutableNBTCompound(); CompoundBinaryTag.Builder entityCompound = CompoundBinaryTag.builder();
var name = value.name(); var name = value.name();
if (name != null) entityCompound.set("name", serializeComponent(name)); if (name != null) entityCompound.put("name", serializeComponent(name));
entityCompound.setString("type", value.type().asString()); entityCompound.putString("type", value.type().asString());
entityCompound.setString("id", value.id().toString()); entityCompound.putString("id", value.id().toString());
compound.set("contents", entityCompound.toCompound()); compound.put("contents", entityCompound.build());
} else { } else {
throw new UnsupportedOperationException("Unknown hover event action: " + event.action()); throw new UnsupportedOperationException("Unknown hover event action: " + event.action());
} }
return compound.toCompound(); return compound.build();
} }
private void setBool(@NotNull MutableNBTCompound compound, @NotNull String key, boolean value) {
compound.setByte(key, value ? (byte) 1 : 0);
}
} }

View File

@ -1,16 +1,15 @@
package net.minestom.server.command.builder.arguments.minecraft; package net.minestom.server.command.builder.arguments.minecraft;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.TagStringIO;
import net.minestom.server.command.CommandSender; import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.parser.SNBTParser;
import java.io.StringReader; import java.io.IOException;
/** /**
* Argument which can be used to retrieve an {@link ItemStack} from its material and with NBT data. * Argument which can be used to retrieve an {@link ItemStack} from its material and with NBT data.
@ -65,10 +64,10 @@ public class ArgumentItemStack extends Argument<ItemStack> {
final String sNBT = input.substring(nbtIndex).replace("\\\"", "\""); final String sNBT = input.substring(nbtIndex).replace("\\\"", "\"");
NBTCompound compound; CompoundBinaryTag compound;
try { try {
compound = (NBTCompound) new SNBTParser(new StringReader(sNBT)).parse(); compound = TagStringIO.get().asCompound(sNBT);
} catch (NBTException e) { } catch (IOException e) {
throw new ArgumentSyntaxException("Item NBT is invalid", input, INVALID_NBT); throw new ArgumentSyntaxException("Item NBT is invalid", input, INVALID_NBT);
} }

View File

@ -1,22 +1,21 @@
package net.minestom.server.command.builder.arguments.minecraft; package net.minestom.server.command.builder.arguments.minecraft;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.TagStringIO;
import net.minestom.server.command.CommandSender; import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.parser.SNBTParser;
import java.io.StringReader; import java.io.IOException;
/** /**
* Argument used to retrieve a {@link NBTCompound} if you need key-value data. * Argument used to retrieve a {@link CompoundBinaryTag} if you need key-value data.
* <p> * <p>
* Example: {display:{Name:"{\"text\":\"Sword of Power\"}"}} * Example: {display:{Name:"{\"text\":\"Sword of Power\"}"}}
*/ */
public class ArgumentNbtCompoundTag extends Argument<NBTCompound> { public class ArgumentNbtCompoundTag extends Argument<CompoundBinaryTag> {
public static final int INVALID_NBT = 1; public static final int INVALID_NBT = 1;
@ -26,15 +25,15 @@ public class ArgumentNbtCompoundTag extends Argument<NBTCompound> {
@NotNull @NotNull
@Override @Override
public NBTCompound parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException { public CompoundBinaryTag parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
try { try {
NBT nbt = new SNBTParser(new StringReader(input)).parse(); BinaryTag nbt = TagStringIO.get().asCompound(input);
if (!(nbt instanceof NBTCompound)) if (!(nbt instanceof CompoundBinaryTag compound))
throw new ArgumentSyntaxException("NBTCompound is invalid", input, INVALID_NBT); throw new ArgumentSyntaxException("NBTCompound is invalid", input, INVALID_NBT);
return (NBTCompound) nbt; return compound;
} catch (NBTException e) { } catch (IOException e) {
throw new ArgumentSyntaxException("NBTCompound is invalid", input, INVALID_NBT); throw new ArgumentSyntaxException("NBTCompound is invalid", input, INVALID_NBT);
} }
} }

View File

@ -1,23 +1,22 @@
package net.minestom.server.command.builder.arguments.minecraft; package net.minestom.server.command.builder.arguments.minecraft;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.TagStringIO;
import net.minestom.server.command.CommandSender; import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.parser.SNBTParser;
import java.io.StringReader; import java.io.IOException;
/** /**
* Argument used to retrieve a {@link NBT} based object, can be any kind of tag like * Argument used to retrieve a {@link BinaryTag} based object, can be any kind of tag like
* {@link org.jglrxavpok.hephaistos.nbt.NBTCompound}, {@link org.jglrxavpok.hephaistos.nbt.NBTList}, * {@link net.kyori.adventure.nbt.CompoundBinaryTag}, {@link net.kyori.adventure.nbt.ListBinaryTag},
* {@link org.jglrxavpok.hephaistos.nbt.NBTInt}, etc... * {@link net.kyori.adventure.nbt.IntBinaryTag}, etc...
* <p> * <p>
* Example: {display:{Name:"{\"text\":\"Sword of Power\"}"}} or [{display:{Name:"{\"text\":\"Sword of Power\"}"}}] * Example: {display:{Name:"{\"text\":\"Sword of Power\"}"}} or [{display:{Name:"{\"text\":\"Sword of Power\"}"}}]
*/ */
public class ArgumentNbtTag extends Argument<NBT> { public class ArgumentNbtTag extends Argument<BinaryTag> {
public static final int INVALID_NBT = 1; public static final int INVALID_NBT = 1;
@ -27,10 +26,10 @@ public class ArgumentNbtTag extends Argument<NBT> {
@NotNull @NotNull
@Override @Override
public NBT parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException { public BinaryTag parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
try { try {
return new SNBTParser(new StringReader(input)).parse(); return TagStringIO.get().asCompound(input);
} catch (NBTException e) { } catch (IOException e) {
throw new ArgumentSyntaxException("Invalid NBT", input, INVALID_NBT); throw new ArgumentSyntaxException("Invalid NBT", input, INVALID_NBT);
} }
} }

View File

@ -1,5 +1,6 @@
package net.minestom.server.entity; package net.minestom.server.entity;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.entity.metadata.animal.FrogMeta; import net.minestom.server.entity.metadata.animal.FrogMeta;
@ -15,7 +16,6 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability; import org.jetbrains.annotations.UnknownNullability;
import org.jglrxavpok.hephaistos.nbt.NBT;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle; import java.lang.invoke.VarHandle;
@ -89,7 +89,7 @@ public final class Metadata {
return new MetadataImpl.EntryImpl<>(TYPE_OPTBLOCKSTATE, value, NetworkBuffer.OPT_BLOCK_STATE); return new MetadataImpl.EntryImpl<>(TYPE_OPTBLOCKSTATE, value, NetworkBuffer.OPT_BLOCK_STATE);
} }
public static Entry<NBT> NBT(@NotNull NBT nbt) { public static Entry<BinaryTag> NBT(@NotNull BinaryTag nbt) {
return new MetadataImpl.EntryImpl<>(TYPE_NBT, nbt, NetworkBuffer.NBT); return new MetadataImpl.EntryImpl<>(TYPE_NBT, nbt, NetworkBuffer.NBT);
} }

View File

@ -1,5 +1,6 @@
package net.minestom.server.entity; package net.minestom.server.entity;
import net.kyori.adventure.nbt.EndBinaryTag;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.metadata.animal.FrogMeta; import net.minestom.server.entity.metadata.animal.FrogMeta;
@ -13,7 +14,6 @@ import net.minestom.server.utils.Direction;
import net.minestom.server.utils.collection.ObjectArray; import net.minestom.server.utils.collection.ObjectArray;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.UnknownNullability; import org.jetbrains.annotations.UnknownNullability;
import org.jglrxavpok.hephaistos.nbt.NBTEnd;
import static net.minestom.server.entity.Metadata.*; import static net.minestom.server.entity.Metadata.*;
import static net.minestom.server.network.NetworkBuffer.VAR_INT; import static net.minestom.server.network.NetworkBuffer.VAR_INT;
@ -38,7 +38,7 @@ final class MetadataImpl {
EMPTY_VALUES.set(TYPE_OPTUUID, OptUUID(null)); EMPTY_VALUES.set(TYPE_OPTUUID, OptUUID(null));
EMPTY_VALUES.set(TYPE_BLOCKSTATE, BlockState(Block.AIR.id())); EMPTY_VALUES.set(TYPE_BLOCKSTATE, BlockState(Block.AIR.id()));
EMPTY_VALUES.set(TYPE_OPTBLOCKSTATE, OptBlockState(null)); EMPTY_VALUES.set(TYPE_OPTBLOCKSTATE, OptBlockState(null));
EMPTY_VALUES.set(TYPE_NBT, NBT(NBTEnd.INSTANCE)); EMPTY_VALUES.set(TYPE_NBT, NBT(EndBinaryTag.endBinaryTag()));
//EMPTY_VALUES.set(TYPE_PARTICLE -> throw new UnsupportedOperationException(); //EMPTY_VALUES.set(TYPE_PARTICLE -> throw new UnsupportedOperationException();
EMPTY_VALUES.set(TYPE_VILLAGERDATA, VillagerData(0, 0, 0)); EMPTY_VALUES.set(TYPE_VILLAGERDATA, VillagerData(0, 0, 0));
EMPTY_VALUES.set(TYPE_OPTVARINT, OptVarInt(null)); EMPTY_VALUES.set(TYPE_OPTVARINT, OptVarInt(null));

View File

@ -1,12 +1,12 @@
package net.minestom.server.entity.damage; package net.minestom.server.entity.damage;
import net.minestom.server.registry.StaticProtocolObject; import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.registry.Registry; import net.minestom.server.registry.Registry;
import net.minestom.server.registry.StaticProtocolObject;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Collection; import java.util.Collection;
@ -36,7 +36,7 @@ public sealed interface DamageType extends StaticProtocolObject, DamageTypes per
return registry().scaling(); return registry().scaling();
} }
NBTCompound asNBT(); CompoundBinaryTag asNBT();
static @NotNull Collection<@NotNull DamageType> values() { static @NotNull Collection<@NotNull DamageType> values() {
return DamageTypeImpl.values(); return DamageTypeImpl.values();
@ -54,7 +54,7 @@ public sealed interface DamageType extends StaticProtocolObject, DamageTypes per
return DamageTypeImpl.getId(id); return DamageTypeImpl.getId(id);
} }
static NBTCompound getNBT() { static CompoundBinaryTag getNBT() {
return DamageTypeImpl.getNBT(); return DamageTypeImpl.getNBT();
} }
} }

View File

@ -1,14 +1,12 @@
package net.minestom.server.entity.damage; package net.minestom.server.entity.damage;
import net.kyori.adventure.nbt.BinaryTagTypes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.ListBinaryTag;
import net.minestom.server.registry.Registry; import net.minestom.server.registry.Registry;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
record DamageTypeImpl(Registry.DamageTypeEntry registry, int id) implements DamageType { record DamageTypeImpl(Registry.DamageTypeEntry registry, int id) implements DamageType {
@ -33,12 +31,12 @@ record DamageTypeImpl(Registry.DamageTypeEntry registry, int id) implements Dama
} }
@Override @Override
public NBTCompound asNBT() { public CompoundBinaryTag asNBT() {
var elem = new HashMap<String, NBT>(); return CompoundBinaryTag.builder()
elem.put("exhaustion", NBT.Float(registry.exhaustion())); .putFloat("exhaustion", registry.exhaustion())
elem.put("message_id", NBT.String(registry.messageId())); .putString("message_id", registry.messageId())
elem.put("scaling", NBT.String(registry.scaling())); .putString("scaling", registry.scaling())
return NBT.Compound(elem); .build();
} }
static Collection<DamageType> values() { static Collection<DamageType> values() {
@ -55,22 +53,23 @@ record DamageTypeImpl(Registry.DamageTypeEntry registry, int id) implements Dama
return id; return id;
} }
private static NBTCompound lazyNbt = null; private static CompoundBinaryTag lazyNbt = null;
static NBTCompound getNBT() { static CompoundBinaryTag getNBT() {
if (lazyNbt == null) { if (lazyNbt == null) {
var damageTypes = values().stream() var entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
.map((damageType) -> NBT.Compound(Map.of( for (var damageType : values()) {
"id", NBT.Int(damageType.id()), entries.add(CompoundBinaryTag.builder()
"name", NBT.String(damageType.name()), .putInt("id", damageType.id())
"element", damageType.asNBT() .putString("name", damageType.name())
))) .put("element", damageType.asNBT())
.toList(); .build());
}
lazyNbt = NBT.Compound(Map.of( lazyNbt = CompoundBinaryTag.builder()
"type", NBT.String("minecraft:damage_type"), .putString("type", "minecraft:damage_type")
"value", NBT.List(NBTType.TAG_Compound, damageTypes) .put("value", entries.build())
)); .build();
} }
return lazyNbt; return lazyNbt;
} }

View File

@ -1,12 +1,11 @@
package net.minestom.server.entity.metadata; package net.minestom.server.entity.metadata;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.entity.Entity; import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Metadata; import net.minestom.server.entity.Metadata;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import java.util.Map;
public class PlayerMeta extends LivingEntityMeta { public class PlayerMeta extends LivingEntityMeta {
public static final byte OFFSET = LivingEntityMeta.MAX_OFFSET; public static final byte OFFSET = LivingEntityMeta.MAX_OFFSET;
@ -109,23 +108,23 @@ public class PlayerMeta extends LivingEntityMeta {
} }
@Nullable @Nullable
public NBT getLeftShoulderEntityData() { public BinaryTag getLeftShoulderEntityData() {
return super.metadata.getIndex(OFFSET + 4, null); return super.metadata.getIndex(OFFSET + 4, null);
} }
public void setLeftShoulderEntityData(@Nullable NBT value) { public void setLeftShoulderEntityData(@Nullable BinaryTag value) {
if (value == null) value = NBT.Compound(Map.of()); if (value == null) value = CompoundBinaryTag.empty();
super.metadata.setIndex(OFFSET + 4, Metadata.NBT(value)); super.metadata.setIndex(OFFSET + 4, Metadata.NBT(value));
} }
@Nullable @Nullable
public NBT getRightShoulderEntityData() { public BinaryTag getRightShoulderEntityData() {
return super.metadata.getIndex(OFFSET + 5, null); return super.metadata.getIndex(OFFSET + 5, null);
} }
public void setRightShoulderEntityData(@Nullable NBT value) { public void setRightShoulderEntityData(@Nullable BinaryTag value) {
if (value == null) value = NBT.Compound(Map.of()); if (value == null) value = CompoundBinaryTag.empty();
super.metadata.setIndex(OFFSET + 5, Metadata.NBT(value)); super.metadata.setIndex(OFFSET + 5, Metadata.NBT(value));
} }

View File

@ -1,34 +1,17 @@
package net.minestom.server.instance; package net.minestom.server.instance;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.IntIntImmutablePair; import it.unimi.dsi.fastutil.ints.IntIntImmutablePair;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.async.AsyncUtils;
import net.minestom.server.world.biomes.Biome; import net.minestom.server.world.biomes.Biome;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.mca.*;
import org.jglrxavpok.hephaistos.mca.readers.ChunkReader;
import org.jglrxavpok.hephaistos.mca.readers.ChunkSectionReader;
import org.jglrxavpok.hephaistos.mca.readers.SectionBiomeInformation;
import org.jglrxavpok.hephaistos.mca.writer.ChunkSectionWriter;
import org.jglrxavpok.hephaistos.mca.writer.ChunkWriter;
import org.jglrxavpok.hephaistos.nbt.*;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.util.Set;
import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -36,7 +19,7 @@ public class AnvilLoader implements IChunkLoader {
private final static Logger LOGGER = LoggerFactory.getLogger(AnvilLoader.class); private final static Logger LOGGER = LoggerFactory.getLogger(AnvilLoader.class);
private final static Biome PLAINS = MinecraftServer.getBiomeManager().getByName(NamespaceID.from("minecraft:plains")); private final static Biome PLAINS = MinecraftServer.getBiomeManager().getByName(NamespaceID.from("minecraft:plains"));
private final Map<String, RegionFile> alreadyLoaded = new ConcurrentHashMap<>(); // private final Map<String, RegionFile> alreadyLoaded = new ConcurrentHashMap<>();
private final Path path; private final Path path;
private final Path levelPath; private final Path levelPath;
private final Path regionPath; private final Path regionPath;
@ -50,7 +33,7 @@ public class AnvilLoader implements IChunkLoader {
private final RegionCache perRegionLoadedChunks = new RegionCache(); private final RegionCache perRegionLoadedChunks = new RegionCache();
// thread local to avoid contention issues with locks // thread local to avoid contention issues with locks
private final ThreadLocal<Int2ObjectMap<BlockState>> blockStateId2ObjectCacheTLS = ThreadLocal.withInitial(Int2ObjectArrayMap::new); // private final ThreadLocal<Int2ObjectMap<BlockState>> blockStateId2ObjectCacheTLS = ThreadLocal.withInitial(Int2ObjectArrayMap::new);
public AnvilLoader(@NotNull Path path) { public AnvilLoader(@NotNull Path path) {
this.path = path; this.path = path;
@ -64,409 +47,409 @@ public class AnvilLoader implements IChunkLoader {
@Override @Override
public void loadInstance(@NotNull Instance instance) { public void loadInstance(@NotNull Instance instance) {
if (!Files.exists(levelPath)) { // if (!Files.exists(levelPath)) {
return; // return;
} // }
try (var reader = new NBTReader(Files.newInputStream(levelPath))) { // try (var reader = new NBTReader(Files.newInputStream(levelPath))) {
final NBTCompound tag = (NBTCompound) reader.read(); // final NBTCompound tag = (NBTCompound) reader.read();
Files.copy(levelPath, path.resolve("level.dat_old"), StandardCopyOption.REPLACE_EXISTING); // Files.copy(levelPath, path.resolve("level.dat_old"), StandardCopyOption.REPLACE_EXISTING);
instance.tagHandler().updateContent(tag); // instance.tagHandler().updateContent(tag);
} catch (IOException | NBTException e) { // } catch (IOException | NBTException e) {
MinecraftServer.getExceptionManager().handleException(e); // MinecraftServer.getExceptionManager().handleException(e);
} // }
} }
@Override @Override
public @NotNull CompletableFuture<@Nullable Chunk> loadChunk(@NotNull Instance instance, int chunkX, int chunkZ) { public @NotNull CompletableFuture<@Nullable Chunk> loadChunk(@NotNull Instance instance, int chunkX, int chunkZ) {
if (!Files.exists(path)) { // if (!Files.exists(path)) {
// No world folder // // No world folder
return CompletableFuture.completedFuture(null); // return CompletableFuture.completedFuture(null);
} // }
try { // try {
return loadMCA(instance, chunkX, chunkZ); // return loadMCA(instance, chunkX, chunkZ);
} catch (Exception e) { // } catch (Exception e) {
MinecraftServer.getExceptionManager().handleException(e); // MinecraftServer.getExceptionManager().handleException(e);
} // }
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
//
private @NotNull CompletableFuture<@Nullable Chunk> loadMCA(Instance instance, int chunkX, int chunkZ) throws IOException, AnvilException { // private @NotNull CompletableFuture<@Nullable Chunk> loadMCA(Instance instance, int chunkX, int chunkZ) throws IOException, AnvilException {
final RegionFile mcaFile = getMCAFile(instance, chunkX, chunkZ); // final RegionFile mcaFile = getMCAFile(instance, chunkX, chunkZ);
if (mcaFile == null) // if (mcaFile == null)
return CompletableFuture.completedFuture(null); // return CompletableFuture.completedFuture(null);
final NBTCompound chunkData = mcaFile.getChunkData(chunkX, chunkZ); // final NBTCompound chunkData = mcaFile.getChunkData(chunkX, chunkZ);
if (chunkData == null) // if (chunkData == null)
return CompletableFuture.completedFuture(null); // return CompletableFuture.completedFuture(null);
//
final ChunkReader chunkReader = new ChunkReader(chunkData); // final ChunkReader chunkReader = new ChunkReader(chunkData);
//
Chunk chunk = instance.getChunkSupplier().createChunk(instance, chunkX, chunkZ); // Chunk chunk = instance.getChunkSupplier().createChunk(instance, chunkX, chunkZ);
synchronized (chunk) { // synchronized (chunk) {
var yRange = chunkReader.getYRange(); // var yRange = chunkReader.getYRange();
if (yRange.getStart() < instance.getDimensionType().getMinY()) { // if (yRange.getStart() < instance.getDimensionType().getMinY()) {
throw new AnvilException( // throw new AnvilException(
String.format("Trying to load chunk with minY = %d, but instance dimension type (%s) has a minY of %d", // String.format("Trying to load chunk with minY = %d, but instance dimension type (%s) has a minY of %d",
yRange.getStart(), // yRange.getStart(),
instance.getDimensionType().getName().asString(), // instance.getDimensionType().getName().asString(),
instance.getDimensionType().getMinY() // instance.getDimensionType().getMinY()
)); // ));
} // }
if (yRange.getEndInclusive() > instance.getDimensionType().getMaxY()) { // if (yRange.getEndInclusive() > instance.getDimensionType().getMaxY()) {
throw new AnvilException( // throw new AnvilException(
String.format("Trying to load chunk with maxY = %d, but instance dimension type (%s) has a maxY of %d", // String.format("Trying to load chunk with maxY = %d, but instance dimension type (%s) has a maxY of %d",
yRange.getEndInclusive(), // yRange.getEndInclusive(),
instance.getDimensionType().getName().asString(), // instance.getDimensionType().getName().asString(),
instance.getDimensionType().getMaxY() // instance.getDimensionType().getMaxY()
)); // ));
} // }
//
// TODO: Parallelize block, block entities and biome loading // // TODO: Parallelize block, block entities and biome loading
// Blocks + Biomes // // Blocks + Biomes
loadSections(chunk, chunkReader); // loadSections(chunk, chunkReader);
//
// Block entities // // Block entities
loadBlockEntities(chunk, chunkReader); // loadBlockEntities(chunk, chunkReader);
} // }
synchronized (perRegionLoadedChunks) { // synchronized (perRegionLoadedChunks) {
int regionX = CoordinatesKt.chunkToRegion(chunkX); // int regionX = CoordinatesKt.chunkToRegion(chunkX);
int regionZ = CoordinatesKt.chunkToRegion(chunkZ); // int regionZ = CoordinatesKt.chunkToRegion(chunkZ);
var chunks = perRegionLoadedChunks.computeIfAbsent(new IntIntImmutablePair(regionX, regionZ), r -> new HashSet<>()); // region cache may have been removed on another thread due to unloadChunk // var chunks = perRegionLoadedChunks.computeIfAbsent(new IntIntImmutablePair(regionX, regionZ), r -> new HashSet<>()); // region cache may have been removed on another thread due to unloadChunk
chunks.add(new IntIntImmutablePair(chunkX, chunkZ)); // chunks.add(new IntIntImmutablePair(chunkX, chunkZ));
} // }
return CompletableFuture.completedFuture(chunk); // return CompletableFuture.completedFuture(chunk);
} // }
//
private @Nullable RegionFile getMCAFile(Instance instance, int chunkX, int chunkZ) { // private @Nullable RegionFile getMCAFile(Instance instance, int chunkX, int chunkZ) {
final int regionX = CoordinatesKt.chunkToRegion(chunkX); // final int regionX = CoordinatesKt.chunkToRegion(chunkX);
final int regionZ = CoordinatesKt.chunkToRegion(chunkZ); // final int regionZ = CoordinatesKt.chunkToRegion(chunkZ);
return alreadyLoaded.computeIfAbsent(RegionFile.Companion.createFileName(regionX, regionZ), n -> { // return alreadyLoaded.computeIfAbsent(RegionFile.Companion.createFileName(regionX, regionZ), n -> {
try { // try {
final Path regionPath = this.regionPath.resolve(n); // final Path regionPath = this.regionPath.resolve(n);
if (!Files.exists(regionPath)) { // if (!Files.exists(regionPath)) {
return null; // return null;
} // }
synchronized (perRegionLoadedChunks) { // synchronized (perRegionLoadedChunks) {
Set<IntIntImmutablePair> previousVersion = perRegionLoadedChunks.put(new IntIntImmutablePair(regionX, regionZ), new HashSet<>()); // Set<IntIntImmutablePair> previousVersion = perRegionLoadedChunks.put(new IntIntImmutablePair(regionX, regionZ), new HashSet<>());
assert previousVersion == null : "The AnvilLoader cache should not already have data for this region."; // assert previousVersion == null : "The AnvilLoader cache should not already have data for this region.";
} // }
return new RegionFile(new RandomAccessFile(regionPath.toFile(), "rw"), regionX, regionZ, instance.getDimensionType().getMinY(), instance.getDimensionType().getMaxY() - 1); // return new RegionFile(new RandomAccessFile(regionPath.toFile(), "rw"), regionX, regionZ, instance.getDimensionType().getMinY(), instance.getDimensionType().getMaxY() - 1);
} catch (IOException | AnvilException e) { // } catch (IOException | AnvilException e) {
MinecraftServer.getExceptionManager().handleException(e); // MinecraftServer.getExceptionManager().handleException(e);
return null; // return null;
} // }
}); // });
} // }
//
private void loadSections(Chunk chunk, ChunkReader chunkReader) { // private void loadSections(Chunk chunk, ChunkReader chunkReader) {
final HashMap<String, Biome> biomeCache = new HashMap<>(); // final HashMap<String, Biome> biomeCache = new HashMap<>();
for (NBTCompound sectionNBT : chunkReader.getSections()) { // for (NBTCompound sectionNBT : chunkReader.getSections()) {
ChunkSectionReader sectionReader = new ChunkSectionReader(chunkReader.getMinecraftVersion(), sectionNBT); // ChunkSectionReader sectionReader = new ChunkSectionReader(chunkReader.getMinecraftVersion(), sectionNBT);
//
if (sectionReader.isSectionEmpty()) continue; // if (sectionReader.isSectionEmpty()) continue;
final int sectionY = sectionReader.getY(); // final int sectionY = sectionReader.getY();
final int yOffset = Chunk.CHUNK_SECTION_SIZE * sectionY; // final int yOffset = Chunk.CHUNK_SECTION_SIZE * sectionY;
//
Section section = chunk.getSection(sectionY); // Section section = chunk.getSection(sectionY);
//
if (sectionReader.getSkyLight() != null) { // if (sectionReader.getSkyLight() != null) {
section.setSkyLight(sectionReader.getSkyLight().copyArray()); // section.setSkyLight(sectionReader.getSkyLight().copyArray());
} // }
if (sectionReader.getBlockLight() != null) { // if (sectionReader.getBlockLight() != null) {
section.setBlockLight(sectionReader.getBlockLight().copyArray()); // section.setBlockLight(sectionReader.getBlockLight().copyArray());
} // }
//
// Biomes // // Biomes
if (chunkReader.getGenerationStatus().compareTo(ChunkColumn.GenerationStatus.Biomes) > 0) { // if (chunkReader.getGenerationStatus().compareTo(ChunkColumn.GenerationStatus.Biomes) > 0) {
SectionBiomeInformation sectionBiomeInformation = chunkReader.readSectionBiomes(sectionReader); // SectionBiomeInformation sectionBiomeInformation = chunkReader.readSectionBiomes(sectionReader);
//
if (sectionBiomeInformation != null && sectionBiomeInformation.hasBiomeInformation()) { // if (sectionBiomeInformation != null && sectionBiomeInformation.hasBiomeInformation()) {
if (sectionBiomeInformation.isFilledWithSingleBiome()) { // if (sectionBiomeInformation.isFilledWithSingleBiome()) {
for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) { // for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) {
for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { // for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) { // for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
int finalX = chunk.chunkX * Chunk.CHUNK_SIZE_X + x; // int finalX = chunk.chunkX * Chunk.CHUNK_SIZE_X + x;
int finalZ = chunk.chunkZ * Chunk.CHUNK_SIZE_Z + z; // int finalZ = chunk.chunkZ * Chunk.CHUNK_SIZE_Z + z;
int finalY = sectionY * Chunk.CHUNK_SECTION_SIZE + y; // int finalY = sectionY * Chunk.CHUNK_SECTION_SIZE + y;
String biomeName = sectionBiomeInformation.getBaseBiome(); // String biomeName = sectionBiomeInformation.getBaseBiome();
Biome biome = biomeCache.computeIfAbsent(biomeName, n -> // Biome biome = biomeCache.computeIfAbsent(biomeName, n ->
Objects.requireNonNullElse(MinecraftServer.getBiomeManager().getByName(NamespaceID.from(n)), PLAINS)); // Objects.requireNonNullElse(MinecraftServer.getBiomeManager().getByName(NamespaceID.from(n)), PLAINS));
chunk.setBiome(finalX, finalY, finalZ, biome); // chunk.setBiome(finalX, finalY, finalZ, biome);
} // }
} // }
} // }
} else { // } else {
for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) { // for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) {
for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { // for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) { // for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
int finalX = chunk.chunkX * Chunk.CHUNK_SIZE_X + x; // int finalX = chunk.chunkX * Chunk.CHUNK_SIZE_X + x;
int finalZ = chunk.chunkZ * Chunk.CHUNK_SIZE_Z + z; // int finalZ = chunk.chunkZ * Chunk.CHUNK_SIZE_Z + z;
int finalY = sectionY * Chunk.CHUNK_SECTION_SIZE + y; // int finalY = sectionY * Chunk.CHUNK_SECTION_SIZE + y;
//
int index = x / 4 + (z / 4) * 4 + (y / 4) * 16; // int index = x / 4 + (z / 4) * 4 + (y / 4) * 16;
String biomeName = sectionBiomeInformation.getBiomes()[index]; // String biomeName = sectionBiomeInformation.getBiomes()[index];
Biome biome = biomeCache.computeIfAbsent(biomeName, n -> // Biome biome = biomeCache.computeIfAbsent(biomeName, n ->
Objects.requireNonNullElse(MinecraftServer.getBiomeManager().getByName(NamespaceID.from(n)), PLAINS)); // Objects.requireNonNullElse(MinecraftServer.getBiomeManager().getByName(NamespaceID.from(n)), PLAINS));
chunk.setBiome(finalX, finalY, finalZ, biome); // chunk.setBiome(finalX, finalY, finalZ, biome);
} // }
} // }
} // }
} // }
} // }
} // }
//
// Blocks // // Blocks
final NBTList<NBTCompound> blockPalette = sectionReader.getBlockPalette(); // final NBTList<NBTCompound> blockPalette = sectionReader.getBlockPalette();
if (blockPalette != null) { // if (blockPalette != null) {
final int[] blockStateIndices = sectionReader.getUncompressedBlockStateIDs(); // final int[] blockStateIndices = sectionReader.getUncompressedBlockStateIDs();
Block[] convertedPalette = new Block[blockPalette.getSize()]; // Block[] convertedPalette = new Block[blockPalette.getSize()];
for (int i = 0; i < convertedPalette.length; i++) { // for (int i = 0; i < convertedPalette.length; i++) {
final NBTCompound paletteEntry = blockPalette.get(i); // final NBTCompound paletteEntry = blockPalette.get(i);
String blockName = Objects.requireNonNull(paletteEntry.getString("Name")); // String blockName = Objects.requireNonNull(paletteEntry.getString("Name"));
if (blockName.equals("minecraft:air")) { // if (blockName.equals("minecraft:air")) {
convertedPalette[i] = Block.AIR; // convertedPalette[i] = Block.AIR;
} else { // } else {
if (blockName.equals("minecraft:grass")) { // if (blockName.equals("minecraft:grass")) {
blockName = "minecraft:short_grass"; // blockName = "minecraft:short_grass";
} // }
Block block = Objects.requireNonNull(Block.fromNamespaceId(blockName)); // Block block = Objects.requireNonNull(Block.fromNamespaceId(blockName));
// Properties // // Properties
final Map<String, String> properties = new HashMap<>(); // final Map<String, String> properties = new HashMap<>();
NBTCompound propertiesNBT = paletteEntry.getCompound("Properties"); // NBTCompound propertiesNBT = paletteEntry.getCompound("Properties");
if (propertiesNBT != null) { // if (propertiesNBT != null) {
for (var property : propertiesNBT) { // for (var property : propertiesNBT) {
if (property.getValue().getID() != NBTType.TAG_String) { // if (property.getValue().getID() != NBTType.TAG_String) {
LOGGER.warn("Fail to parse block state properties {}, expected a TAG_String for {}, but contents were {}", // LOGGER.warn("Fail to parse block state properties {}, expected a TAG_String for {}, but contents were {}",
propertiesNBT, // propertiesNBT,
property.getKey(), // property.getKey(),
property.getValue().toSNBT()); // property.getValue().toSNBT());
} else { // } else {
properties.put(property.getKey(), ((NBTString) property.getValue()).getValue()); // properties.put(property.getKey(), ((NBTString) property.getValue()).getValue());
} // }
} // }
} // }
//
if (!properties.isEmpty()) block = block.withProperties(properties); // if (!properties.isEmpty()) block = block.withProperties(properties);
// Handler // // Handler
final BlockHandler handler = MinecraftServer.getBlockManager().getHandler(block.name()); // final BlockHandler handler = MinecraftServer.getBlockManager().getHandler(block.name());
if (handler != null) block = block.withHandler(handler); // if (handler != null) block = block.withHandler(handler);
//
convertedPalette[i] = block; // convertedPalette[i] = block;
} // }
} // }
//
for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) { // for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) {
for (int z = 0; z < Chunk.CHUNK_SECTION_SIZE; z++) { // for (int z = 0; z < Chunk.CHUNK_SECTION_SIZE; z++) {
for (int x = 0; x < Chunk.CHUNK_SECTION_SIZE; x++) { // for (int x = 0; x < Chunk.CHUNK_SECTION_SIZE; x++) {
try { // try {
final int blockIndex = y * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SECTION_SIZE + z * Chunk.CHUNK_SECTION_SIZE + x; // final int blockIndex = y * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SECTION_SIZE + z * Chunk.CHUNK_SECTION_SIZE + x;
final int paletteIndex = blockStateIndices[blockIndex]; // final int paletteIndex = blockStateIndices[blockIndex];
final Block block = convertedPalette[paletteIndex]; // final Block block = convertedPalette[paletteIndex];
//
chunk.setBlock(x, y + yOffset, z, block); // chunk.setBlock(x, y + yOffset, z, block);
} catch (Exception e) { // } catch (Exception e) {
MinecraftServer.getExceptionManager().handleException(e); // MinecraftServer.getExceptionManager().handleException(e);
} // }
} // }
} // }
} // }
} // }
} // }
} // }
//
private void loadBlockEntities(Chunk loadedChunk, ChunkReader chunkReader) { // private void loadBlockEntities(Chunk loadedChunk, ChunkReader chunkReader) {
for (NBTCompound te : chunkReader.getBlockEntities()) { // for (NBTCompound te : chunkReader.getBlockEntities()) {
final var x = te.getInt("x"); // final var x = te.getInt("x");
final var y = te.getInt("y"); // final var y = te.getInt("y");
final var z = te.getInt("z"); // final var z = te.getInt("z");
if (x == null || y == null || z == null) { // if (x == null || y == null || z == null) {
LOGGER.warn("Tile entity has failed to load due to invalid coordinate"); // LOGGER.warn("Tile entity has failed to load due to invalid coordinate");
continue; // continue;
} // }
Block block = loadedChunk.getBlock(x, y, z); // Block block = loadedChunk.getBlock(x, y, z);
//
final String tileEntityID = te.getString("id"); // final String tileEntityID = te.getString("id");
if (tileEntityID != null) { // if (tileEntityID != null) {
final BlockHandler handler = MinecraftServer.getBlockManager().getHandlerOrDummy(tileEntityID); // final BlockHandler handler = MinecraftServer.getBlockManager().getHandlerOrDummy(tileEntityID);
block = block.withHandler(handler); // block = block.withHandler(handler);
} // }
// Remove anvil tags // // Remove anvil tags
MutableNBTCompound mutableCopy = te.toMutableCompound(); // MutableNBTCompound mutableCopy = te.toMutableCompound();
mutableCopy.remove("id"); // mutableCopy.remove("id");
mutableCopy.remove("x"); // mutableCopy.remove("x");
mutableCopy.remove("y"); // mutableCopy.remove("y");
mutableCopy.remove("z"); // mutableCopy.remove("z");
mutableCopy.remove("keepPacked"); // mutableCopy.remove("keepPacked");
// Place block // // Place block
final var finalBlock = mutableCopy.getSize() > 0 ? // final var finalBlock = mutableCopy.getSize() > 0 ?
block.withNbt(mutableCopy.toCompound()) : block; // block.withNbt(mutableCopy.toCompound()) : block;
loadedChunk.setBlock(x, y, z, finalBlock); // loadedChunk.setBlock(x, y, z, finalBlock);
} // }
} // }
//
@Override @Override
public @NotNull CompletableFuture<Void> saveInstance(@NotNull Instance instance) { public @NotNull CompletableFuture<Void> saveInstance(@NotNull Instance instance) {
final NBTCompound nbt = instance.tagHandler().asCompound(); // final NBTCompound nbt = instance.tagHandler().asCompound();
if (nbt.isEmpty()) { // if (nbt.isEmpty()) {
// Instance has no data // // Instance has no data
return AsyncUtils.VOID_FUTURE; // return AsyncUtils.VOID_FUTURE;
} // }
try (NBTWriter writer = new NBTWriter(Files.newOutputStream(levelPath))) { // try (NBTWriter writer = new NBTWriter(Files.newOutputStream(levelPath))) {
writer.writeNamed("", nbt); // writer.writeNamed("", nbt);
} catch (IOException e) { // } catch (IOException e) {
e.printStackTrace(); // e.printStackTrace();
} // }
return AsyncUtils.VOID_FUTURE; return AsyncUtils.VOID_FUTURE;
} }
@Override @Override
public @NotNull CompletableFuture<Void> saveChunk(@NotNull Chunk chunk) { public @NotNull CompletableFuture<Void> saveChunk(@NotNull Chunk chunk) {
final int chunkX = chunk.getChunkX(); // final int chunkX = chunk.getChunkX();
final int chunkZ = chunk.getChunkZ(); // final int chunkZ = chunk.getChunkZ();
RegionFile mcaFile; // RegionFile mcaFile;
synchronized (alreadyLoaded) { // synchronized (alreadyLoaded) {
mcaFile = getMCAFile(chunk.instance, chunkX, chunkZ); // mcaFile = getMCAFile(chunk.instance, chunkX, chunkZ);
if (mcaFile == null) { // if (mcaFile == null) {
final int regionX = CoordinatesKt.chunkToRegion(chunkX); // final int regionX = CoordinatesKt.chunkToRegion(chunkX);
final int regionZ = CoordinatesKt.chunkToRegion(chunkZ); // final int regionZ = CoordinatesKt.chunkToRegion(chunkZ);
final String n = RegionFile.Companion.createFileName(regionX, regionZ); // final String n = RegionFile.Companion.createFileName(regionX, regionZ);
File regionFile = new File(regionPath.toFile(), n); // File regionFile = new File(regionPath.toFile(), n);
try { // try {
if (!regionFile.exists()) { // if (!regionFile.exists()) {
if (!regionFile.getParentFile().exists()) { // if (!regionFile.getParentFile().exists()) {
regionFile.getParentFile().mkdirs(); // regionFile.getParentFile().mkdirs();
} // }
regionFile.createNewFile(); // regionFile.createNewFile();
} // }
mcaFile = new RegionFile(new RandomAccessFile(regionFile, "rw"), regionX, regionZ); // mcaFile = new RegionFile(new RandomAccessFile(regionFile, "rw"), regionX, regionZ);
alreadyLoaded.put(n, mcaFile); // alreadyLoaded.put(n, mcaFile);
} catch (AnvilException | IOException e) { // } catch (AnvilException | IOException e) {
LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e); // LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e);
MinecraftServer.getExceptionManager().handleException(e); // MinecraftServer.getExceptionManager().handleException(e);
return AsyncUtils.VOID_FUTURE; // return AsyncUtils.VOID_FUTURE;
} // }
} // }
} // }
ChunkWriter writer = new ChunkWriter(SupportedVersion.Companion.getLatest()); // ChunkWriter writer = new ChunkWriter(SupportedVersion.Companion.getLatest());
save(chunk, writer); // save(chunk, writer);
try { // try {
LOGGER.debug("Attempt saving at {} {}", chunk.getChunkX(), chunk.getChunkZ()); // LOGGER.debug("Attempt saving at {} {}", chunk.getChunkX(), chunk.getChunkZ());
mcaFile.writeColumnData(writer.toNBT(), chunk.getChunkX(), chunk.getChunkZ()); // mcaFile.writeColumnData(writer.toNBT(), chunk.getChunkX(), chunk.getChunkZ());
} catch (IOException e) { // } catch (IOException e) {
LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e); // LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e);
MinecraftServer.getExceptionManager().handleException(e); // MinecraftServer.getExceptionManager().handleException(e);
return AsyncUtils.VOID_FUTURE; // return AsyncUtils.VOID_FUTURE;
} // }
return AsyncUtils.VOID_FUTURE; return AsyncUtils.VOID_FUTURE;
} }
private BlockState getBlockState(final Block block) { // private BlockState getBlockState(final Block block) {
return blockStateId2ObjectCacheTLS.get().computeIfAbsent(block.stateId(), _unused -> new BlockState(block.name(), block.properties())); // return blockStateId2ObjectCacheTLS.get().computeIfAbsent(block.stateId(), _unused -> new BlockState(block.name(), block.properties()));
} // }
//
private void save(Chunk chunk, ChunkWriter chunkWriter) { // private void save(Chunk chunk, ChunkWriter chunkWriter) {
final int minY = chunk.getMinSection() * Chunk.CHUNK_SECTION_SIZE; // final int minY = chunk.getMinSection() * Chunk.CHUNK_SECTION_SIZE;
final int maxY = chunk.getMaxSection() * Chunk.CHUNK_SECTION_SIZE - 1; // final int maxY = chunk.getMaxSection() * Chunk.CHUNK_SECTION_SIZE - 1;
chunkWriter.setYPos(minY); // chunkWriter.setYPos(minY);
List<NBTCompound> blockEntities = new ArrayList<>(); // List<NBTCompound> blockEntities = new ArrayList<>();
chunkWriter.setStatus(ChunkColumn.GenerationStatus.Full); // chunkWriter.setStatus(ChunkColumn.GenerationStatus.Full);
//
List<NBTCompound> sectionData = new ArrayList<>((maxY - minY + 1) / Chunk.CHUNK_SECTION_SIZE); // List<NBTCompound> sectionData = new ArrayList<>((maxY - minY + 1) / Chunk.CHUNK_SECTION_SIZE);
int[] palettedBiomes = new int[ChunkSection.Companion.getBiomeArraySize()]; // int[] palettedBiomes = new int[ChunkSection.Companion.getBiomeArraySize()];
int[] palettedBlockStates = new int[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SIZE_Z]; // int[] palettedBlockStates = new int[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SIZE_Z];
for (int sectionY = chunk.getMinSection(); sectionY < chunk.getMaxSection(); sectionY++) { // for (int sectionY = chunk.getMinSection(); sectionY < chunk.getMaxSection(); sectionY++) {
ChunkSectionWriter sectionWriter = new ChunkSectionWriter(SupportedVersion.Companion.getLatest(), (byte) sectionY); // ChunkSectionWriter sectionWriter = new ChunkSectionWriter(SupportedVersion.Companion.getLatest(), (byte) sectionY);
//
Section section = chunk.getSection(sectionY); // Section section = chunk.getSection(sectionY);
sectionWriter.setSkyLights(section.skyLight().array()); // sectionWriter.setSkyLights(section.skyLight().array());
sectionWriter.setBlockLights(section.blockLight().array()); // sectionWriter.setBlockLights(section.blockLight().array());
//
BiomePalette biomePalette = new BiomePalette(); // BiomePalette biomePalette = new BiomePalette();
BlockPalette blockPalette = new BlockPalette(); // BlockPalette blockPalette = new BlockPalette();
for (int sectionLocalY = 0; sectionLocalY < Chunk.CHUNK_SECTION_SIZE; sectionLocalY++) { // for (int sectionLocalY = 0; sectionLocalY < Chunk.CHUNK_SECTION_SIZE; sectionLocalY++) {
for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { // for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) { // for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
final int y = sectionLocalY + sectionY * Chunk.CHUNK_SECTION_SIZE; // final int y = sectionLocalY + sectionY * Chunk.CHUNK_SECTION_SIZE;
//
final int blockIndex = x + sectionLocalY * 16 * 16 + z * 16; // final int blockIndex = x + sectionLocalY * 16 * 16 + z * 16;
//
final Block block = chunk.getBlock(x, y, z); // final Block block = chunk.getBlock(x, y, z);
//
final BlockState hephaistosBlockState = getBlockState(block); // final BlockState hephaistosBlockState = getBlockState(block);
blockPalette.increaseReference(hephaistosBlockState); // blockPalette.increaseReference(hephaistosBlockState);
//
palettedBlockStates[blockIndex] = blockPalette.getPaletteIndex(hephaistosBlockState); // palettedBlockStates[blockIndex] = blockPalette.getPaletteIndex(hephaistosBlockState);
//
// biome are stored for 4x4x4 volumes, avoid unnecessary work // // biome are stored for 4x4x4 volumes, avoid unnecessary work
if (x % 4 == 0 && sectionLocalY % 4 == 0 && z % 4 == 0) { // if (x % 4 == 0 && sectionLocalY % 4 == 0 && z % 4 == 0) {
int biomeIndex = (x / 4) + (sectionLocalY / 4) * 4 * 4 + (z / 4) * 4; // int biomeIndex = (x / 4) + (sectionLocalY / 4) * 4 * 4 + (z / 4) * 4;
final Biome biome = chunk.getBiome(x, y, z); // final Biome biome = chunk.getBiome(x, y, z);
final String biomeName = biome.name(); // final String biomeName = biome.name();
//
biomePalette.increaseReference(biomeName); // biomePalette.increaseReference(biomeName);
palettedBiomes[biomeIndex] = biomePalette.getPaletteIndex(biomeName); // palettedBiomes[biomeIndex] = biomePalette.getPaletteIndex(biomeName);
} // }
//
// Block entities // // Block entities
final BlockHandler handler = block.handler(); // final BlockHandler handler = block.handler();
final NBTCompound originalNBT = block.nbt(); // final NBTCompound originalNBT = block.nbt();
if (originalNBT != null || handler != null) { // if (originalNBT != null || handler != null) {
MutableNBTCompound nbt = originalNBT != null ? // MutableNBTCompound nbt = originalNBT != null ?
originalNBT.toMutableCompound() : new MutableNBTCompound(); // originalNBT.toMutableCompound() : new MutableNBTCompound();
//
if (handler != null) { // if (handler != null) {
nbt.setString("id", handler.getNamespaceId().asString()); // nbt.setString("id", handler.getNamespaceId().asString());
} // }
nbt.setInt("x", x + Chunk.CHUNK_SIZE_X * chunk.getChunkX()); // nbt.setInt("x", x + Chunk.CHUNK_SIZE_X * chunk.getChunkX());
nbt.setInt("y", y); // nbt.setInt("y", y);
nbt.setInt("z", z + Chunk.CHUNK_SIZE_Z * chunk.getChunkZ()); // nbt.setInt("z", z + Chunk.CHUNK_SIZE_Z * chunk.getChunkZ());
nbt.setByte("keepPacked", (byte) 0); // nbt.setByte("keepPacked", (byte) 0);
blockEntities.add(nbt.toCompound()); // blockEntities.add(nbt.toCompound());
} // }
} // }
} // }
} // }
//
sectionWriter.setPalettedBiomes(biomePalette, palettedBiomes); // sectionWriter.setPalettedBiomes(biomePalette, palettedBiomes);
sectionWriter.setPalettedBlockStates(blockPalette, palettedBlockStates); // sectionWriter.setPalettedBlockStates(blockPalette, palettedBlockStates);
//
sectionData.add(sectionWriter.toNBT()); // sectionData.add(sectionWriter.toNBT());
} // }
//
chunkWriter.setSectionsData(NBT.List(NBTType.TAG_Compound, sectionData)); // chunkWriter.setSectionsData(NBT.List(NBTType.TAG_Compound, sectionData));
chunkWriter.setBlockEntityData(NBT.List(NBTType.TAG_Compound, blockEntities)); // chunkWriter.setBlockEntityData(NBT.List(NBTType.TAG_Compound, blockEntities));
} // }
//
/** // /**
* Unload a given chunk. Also unloads a region when no chunk from that region is loaded. // * Unload a given chunk. Also unloads a region when no chunk from that region is loaded.
* // *
* @param chunk the chunk to unload // * @param chunk the chunk to unload
*/ // */
@Override // @Override
public void unloadChunk(Chunk chunk) { // public void unloadChunk(Chunk chunk) {
final int regionX = CoordinatesKt.chunkToRegion(chunk.chunkX); // final int regionX = CoordinatesKt.chunkToRegion(chunk.chunkX);
final int regionZ = CoordinatesKt.chunkToRegion(chunk.chunkZ); // final int regionZ = CoordinatesKt.chunkToRegion(chunk.chunkZ);
//
final IntIntImmutablePair regionKey = new IntIntImmutablePair(regionX, regionZ); // final IntIntImmutablePair regionKey = new IntIntImmutablePair(regionX, regionZ);
synchronized (perRegionLoadedChunks) { // synchronized (perRegionLoadedChunks) {
Set<IntIntImmutablePair> chunks = perRegionLoadedChunks.get(regionKey); // Set<IntIntImmutablePair> chunks = perRegionLoadedChunks.get(regionKey);
if (chunks != null) { // if null, trying to unload a chunk from a region that was not created by the AnvilLoader // if (chunks != null) { // if null, trying to unload a chunk from a region that was not created by the AnvilLoader
// don't check return value, trying to unload a chunk not created by the AnvilLoader is valid // // don't check return value, trying to unload a chunk not created by the AnvilLoader is valid
chunks.remove(new IntIntImmutablePair(chunk.chunkX, chunk.chunkZ)); // chunks.remove(new IntIntImmutablePair(chunk.chunkX, chunk.chunkZ));
//
if (chunks.isEmpty()) { // if (chunks.isEmpty()) {
perRegionLoadedChunks.remove(regionKey); // perRegionLoadedChunks.remove(regionKey);
RegionFile regionFile = alreadyLoaded.remove(RegionFile.Companion.createFileName(regionX, regionZ)); // RegionFile regionFile = alreadyLoaded.remove(RegionFile.Companion.createFileName(regionX, regionZ));
if (regionFile != null) { // if (regionFile != null) {
try { // try {
regionFile.close(); // regionFile.close();
} catch (IOException e) { // } catch (IOException e) {
MinecraftServer.getExceptionManager().handleException(e); // MinecraftServer.getExceptionManager().handleException(e);
} // }
} // }
} // }
} // }
} // }
} // }
@Override @Override
public boolean supportsParallelLoading() { public boolean supportsParallelLoading() {

View File

@ -2,6 +2,7 @@ package net.minestom.server.instance;
import com.extollit.gaming.ai.path.model.ColumnarOcclusionFieldList; import com.extollit.gaming.ai.path.model.ColumnarOcclusionFieldList;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
@ -27,8 +28,6 @@ import net.minestom.server.world.biomes.Biome;
import net.minestom.server.world.biomes.BiomeManager; import net.minestom.server.world.biomes.BiomeManager;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -225,7 +224,7 @@ public class DynamicChunk extends Chunk {
} }
private @NotNull ChunkDataPacket createChunkPacket() { private @NotNull ChunkDataPacket createChunkPacket() {
final NBTCompound heightmapsNBT = computeHeightmap(); final CompoundBinaryTag heightmapsNBT = computeHeightmap();
// Data // Data
final byte[] data; final byte[] data;
@ -242,7 +241,7 @@ public class DynamicChunk extends Chunk {
); );
} }
protected NBTCompound computeHeightmap() { protected CompoundBinaryTag computeHeightmap() {
// TODO: don't hardcode heightmaps // TODO: don't hardcode heightmaps
// Heightmap // Heightmap
int dimensionHeight = getInstance().getDimensionType().getHeight(); int dimensionHeight = getInstance().getDimensionType().getHeight();
@ -255,9 +254,10 @@ public class DynamicChunk extends Chunk {
} }
} }
final int bitsForHeight = MathUtils.bitsToRepresent(dimensionHeight); final int bitsForHeight = MathUtils.bitsToRepresent(dimensionHeight);
return NBT.Compound(Map.of( return CompoundBinaryTag.builder()
"MOTION_BLOCKING", NBT.LongArray(encodeBlocks(motionBlocking, bitsForHeight)), .putLongArray("MOTION_BLOCKING", encodeBlocks(motionBlocking, bitsForHeight))
"WORLD_SURFACE", NBT.LongArray(encodeBlocks(worldSurface, bitsForHeight)))); .putLongArray("WORLD_SURFACE", encodeBlocks(worldSurface, bitsForHeight))
.build();
} }
@NotNull UpdateLightPacket createLightPacket() { @NotNull UpdateLightPacket createLightPacket() {

View File

@ -1,6 +1,6 @@
package net.minestom.server.instance; package net.minestom.server.instance;
import org.jglrxavpok.hephaistos.nbt.NBTCompound; import net.kyori.adventure.nbt.CompoundBinaryTag;
@FunctionalInterface @FunctionalInterface
public interface ExplosionSupplier { public interface ExplosionSupplier {
@ -12,9 +12,9 @@ public interface ExplosionSupplier {
* @param centerY center Y of the explosion * @param centerY center Y of the explosion
* @param centerZ center Z of the explosion * @param centerZ center Z of the explosion
* @param strength strength of the explosion * @param strength strength of the explosion
* @param additionalData data passed via {@link Instance#explode(float, float, float, float, NBTCompound)} )}. Can be null * @param additionalData data passed via {@link Instance#explode(float, float, float, float, CompoundBinaryTag)} )}. Can be null
* @return Explosion object representing the algorithm to use * @return Explosion object representing the algorithm to use
*/ */
Explosion createExplosion(float centerX, float centerY, float centerZ, float strength, NBTCompound additionalData); Explosion createExplosion(float centerX, float centerY, float centerZ, float strength, CompoundBinaryTag additionalData);
} }

View File

@ -2,6 +2,7 @@ package net.minestom.server.instance;
import it.unimi.dsi.fastutil.objects.ObjectArraySet; import it.unimi.dsi.fastutil.objects.ObjectArraySet;
import net.kyori.adventure.identity.Identity; import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.pointer.Pointers; import net.kyori.adventure.pointer.Pointers;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.ServerProcess; import net.minestom.server.ServerProcess;
@ -45,7 +46,6 @@ import net.minestom.server.world.DimensionType;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.time.Duration; import java.time.Duration;
import java.util.*; import java.util.*;
@ -792,7 +792,7 @@ public abstract class Instance implements Block.Getter, Block.Setter,
* @param additionalData data to pass to the explosion supplier * @param additionalData data to pass to the explosion supplier
* @throws IllegalStateException If no {@link ExplosionSupplier} was supplied * @throws IllegalStateException If no {@link ExplosionSupplier} was supplied
*/ */
public void explode(float centerX, float centerY, float centerZ, float strength, @Nullable NBTCompound additionalData) { public void explode(float centerX, float centerY, float centerZ, float strength, @Nullable CompoundBinaryTag additionalData) {
final ExplosionSupplier explosionSupplier = getExplosionSupplier(); final ExplosionSupplier explosionSupplier = getExplosionSupplier();
Check.stateCondition(explosionSupplier == null, "Tried to create an explosion with no explosion supplier"); Check.stateCondition(explosionSupplier == null, "Tried to create an explosion with no explosion supplier");
final Explosion explosion = explosionSupplier.createExplosion(centerX, centerY, centerZ, strength, additionalData); final Explosion explosion = explosionSupplier.createExplosion(centerX, centerY, centerZ, strength, additionalData);

View File

@ -1,6 +1,7 @@
package net.minestom.server.instance; package net.minestom.server.instance;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
@ -32,7 +33,6 @@ import net.minestom.server.world.DimensionType;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import space.vectrix.flare.fastutil.Long2ObjectSyncMap; import space.vectrix.flare.fastutil.Long2ObjectSyncMap;
@ -186,7 +186,7 @@ public class InstanceContainer extends Instance {
chunk.sendPacketToViewers(new BlockChangePacket(blockPosition, block.stateId())); chunk.sendPacketToViewers(new BlockChangePacket(blockPosition, block.stateId()));
var registry = block.registry(); var registry = block.registry();
if (registry.isBlockEntity()) { if (registry.isBlockEntity()) {
final NBTCompound data = BlockUtils.extractClientNbt(block); final CompoundBinaryTag data = BlockUtils.extractClientNbt(block);
chunk.sendPacketToViewers(new BlockEntityDataPacket(blockPosition, registry.blockEntityId(), data)); chunk.sendPacketToViewers(new BlockEntityDataPacket(blockPosition, registry.blockEntityId(), data));
} }
} }

View File

@ -1,5 +1,7 @@
package net.minestom.server.instance; package net.minestom.server.instance;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.LongArrayBinaryTag;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.ServerFlag; import net.minestom.server.ServerFlag;
import net.minestom.server.collision.Shape; import net.minestom.server.collision.Shape;
@ -16,8 +18,6 @@ import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.chunk.ChunkUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -202,14 +202,17 @@ public class LightingChunk extends DynamicChunk {
} }
@Override @Override
protected NBTCompound computeHeightmap() { protected CompoundBinaryTag computeHeightmap() {
// Heightmap // Heightmap
int[] heightmap = getHeightmap(); int[] heightmap = getHeightmap();
int dimensionHeight = getInstance().getDimensionType().getHeight(); int dimensionHeight = getInstance().getDimensionType().getHeight();
final int bitsForHeight = MathUtils.bitsToRepresent(dimensionHeight); final int bitsForHeight = MathUtils.bitsToRepresent(dimensionHeight);
return NBT.Compound(Map.of(
"MOTION_BLOCKING", NBT.LongArray(encodeBlocks(heightmap, bitsForHeight)), LongArrayBinaryTag encoded = LongArrayBinaryTag.longArrayBinaryTag(encodeBlocks(heightmap, bitsForHeight));
"WORLD_SURFACE", NBT.LongArray(encodeBlocks(heightmap, bitsForHeight)))); return CompoundBinaryTag.builder()
.put("MOTION_BLOCKING", encoded)
.put("WORLD_SURFACE", encoded)
.build();
} }
// Lazy compute heightmap // Lazy compute heightmap

View File

@ -1,15 +1,15 @@
package net.minestom.server.instance.block; package net.minestom.server.instance.block;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
import net.minestom.server.instance.batch.Batch; import net.minestom.server.instance.batch.Batch;
import net.minestom.server.registry.StaticProtocolObject;
import net.minestom.server.registry.Registry; import net.minestom.server.registry.Registry;
import net.minestom.server.registry.StaticProtocolObject;
import net.minestom.server.tag.Tag; import net.minestom.server.tag.Tag;
import net.minestom.server.tag.TagReadable; import net.minestom.server.tag.TagReadable;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.*; import org.jetbrains.annotations.*;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
@ -67,7 +67,7 @@ public sealed interface Block extends StaticProtocolObject, TagReadable, Blocks
* @return a new block with different nbt * @return a new block with different nbt
*/ */
@Contract(pure = true) @Contract(pure = true)
@NotNull Block withNbt(@Nullable NBTCompound compound); @NotNull Block withNbt(@Nullable CompoundBinaryTag compound);
/** /**
* Creates a new block with the specified {@link BlockHandler handler}. * Creates a new block with the specified {@link BlockHandler handler}.
@ -86,7 +86,7 @@ public sealed interface Block extends StaticProtocolObject, TagReadable, Blocks
* @return the block nbt, null if not present * @return the block nbt, null if not present
*/ */
@Contract(pure = true) @Contract(pure = true)
@Nullable NBTCompound nbt(); @Nullable CompoundBinaryTag nbt();
@Contract(pure = true) @Contract(pure = true)
default boolean hasNbt() { default boolean hasNbt() {

View File

@ -4,6 +4,7 @@ import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.registry.Registry; import net.minestom.server.registry.Registry;
import net.minestom.server.tag.Tag; import net.minestom.server.tag.Tag;
import net.minestom.server.utils.ArrayUtils; import net.minestom.server.utils.ArrayUtils;
@ -14,8 +15,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability; import org.jetbrains.annotations.UnknownNullability;
import org.jetbrains.annotations.Unmodifiable; import org.jetbrains.annotations.Unmodifiable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import java.time.Duration; import java.time.Duration;
import java.util.*; import java.util.*;
@ -23,7 +22,7 @@ import java.util.function.Function;
record BlockImpl(@NotNull Registry.BlockEntry registry, record BlockImpl(@NotNull Registry.BlockEntry registry,
byte @NotNull [] propertiesArray, byte @NotNull [] propertiesArray,
@Nullable NBTCompound nbt, @Nullable CompoundBinaryTag nbt,
@Nullable BlockHandler handler) implements Block { @Nullable BlockHandler handler) implements Block {
// Block state -> block object // Block state -> block object
private static final ObjectArray<Block> BLOCK_STATE_MAP = ObjectArray.singleThread(); private static final ObjectArray<Block> BLOCK_STATE_MAP = ObjectArray.singleThread();
@ -86,7 +85,7 @@ record BlockImpl(@NotNull Registry.BlockEntry registry,
final int defaultState = properties.getInt("defaultStateId"); final int defaultState = properties.getInt("defaultStateId");
return getState(defaultState); return getState(defaultState);
}); });
private static final Cache<NBTCompound, NBTCompound> NBT_CACHE = Caffeine.newBuilder() private static final Cache<CompoundBinaryTag, CompoundBinaryTag> NBT_CACHE = Caffeine.newBuilder()
.expireAfterWrite(Duration.ofMinutes(5)) .expireAfterWrite(Duration.ofMinutes(5))
.weakValues() .weakValues()
.build(); .build();
@ -144,14 +143,16 @@ record BlockImpl(@NotNull Registry.BlockEntry registry,
@Override @Override
public @NotNull <T> Block withTag(@NotNull Tag<T> tag, @Nullable T value) { public @NotNull <T> Block withTag(@NotNull Tag<T> tag, @Nullable T value) {
var temporaryNbt = new MutableNBTCompound(Objects.requireNonNullElse(nbt, NBTCompound.EMPTY)); var builder = CompoundBinaryTag.builder();
tag.write(temporaryNbt, value); if (nbt != null) builder.put(nbt);
final var finalNbt = temporaryNbt.getSize() > 0 ? NBT_CACHE.get(temporaryNbt.toCompound(), Function.identity()) : null; tag.write(builder, value);
var temporaryNbt = builder.build();
final var finalNbt = temporaryNbt.size() > 0 ? NBT_CACHE.get(temporaryNbt, Function.identity()) : null;
return new BlockImpl(registry, propertiesArray, finalNbt, handler); return new BlockImpl(registry, propertiesArray, finalNbt, handler);
} }
@Override @Override
public @NotNull Block withNbt(@Nullable NBTCompound compound) { public @NotNull Block withNbt(@Nullable CompoundBinaryTag compound) {
return new BlockImpl(registry, propertiesArray, compound, handler); return new BlockImpl(registry, propertiesArray, compound, handler);
} }
@ -183,7 +184,7 @@ record BlockImpl(@NotNull Registry.BlockEntry registry,
@Override @Override
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) { public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
return tag.read(Objects.requireNonNullElse(nbt, NBTCompound.EMPTY)); return tag.read(Objects.requireNonNullElse(nbt, CompoundBinaryTag.empty()));
} }
private Map<PropertiesHolder, BlockImpl> possibleProperties() { private Map<PropertiesHolder, BlockImpl> possibleProperties() {

View File

@ -1,5 +1,6 @@
package net.minestom.server.item; package net.minestom.server.item;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.minestom.server.item.attribute.ItemAttribute; import net.minestom.server.item.attribute.ItemAttribute;
@ -12,7 +13,6 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability; import org.jetbrains.annotations.UnknownNullability;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -26,7 +26,7 @@ public sealed interface ItemMeta extends TagReadable, NetworkBuffer.Writer
@Contract(value = "_, -> new", pure = true) @Contract(value = "_, -> new", pure = true)
@NotNull ItemMeta with(@NotNull Consumer<@NotNull Builder> builderConsumer); @NotNull ItemMeta with(@NotNull Consumer<@NotNull Builder> builderConsumer);
@NotNull NBTCompound toNBT(); @NotNull CompoundBinaryTag toNBT();
@NotNull String toSNBT(); @NotNull String toSNBT();

View File

@ -1,16 +1,17 @@
package net.minestom.server.item; package net.minestom.server.item;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.TagStringIO;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.tag.Tag; import net.minestom.server.tag.Tag;
import net.minestom.server.tag.TagHandler; import net.minestom.server.tag.TagHandler;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.UnknownNullability; import org.jetbrains.annotations.UnknownNullability;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.io.IOException;
import java.util.Objects; import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
import static net.minestom.server.network.NetworkBuffer.BYTE;
import static net.minestom.server.network.NetworkBuffer.NBT; import static net.minestom.server.network.NetworkBuffer.NBT;
record ItemMetaImpl(TagHandler tagHandler) implements ItemMeta { record ItemMetaImpl(TagHandler tagHandler) implements ItemMeta {
@ -29,23 +30,22 @@ record ItemMetaImpl(TagHandler tagHandler) implements ItemMeta {
} }
@Override @Override
public @NotNull NBTCompound toNBT() { public @NotNull CompoundBinaryTag toNBT() {
return tagHandler.asCompound(); return tagHandler.asCompound();
} }
@Override @Override
public @NotNull String toSNBT() { public @NotNull String toSNBT() {
return toNBT().toSNBT(); try {
return TagStringIO.get().asString(toNBT());
} catch (IOException e) {
throw new RuntimeException("Failed to convert to SNBT", e);
}
} }
@Override @Override
public void write(@NotNull NetworkBuffer writer) { public void write(@NotNull NetworkBuffer writer) {
final NBTCompound nbt = toNBT(); writer.write(NBT, toNBT());
if (nbt.isEmpty()) {
writer.write(BYTE, (byte) 0);
return;
}
writer.write(NBT, nbt);
} }
@Override @Override

View File

@ -1,5 +1,6 @@
package net.minestom.server.item; package net.minestom.server.item;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.api.BinaryTagHolder; import net.kyori.adventure.nbt.api.BinaryTagHolder;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.event.HoverEvent;
@ -11,8 +12,8 @@ import net.minestom.server.tag.TagReadable;
import net.minestom.server.tag.TagWritable; import net.minestom.server.tag.TagWritable;
import net.minestom.server.utils.validate.Check; import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.*; import org.jetbrains.annotations.*;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.IntUnaryOperator; import java.util.function.IntUnaryOperator;
@ -47,13 +48,13 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
} }
@Contract(value = "_, _, _ -> new", pure = true) @Contract(value = "_, _, _ -> new", pure = true)
static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable NBTCompound nbtCompound, int amount) { static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable CompoundBinaryTag nbtCompound, int amount) {
if (nbtCompound == null) return of(material, amount); if (nbtCompound == null) return of(material, amount);
return builder(material).amount(amount).meta(nbtCompound).build(); return builder(material).amount(amount).meta(nbtCompound).build();
} }
@Contract(value = "_, _ -> new", pure = true) @Contract(value = "_, _ -> new", pure = true)
static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable NBTCompound nbtCompound) { static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable CompoundBinaryTag nbtCompound) {
return fromNBT(material, nbtCompound, 1); return fromNBT(material, nbtCompound, 1);
} }
@ -63,7 +64,7 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
* @param nbtCompound The nbt representation of the item * @param nbtCompound The nbt representation of the item
*/ */
@ApiStatus.Experimental @ApiStatus.Experimental
static @NotNull ItemStack fromItemNBT(@NotNull NBTCompound nbtCompound) { static @NotNull ItemStack fromItemNBT(@NotNull CompoundBinaryTag nbtCompound) {
String id = nbtCompound.getString("id"); String id = nbtCompound.getString("id");
Check.notNull(id, "Item NBT must contain an id field."); Check.notNull(id, "Item NBT must contain an id field.");
Material material = Material.fromNamespaceId(id); Material material = Material.fromNamespaceId(id);
@ -71,7 +72,7 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
Byte amount = nbtCompound.getByte("Count"); Byte amount = nbtCompound.getByte("Count");
if (amount == null) amount = 1; if (amount == null) amount = 1;
final NBTCompound tag = nbtCompound.getCompound("tag"); final CompoundBinaryTag tag = nbtCompound.getCompound("tag");
return tag != null ? fromNBT(material, tag, amount) : of(material, amount); return tag != null ? fromNBT(material, tag, amount) : of(material, amount);
} }
@ -168,8 +169,13 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
@Override @Override
default @NotNull HoverEvent<HoverEvent.ShowItem> asHoverEvent(@NotNull UnaryOperator<HoverEvent.ShowItem> op) { default @NotNull HoverEvent<HoverEvent.ShowItem> asHoverEvent(@NotNull UnaryOperator<HoverEvent.ShowItem> op) {
final BinaryTagHolder tagHolder = BinaryTagHolder.encode(meta().toNBT(), MinestomAdventure.NBT_CODEC); try {
return HoverEvent.showItem(op.apply(HoverEvent.ShowItem.showItem(material(), amount(), tagHolder))); final BinaryTagHolder tagHolder = BinaryTagHolder.encode(meta().toNBT(), MinestomAdventure.NBT_CODEC);
return HoverEvent.showItem(op.apply(HoverEvent.ShowItem.showItem(material(), amount(), tagHolder)));
} catch (IOException e) {
//todo(matt): revisit,
throw new RuntimeException(e);
}
} }
/** /**
@ -178,7 +184,7 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
* @return The nbt representation of the item * @return The nbt representation of the item
*/ */
@ApiStatus.Experimental @ApiStatus.Experimental
@NotNull NBTCompound toItemNBT(); @NotNull CompoundBinaryTag toItemNBT();
@Deprecated @Deprecated
@ -208,7 +214,7 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
@NotNull Builder meta(@NotNull TagHandler tagHandler); @NotNull Builder meta(@NotNull TagHandler tagHandler);
@Contract(value = "_ -> this") @Contract(value = "_ -> this")
@NotNull Builder meta(@NotNull NBTCompound compound); @NotNull Builder meta(@NotNull CompoundBinaryTag compound);
@Contract(value = "_ -> this") @Contract(value = "_ -> this")
@NotNull Builder meta(@NotNull ItemMeta itemMeta); @NotNull Builder meta(@NotNull ItemMeta itemMeta);

View File

@ -1,5 +1,6 @@
package net.minestom.server.item; package net.minestom.server.item;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.ServerFlag; import net.minestom.server.ServerFlag;
import net.minestom.server.item.rule.VanillaStackingRule; import net.minestom.server.item.rule.VanillaStackingRule;
import net.minestom.server.tag.Tag; import net.minestom.server.tag.Tag;
@ -7,12 +8,7 @@ import net.minestom.server.tag.TagHandler;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTByte;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTString;
import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
record ItemStackImpl(Material material, int amount, ItemMetaImpl meta) implements ItemStack { record ItemStackImpl(Material material, int amount, ItemMetaImpl meta) implements ItemStack {
@ -89,12 +85,13 @@ record ItemStackImpl(Material material, int amount, ItemMetaImpl meta) implement
} }
@Override @Override
public @NotNull NBTCompound toItemNBT() { public @NotNull CompoundBinaryTag toItemNBT() {
final NBTString material = NBT.String(material().name()); CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
final NBTByte amount = NBT.Byte(amount()); .putString("id", material.name())
final NBTCompound nbt = meta().toNBT(); .putByte("Count", (byte) amount);
if (nbt.isEmpty()) return NBT.Compound(Map.of("id", material, "Count", amount)); CompoundBinaryTag nbt = meta.toNBT();
return NBT.Compound(Map.of("id", material, "Count", amount, "tag", nbt)); if (nbt.size() > 0) builder.put("tag", nbt);
return builder.build();
} }
@Contract(value = "-> new", pure = true) @Contract(value = "-> new", pure = true)
@ -129,7 +126,7 @@ record ItemStackImpl(Material material, int amount, ItemMetaImpl meta) implement
} }
@Override @Override
public ItemStack.@NotNull Builder meta(@NotNull NBTCompound compound) { public ItemStack.@NotNull Builder meta(@NotNull CompoundBinaryTag compound) {
return metaBuilder(new ItemMetaImpl.Builder(TagHandler.fromCompound(compound))); return metaBuilder(new ItemMetaImpl.Builder(TagHandler.fromCompound(compound)));
} }

View File

@ -1,20 +1,19 @@
package net.minestom.server.item.armor; package net.minestom.server.item.armor;
import net.kyori.adventure.nbt.BinaryTagTypes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.ListBinaryTag;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
public class TrimManager { public class TrimManager {
private final Set<TrimMaterial> trimMaterials; private final Set<TrimMaterial> trimMaterials;
private final Set<TrimPattern> trimPatterns; private final Set<TrimPattern> trimPatterns;
private NBTCompound trimMaterialCache = null; private CompoundBinaryTag trimMaterialCache = null;
private NBTCompound trimPatternCache = null; private CompoundBinaryTag trimPatternCache = null;
public TrimManager() { public TrimManager() {
this.trimMaterials = new HashSet<>(); this.trimMaterials = new HashSet<>();
@ -30,38 +29,28 @@ public class TrimManager {
} }
public NBTCompound getTrimMaterialNBT() { public CompoundBinaryTag getTrimMaterialNBT() {
if (trimMaterialCache == null) { if (trimMaterialCache == null) {
var trimMaterials = this.trimMaterials.stream() ListBinaryTag.Builder<CompoundBinaryTag> entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
.map((trimMaterial) -> NBT.Compound(Map.of( for (TrimMaterial trimMaterial : this.trimMaterials)
"id", NBT.Int(trimMaterial.id()), entries.add(trimMaterial.asNBT());
"name", NBT.String(trimMaterial.name()), trimMaterialCache = CompoundBinaryTag.builder()
"element", trimMaterial.asNBT() .putString("type", "minecraft:trim_material")
))) .put("value", entries.build())
.toList(); .build();
trimMaterialCache = NBT.Compound(Map.of(
"type", NBT.String("minecraft:trim_material"),
"value", NBT.List(NBTType.TAG_Compound, trimMaterials)
));
} }
return trimMaterialCache; return trimMaterialCache;
} }
public NBTCompound getTrimPatternNBT() { public CompoundBinaryTag getTrimPatternNBT() {
if (trimPatternCache == null) { if (trimPatternCache == null) {
var trimPatterns = this.trimPatterns.stream() ListBinaryTag.Builder<CompoundBinaryTag> entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
.map((trimPattern) -> NBT.Compound(Map.of( for (TrimPattern trimPattern : this.trimPatterns)
"id", NBT.Int(trimPattern.id()), entries.add(trimPattern.asNBT());
"name", NBT.String(trimPattern.name()), trimPatternCache = CompoundBinaryTag.builder()
"element", trimPattern.asNBT() .putString("type", "minecraft:trim_pattern")
))) .put("value", entries.build())
.toList(); .build();
trimPatternCache = NBT.Compound(Map.of(
"type", NBT.String("minecraft:trim_pattern"),
"value", NBT.List(NBTType.TAG_Compound, trimPatterns)
));
} }
return trimPatternCache; return trimPatternCache;

View File

@ -1,13 +1,13 @@
package net.minestom.server.item.armor; package net.minestom.server.item.armor;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.registry.StaticProtocolObject;
import net.minestom.server.registry.Registry; import net.minestom.server.registry.Registry;
import net.minestom.server.registry.StaticProtocolObject;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
@ -84,6 +84,6 @@ public interface TrimMaterial extends StaticProtocolObject {
return registry().description(); return registry().description();
} }
NBTCompound asNBT(); CompoundBinaryTag asNBT();
} }

View File

@ -1,9 +1,9 @@
package net.minestom.server.item.armor; package net.minestom.server.item.armor;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.StringBinaryTag;
import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer; import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer;
import net.minestom.server.registry.Registry; import net.minestom.server.registry.Registry;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
@ -31,19 +31,15 @@ record TrimMaterialImpl(Registry.TrimMaterialEntry registry, int id) implements
return CONTAINER.values(); return CONTAINER.values();
} }
public NBTCompound asNBT() { public CompoundBinaryTag asNBT() {
return NBT.Compound(nbt -> { return CompoundBinaryTag.builder()
nbt.setString("asset_name", assetName()); .putString("asset_name", assetName())
nbt.setString("ingredient", ingredient().namespace().asString()); .putString("ingredient", ingredient().namespace().asString())
nbt.setFloat("item_model_index", itemModelIndex()); .putFloat("item_model_index", itemModelIndex())
nbt.set("override_armor_materials", NBT.Compound(overrideArmorMaterials().entrySet().stream() .put("override_armor_materials", CompoundBinaryTag.from(overrideArmorMaterials().entrySet().stream()
.collect(Collectors.toMap( .collect(Collectors.toMap(Map.Entry::getKey, entry -> StringBinaryTag.stringBinaryTag(entry.getValue())))))
Map.Entry::getKey, .put("description", NbtComponentSerializer.nbt().serialize(description()))
entry -> NBT.String(entry.getValue()) .build();
))
));
nbt.set("description", NbtComponentSerializer.nbt().serialize(description()));
});
} }
} }

View File

@ -1,13 +1,13 @@
package net.minestom.server.item.armor; package net.minestom.server.item.armor;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.registry.StaticProtocolObject;
import net.minestom.server.registry.Registry; import net.minestom.server.registry.Registry;
import net.minestom.server.registry.StaticProtocolObject;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Collection; import java.util.Collection;
@ -61,6 +61,6 @@ public interface TrimPattern extends StaticProtocolObject {
return registry().decal(); return registry().decal();
} }
NBTCompound asNBT(); CompoundBinaryTag asNBT();
} }

View File

@ -1,9 +1,8 @@
package net.minestom.server.item.armor; package net.minestom.server.item.armor;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer; import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer;
import net.minestom.server.registry.Registry; import net.minestom.server.registry.Registry;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -29,13 +28,13 @@ record TrimPatternImpl(Registry.TrimPatternEntry registry, int id) implements Tr
return CONTAINER.values(); return CONTAINER.values();
} }
public NBTCompound asNBT() { public CompoundBinaryTag asNBT() {
return NBT.Compound(nbt -> { return CompoundBinaryTag.builder()
nbt.setString("asset_id", assetID().asString()); .putString("asset_id", assetID().asString())
nbt.setString("template_item", template().namespace().asString()); .putString("template_item", template().namespace().asString())
nbt.set("description", NbtComponentSerializer.nbt().serialize(description())); .put("description", NbtComponentSerializer.nbt().serialize(description()))
nbt.setByte("decal", (byte) (decal() ? 1 : 0)); .putBoolean("decal", decal())
}); .build();
} }
} }

View File

@ -1,14 +1,11 @@
package net.minestom.server.item.firework; package net.minestom.server.item.firework;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.color.Color; import net.minestom.server.color.Color;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTIntArray;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
public record FireworkEffect(boolean flicker, boolean trail, public record FireworkEffect(boolean flicker, boolean trail,
@NotNull FireworkEffectType type, @NotNull FireworkEffectType type,
@ -25,36 +22,34 @@ public record FireworkEffect(boolean flicker, boolean trail,
* @param compound The NBT connection, which should be a fireworks effect. * @param compound The NBT connection, which should be a fireworks effect.
* @return A new created firework effect. * @return A new created firework effect.
*/ */
public static @NotNull FireworkEffect fromCompound(@NotNull NBTCompound compound) { public static @NotNull FireworkEffect fromCompound(@NotNull CompoundBinaryTag compound) {
List<Color> primaryColor = new ArrayList<>(); List<Color> primaryColor = new ArrayList<>();
List<Color> secondaryColor = new ArrayList<>(); List<Color> secondaryColor = new ArrayList<>();
if (compound.get("Colors") instanceof NBTIntArray colors) { for (int rgb : compound.getIntArray("Colors"))
for (int rgb : colors) primaryColor.add(new Color(rgb)); primaryColor.add(new Color(rgb));
} for (int rgb : compound.getIntArray("FadeColors"))
if (compound.get("FadeColors") instanceof NBTIntArray fadeColors) { secondaryColor.add(new Color(rgb));
for (int rgb : fadeColors) secondaryColor.add(new Color(rgb));
}
boolean flicker = compound.containsKey("Flicker") && compound.getBoolean("Flicker"); boolean flicker = compound.getBoolean("Flicker");
boolean trail = compound.containsKey("Trail") && compound.getBoolean("Trail"); boolean trail = compound.getBoolean("Trail");
FireworkEffectType type = compound.containsKey("Type") ? FireworkEffectType type = FireworkEffectType.byId(compound.getByte("Type"));
FireworkEffectType.byId(compound.getAsByte("Type")) : FireworkEffectType.SMALL_BALL;
return new FireworkEffect(flicker, trail, type, primaryColor, secondaryColor); return new FireworkEffect(flicker, trail, type, primaryColor, secondaryColor);
} }
/** /**
* Retrieves the {@link FireworkEffect} as a {@link NBTCompound}. * Retrieves the {@link FireworkEffect} as a {@link CompoundBinaryTag}.
* *
* @return The firework effect as a nbt compound. * @return The firework effect as a nbt compound.
*/ */
public @NotNull NBTCompound asCompound() { public @NotNull CompoundBinaryTag asCompound() {
return NBT.Compound(Map.of( return CompoundBinaryTag.builder()
"Flicker", NBT.Boolean(flicker), .putBoolean("Flicker", flicker)
"Trail", NBT.Boolean(trail), .putBoolean("Trail", trail)
"Type", NBT.Byte(type.getType()), .putByte("Type", (byte) type.getType())
"Colors", NBT.IntArray(colors.stream().mapToInt(Color::asRGB).toArray()), .putIntArray("Colors", colors.stream().mapToInt(Color::asRGB).toArray())
"FadeColors", NBT.IntArray(fadeColors.stream().mapToInt(Color::asRGB).toArray()))); .putIntArray("FadeColors", fadeColors.stream().mapToInt(Color::asRGB).toArray())
.build();
} }
} }

View File

@ -1,32 +1,30 @@
package net.minestom.server.item.metadata; package net.minestom.server.item.metadata;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.BinaryTagTypes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.ListBinaryTag;
import net.minestom.server.entity.PlayerSkin; import net.minestom.server.entity.PlayerSkin;
import net.minestom.server.item.ItemMetaView; import net.minestom.server.item.ItemMetaView;
import net.minestom.server.tag.*; import net.minestom.server.tag.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability; import org.jetbrains.annotations.UnknownNullability;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
public record PlayerHeadMeta(TagReadable readable) implements ItemMetaView<PlayerHeadMeta.Builder> { public record PlayerHeadMeta(TagReadable readable) implements ItemMetaView<PlayerHeadMeta.Builder> {
public static final Tag<UUID> SKULL_OWNER = Tag.UUID("Id").path("SkullOwner"); public static final Tag<UUID> SKULL_OWNER = Tag.UUID("Id").path("SkullOwner");
public static final Tag<PlayerSkin> SKIN = Tag.Structure("Properties", new TagSerializer<PlayerSkin>() { public static final Tag<PlayerSkin> SKIN = Tag.Structure("Properties", new TagSerializer<PlayerSkin>() {
private static final Tag<NBT> TEXTURES = Tag.NBT("textures"); private static final Tag<BinaryTag> TEXTURES = Tag.NBT("textures");
@Override @Override
public @Nullable PlayerSkin read(@NotNull TagReadable reader) { public @Nullable PlayerSkin read(@NotNull TagReadable reader) {
final NBT result = reader.getTag(TEXTURES); final BinaryTag result = reader.getTag(TEXTURES);
if (!(result instanceof NBTList)) return null; if (!(result instanceof ListBinaryTag textures)) return null;
final NBTList<NBTCompound> textures = (NBTList<NBTCompound>) result; final CompoundBinaryTag texture = textures.getCompound(0);
final NBTCompound texture = textures.get(0);
final String value = texture.getString("Value"); final String value = texture.getString("Value");
final String signature = texture.getString("Signature"); final String signature = texture.getString("Signature");
return new PlayerSkin(value, signature); return new PlayerSkin(value, signature);
@ -36,9 +34,9 @@ public record PlayerHeadMeta(TagReadable readable) implements ItemMetaView<Playe
public void write(@NotNull TagWritable writer, @NotNull PlayerSkin playerSkin) { public void write(@NotNull TagWritable writer, @NotNull PlayerSkin playerSkin) {
final String value = Objects.requireNonNullElse(playerSkin.textures(), ""); final String value = Objects.requireNonNullElse(playerSkin.textures(), "");
final String signature = Objects.requireNonNullElse(playerSkin.signature(), ""); final String signature = Objects.requireNonNullElse(playerSkin.signature(), "");
NBTList<NBTCompound> textures = new NBTList<>(NBTType.TAG_Compound, writer.setTag(TEXTURES, ListBinaryTag.listBinaryTag(BinaryTagTypes.COMPOUND, List.of(
List.of(NBT.Compound(Map.of("Value", NBT.String(value), "Signature", NBT.String(signature))))); CompoundBinaryTag.builder().putString("Value", value).putString("Signature", signature).build()
writer.setTag(TEXTURES, textures); )));
} }
}).path("SkullOwner"); }).path("SkullOwner");

View File

@ -1,5 +1,6 @@
package net.minestom.server.listener; package net.minestom.server.listener;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode; import net.minestom.server.entity.GameMode;
@ -22,7 +23,6 @@ import net.minestom.server.network.packet.server.play.AcknowledgeBlockChangePack
import net.minestom.server.network.packet.server.play.BlockEntityDataPacket; import net.minestom.server.network.packet.server.play.BlockEntityDataPacket;
import net.minestom.server.utils.block.BlockUtils; import net.minestom.server.utils.block.BlockUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
public final class PlayerDiggingListener { public final class PlayerDiggingListener {
@ -58,7 +58,7 @@ public final class PlayerDiggingListener {
// Refresh block on player screen in case it had special data (like a sign) // Refresh block on player screen in case it had special data (like a sign)
var registry = diggingResult.block().registry(); var registry = diggingResult.block().registry();
if (registry.isBlockEntity()) { if (registry.isBlockEntity()) {
final NBTCompound data = BlockUtils.extractClientNbt(diggingResult.block()); final CompoundBinaryTag data = BlockUtils.extractClientNbt(diggingResult.block());
player.sendPacketToViewersAndSelf(new BlockEntityDataPacket(blockPosition, registry.blockEntityId(), data)); player.sendPacketToViewersAndSelf(new BlockEntityDataPacket(blockPosition, registry.blockEntityId(), data));
} }
} }

View File

@ -1,5 +1,7 @@
package net.minestom.server.message; package net.minestom.server.message;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.TagStringIO;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
@ -7,11 +9,8 @@ import net.minestom.server.network.packet.server.play.SystemChatPacket;
import net.minestom.server.utils.PacketUtils; import net.minestom.server.utils.PacketUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.parser.SNBTParser;
import java.io.StringReader; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
@ -27,11 +26,11 @@ public final class Messenger {
private static final UUID NO_SENDER = new UUID(0, 0); private static final UUID NO_SENDER = new UUID(0, 0);
private static final SystemChatPacket CANNOT_SEND_PACKET = new SystemChatPacket(CANNOT_SEND_MESSAGE, false); private static final SystemChatPacket CANNOT_SEND_PACKET = new SystemChatPacket(CANNOT_SEND_MESSAGE, false);
private static final NBTCompound CHAT_REGISTRY; private static final CompoundBinaryTag CHAT_REGISTRY;
static { static {
try { try {
CHAT_REGISTRY = (NBTCompound) new SNBTParser(new StringReader( CHAT_REGISTRY = TagStringIO.get().asCompound(
""" """
{ {
"type": "minecraft:chat_type", "type": "minecraft:chat_type",
@ -57,13 +56,13 @@ public final class Messenger {
} }
} ] } ]
}""" }"""
)).parse(); );
} catch (NBTException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public static @NotNull NBTCompound chatRegistry() { public static @NotNull CompoundBinaryTag chatRegistry() {
return CHAT_REGISTRY; return CHAT_REGISTRY;
} }

View File

@ -1,5 +1,6 @@
package net.minestom.server.network; package net.minestom.server.network;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
@ -32,7 +33,8 @@ import org.jctools.queues.MpscUnboundedArrayQueue;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -280,14 +282,15 @@ public final class ConnectionManager {
// Registry data (if it should be sent) // Registry data (if it should be sent)
if (event.willSendRegistryData()) { if (event.willSendRegistryData()) {
var registry = new HashMap<String, NBT>(); var registryCompound = CompoundBinaryTag.builder()
registry.put("minecraft:chat_type", Messenger.chatRegistry()); .put("minecraft:chat_type", Messenger.chatRegistry())
registry.put("minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT()); .put("minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT())
registry.put("minecraft:worldgen/biome", MinecraftServer.getBiomeManager().toNBT()); .put("minecraft:worldgen/biome", MinecraftServer.getBiomeManager().toNBT())
registry.put("minecraft:damage_type", DamageType.getNBT()); .put("minecraft:damage_type", DamageType.getNBT())
registry.put("minecraft:trim_material", MinecraftServer.getTrimManager().getTrimMaterialNBT()); // .put("minecraft:trim_material", MinecraftServer.getTrimManager().getTrimMaterialNBT())
registry.put("minecraft:trim_pattern", MinecraftServer.getTrimManager().getTrimPatternNBT()); // .put("minecraft:trim_pattern", MinecraftServer.getTrimManager().getTrimPatternNBT())
player.sendPacket(new RegistryDataPacket(NBT.Compound(registry))); .build();
player.sendPacket(new RegistryDataPacket(registryCompound));
player.sendPacket(TagsPacket.DEFAULT_TAGS); player.sendPacket(TagsPacket.DEFAULT_TAGS);
} }

View File

@ -1,5 +1,6 @@
package net.minestom.server.network; package net.minestom.server.network;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.entity.Entity; import net.minestom.server.entity.Entity;
@ -15,10 +16,9 @@ import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTReader;
import org.jglrxavpok.hephaistos.nbt.NBTWriter;
import java.io.DataInput;
import java.io.DataOutput;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.*; import java.util.*;
@ -40,7 +40,7 @@ public final class NetworkBuffer {
public static final Type<Long> VAR_LONG = new NetworkBufferTypeImpl.VarLongType(); public static final Type<Long> VAR_LONG = new NetworkBufferTypeImpl.VarLongType();
public static final Type<byte[]> RAW_BYTES = new NetworkBufferTypeImpl.RawBytesType(); public static final Type<byte[]> RAW_BYTES = new NetworkBufferTypeImpl.RawBytesType();
public static final Type<String> STRING = new NetworkBufferTypeImpl.StringType(); public static final Type<String> STRING = new NetworkBufferTypeImpl.StringType();
public static final Type<NBT> NBT = new NetworkBufferTypeImpl.NbtType(); public static final Type<BinaryTag> NBT = new NetworkBufferTypeImpl.NbtType();
public static final Type<Point> BLOCK_POSITION = new NetworkBufferTypeImpl.BlockPositionType(); public static final Type<Point> BLOCK_POSITION = new NetworkBufferTypeImpl.BlockPositionType();
public static final Type<Component> COMPONENT = new NetworkBufferTypeImpl.ComponentType(); public static final Type<Component> COMPONENT = new NetworkBufferTypeImpl.ComponentType();
public static final Type<Component> JSON_COMPONENT = new NetworkBufferTypeImpl.JsonComponentType(); public static final Type<Component> JSON_COMPONENT = new NetworkBufferTypeImpl.JsonComponentType();
@ -81,8 +81,8 @@ public final class NetworkBuffer {
int writeIndex; int writeIndex;
int readIndex; int readIndex;
NBTWriter nbtWriter; DataOutput nbtWriter;
NBTReader nbtReader; DataInput nbtReader;
public NetworkBuffer(@NotNull ByteBuffer buffer, boolean resizable) { public NetworkBuffer(@NotNull ByteBuffer buffer, boolean resizable) {
this.nioBuffer = buffer.order(ByteOrder.BIG_ENDIAN); this.nioBuffer = buffer.order(ByteOrder.BIG_ENDIAN);

View File

@ -1,16 +1,16 @@
package net.minestom.server.network.packet.server.configuration; package net.minestom.server.network.packet.server.configuration;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import static net.minestom.server.network.NetworkBuffer.NBT; import static net.minestom.server.network.NetworkBuffer.NBT;
public record RegistryDataPacket(@NotNull NBTCompound data) implements ServerPacket.Configuration { public record RegistryDataPacket(@NotNull CompoundBinaryTag data) implements ServerPacket.Configuration {
public RegistryDataPacket(@NotNull NetworkBuffer buffer) { public RegistryDataPacket(@NotNull NetworkBuffer buffer) {
this((NBTCompound) buffer.read(NBT)); this((CompoundBinaryTag) buffer.read(NBT));
} }
@Override @Override

View File

@ -1,19 +1,19 @@
package net.minestom.server.network.packet.server.play; package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import static net.minestom.server.network.NetworkBuffer.*; import static net.minestom.server.network.NetworkBuffer.*;
public record BlockEntityDataPacket(@NotNull Point blockPosition, int action, public record BlockEntityDataPacket(@NotNull Point blockPosition, int action,
@Nullable NBTCompound data) implements ServerPacket.Play { @Nullable CompoundBinaryTag data) implements ServerPacket.Play {
public BlockEntityDataPacket(@NotNull NetworkBuffer reader) { public BlockEntityDataPacket(@NotNull NetworkBuffer reader) {
this(reader.read(BLOCK_POSITION), reader.read(VAR_INT), (NBTCompound) reader.read(NBT)); this(reader.read(BLOCK_POSITION), reader.read(VAR_INT), (CompoundBinaryTag) reader.read(NBT));
} }
@Override @Override

View File

@ -1,20 +1,20 @@
package net.minestom.server.network.packet.server.play; package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.potion.Potion; import net.minestom.server.potion.Potion;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import static net.minestom.server.network.NetworkBuffer.*; import static net.minestom.server.network.NetworkBuffer.*;
public record EntityEffectPacket(int entityId, @NotNull Potion potion, public record EntityEffectPacket(int entityId, @NotNull Potion potion,
@Nullable NBTCompound factorCodec) implements ServerPacket.Play { @Nullable CompoundBinaryTag factorCodec) implements ServerPacket.Play {
public EntityEffectPacket(@NotNull NetworkBuffer reader) { public EntityEffectPacket(@NotNull NetworkBuffer reader) {
this(reader.read(VAR_INT), new Potion(reader), this(reader.read(VAR_INT), new Potion(reader),
reader.read(BOOLEAN) ? (NBTCompound) reader.read(NBT) : null); reader.read(BOOLEAN) ? (CompoundBinaryTag) reader.read(NBT) : null);
} }
@Override @Override

View File

@ -1,16 +1,17 @@
package net.minestom.server.network.packet.server.play; package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import static net.minestom.server.network.NetworkBuffer.*; import static net.minestom.server.network.NetworkBuffer.*;
public record NbtQueryResponsePacket(int transactionId, NBTCompound data) implements ServerPacket.Play { public record NbtQueryResponsePacket(int transactionId, CompoundBinaryTag data) implements ServerPacket.Play {
public NbtQueryResponsePacket(@NotNull NetworkBuffer reader) { public NbtQueryResponsePacket(@NotNull NetworkBuffer reader) {
this(reader.read(VAR_INT), (NBTCompound) reader.read(NBT)); this(reader.read(VAR_INT), (CompoundBinaryTag) reader.read(NBT));
} }
@Override @Override

View File

@ -1,12 +1,12 @@
package net.minestom.server.network.packet.server.play.data; package net.minestom.server.network.packet.server.play.data;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.block.BlockUtils; import net.minestom.server.utils.block.BlockUtils;
import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.chunk.ChunkUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -14,7 +14,7 @@ import java.util.stream.Collectors;
import static net.minestom.server.network.NetworkBuffer.*; import static net.minestom.server.network.NetworkBuffer.*;
public record ChunkData(@NotNull NBTCompound heightmaps, byte @NotNull [] data, public record ChunkData(@NotNull CompoundBinaryTag heightmaps, byte @NotNull [] data,
@NotNull Map<Integer, Block> blockEntities) implements NetworkBuffer.Writer { @NotNull Map<Integer, Block> blockEntities) implements NetworkBuffer.Writer {
public ChunkData { public ChunkData {
blockEntities = blockEntities.entrySet() blockEntities = blockEntities.entrySet()
@ -24,7 +24,7 @@ public record ChunkData(@NotNull NBTCompound heightmaps, byte @NotNull [] data,
} }
public ChunkData(@NotNull NetworkBuffer reader) { public ChunkData(@NotNull NetworkBuffer reader) {
this((NBTCompound) reader.read(NBT), reader.read(BYTE_ARRAY), this((CompoundBinaryTag) reader.read(NBT), reader.read(BYTE_ARRAY),
readBlockEntities(reader)); readBlockEntities(reader));
} }
@ -46,7 +46,7 @@ public record ChunkData(@NotNull NBTCompound heightmaps, byte @NotNull [] data,
writer.write(SHORT, (short) point.blockY()); // y writer.write(SHORT, (short) point.blockY()); // y
writer.write(VAR_INT, registry.blockEntityId()); writer.write(VAR_INT, registry.blockEntityId());
final NBTCompound nbt = BlockUtils.extractClientNbt(block); final CompoundBinaryTag nbt = BlockUtils.extractClientNbt(block);
assert nbt != null; assert nbt != null;
writer.write(NBT, nbt); // block nbt writer.write(NBT, nbt); // block nbt
} }
@ -59,7 +59,7 @@ public record ChunkData(@NotNull NBTCompound heightmaps, byte @NotNull [] data,
final byte xz = reader.read(BYTE); final byte xz = reader.read(BYTE);
final short y = reader.read(SHORT); final short y = reader.read(SHORT);
final int blockEntityId = reader.read(VAR_INT); final int blockEntityId = reader.read(VAR_INT);
final NBTCompound nbt = (NBTCompound) reader.read(NBT); final CompoundBinaryTag nbt = (CompoundBinaryTag) reader.read(NBT);
// TODO create block object // TODO create block object
} }
return blockEntities; return blockEntities;

View File

@ -1,23 +1,23 @@
package net.minestom.server.permission; package net.minestom.server.permission;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.command.CommandSender; import net.minestom.server.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Objects; import java.util.Objects;
/** /**
* Representation of a permission granted to a {@link CommandSender}. * Representation of a permission granted to a {@link CommandSender}.
* Each permission has a string representation used as an identifier, and an optional * Each permission has a string representation used as an identifier, and an optional
* {@link NBTCompound} used to store additional data. * {@link CompoundBinaryTag} used to store additional data.
* <p> * <p>
* The class is immutable. * The class is immutable.
*/ */
public class Permission { public class Permission {
private final String permissionName; private final String permissionName;
private final NBTCompound data; private final CompoundBinaryTag data;
/** /**
* Creates a new permission object with optional data. * Creates a new permission object with optional data.
@ -25,7 +25,7 @@ public class Permission {
* @param permissionName the name of the permission * @param permissionName the name of the permission
* @param data the optional data of the permission * @param data the optional data of the permission
*/ */
public Permission(@NotNull String permissionName, @Nullable NBTCompound data) { public Permission(@NotNull String permissionName, @Nullable CompoundBinaryTag data) {
this.permissionName = permissionName; this.permissionName = permissionName;
this.data = data; this.data = data;
} }
@ -55,7 +55,7 @@ public class Permission {
* @return the nbt data of this permission, can be null if not any * @return the nbt data of this permission, can be null if not any
*/ */
@Nullable @Nullable
public NBTCompound getNBTData() { public CompoundBinaryTag getNBTData() {
return data; return data;
} }

View File

@ -2,8 +2,6 @@ package net.minestom.server.permission;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.parser.SNBTParser;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -14,8 +12,7 @@ import java.util.regex.Pattern;
* Permissions are in-memory only by default. * Permissions are in-memory only by default.
* You have however the capacity to store them persistently as the {@link Permission} object * You have however the capacity to store them persistently as the {@link Permission} object
* is serializer-friendly, {@link Permission#getPermissionName()} being a {@link String} * is serializer-friendly, {@link Permission#getPermissionName()} being a {@link String}
* and {@link Permission#getNBTData()} serializable into a string using {@link NBTCompound#toSNBT()} * and {@link Permission#getNBTData()} serializable into a string using {@link net.kyori.adventure.nbt.TagStringIO}.
* and deserialized back with {@link SNBTParser#parse()}.
*/ */
public interface PermissionHandler { public interface PermissionHandler {

View File

@ -1,10 +1,10 @@
package net.minestom.server.permission; package net.minestom.server.permission;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
/** /**
* Interface used to check if the {@link NBTCompound nbt data} of a {@link Permission} is correct. * Interface used to check if the {@link CompoundBinaryTag nbt data} of a {@link Permission} is correct.
*/ */
@FunctionalInterface @FunctionalInterface
public interface PermissionVerifier { public interface PermissionVerifier {
@ -16,5 +16,5 @@ public interface PermissionVerifier {
* @return true if {@link PermissionHandler#hasPermission(String, PermissionVerifier)} * @return true if {@link PermissionHandler#hasPermission(String, PermissionVerifier)}
* should return true, false otherwise * should return true, false otherwise
*/ */
boolean isValid(@Nullable NBTCompound nbtCompound); boolean isValid(@Nullable CompoundBinaryTag nbtCompound);
} }

View File

@ -1,10 +1,10 @@
package net.minestom.server.tag; package net.minestom.server.tag;
import net.kyori.adventure.nbt.*;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minestom.server.ServerFlag; import net.minestom.server.ServerFlag;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import org.jglrxavpok.hephaistos.nbt.*;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
@ -13,40 +13,41 @@ import java.util.function.Function;
* Basic serializers for {@link Tag tags}. * Basic serializers for {@link Tag tags}.
*/ */
final class Serializers { final class Serializers {
static final Entry<Byte, NBTByte> BYTE = new Entry<>(NBTType.TAG_Byte, NBTByte::getValue, NBT::Byte); static final Entry<Byte, ByteBinaryTag> BYTE = new Entry<>(BinaryTagTypes.BYTE, ByteBinaryTag::value, ByteBinaryTag::byteBinaryTag);
static final Entry<Boolean, NBTByte> BOOLEAN = new Entry<>(NBTType.TAG_Byte, NBTByte::asBoolean, NBT::Boolean); static final Entry<Boolean, ByteBinaryTag> BOOLEAN = new Entry<>(BinaryTagTypes.BYTE, b -> b.value() != 0, b -> b ? ByteBinaryTag.ONE : ByteBinaryTag.ZERO);
static final Entry<Short, NBTShort> SHORT = new Entry<>(NBTType.TAG_Short, NBTShort::getValue, NBT::Short); static final Entry<Short, ShortBinaryTag> SHORT = new Entry<>(BinaryTagTypes.SHORT, ShortBinaryTag::value, ShortBinaryTag::shortBinaryTag);
static final Entry<Integer, NBTInt> INT = new Entry<>(NBTType.TAG_Int, NBTInt::getValue, NBT::Int); static final Entry<Integer, IntBinaryTag> INT = new Entry<>(BinaryTagTypes.INT, IntBinaryTag::value, IntBinaryTag::intBinaryTag);
static final Entry<Long, NBTLong> LONG = new Entry<>(NBTType.TAG_Long, NBTLong::getValue, NBT::Long); static final Entry<Long, LongBinaryTag> LONG = new Entry<>(BinaryTagTypes.LONG, LongBinaryTag::value, LongBinaryTag::longBinaryTag);
static final Entry<Float, NBTFloat> FLOAT = new Entry<>(NBTType.TAG_Float, NBTFloat::getValue, NBT::Float); static final Entry<Float, FloatBinaryTag> FLOAT = new Entry<>(BinaryTagTypes.FLOAT, FloatBinaryTag::value, FloatBinaryTag::floatBinaryTag);
static final Entry<Double, NBTDouble> DOUBLE = new Entry<>(NBTType.TAG_Double, NBTDouble::getValue, NBT::Double); static final Entry<Double, DoubleBinaryTag> DOUBLE = new Entry<>(BinaryTagTypes.DOUBLE, DoubleBinaryTag::value, DoubleBinaryTag::doubleBinaryTag);
static final Entry<String, NBTString> STRING = new Entry<>(NBTType.TAG_String, NBTString::getValue, NBT::String); static final Entry<String, StringBinaryTag> STRING = new Entry<>(BinaryTagTypes.STRING, StringBinaryTag::value, StringBinaryTag::stringBinaryTag);
static final Entry<NBT, NBT> NBT_ENTRY = new Entry<>(null, Function.identity(), Function.identity()); static final Entry<BinaryTag, BinaryTag> NBT_ENTRY = new Entry<>(null, Function.identity(), Function.identity());
static final Entry<java.util.UUID, NBTIntArray> UUID = new Entry<>(NBTType.TAG_Int_Array, intArray -> intArrayToUuid(intArray.getValue().copyArray()), static final Entry<java.util.UUID, IntArrayBinaryTag> UUID = new Entry<>(BinaryTagTypes.INT_ARRAY,
uuid -> NBT.IntArray(uuidToIntArray(uuid))); intArray -> intArrayToUuid(intArray.value()),
static final Entry<ItemStack, NBTCompound> ITEM = new Entry<>(NBTType.TAG_Compound, ItemStack::fromItemNBT, ItemStack::toItemNBT); uuid -> IntArrayBinaryTag.intArrayBinaryTag(uuidToIntArray(uuid)));
static final Entry<Component, NBTString> COMPONENT = new Entry<>(NBTType.TAG_String, input -> GsonComponentSerializer.gson().deserialize(input.getValue()), static final Entry<ItemStack, CompoundBinaryTag> ITEM = new Entry<>(BinaryTagTypes.COMPOUND, ItemStack::fromItemNBT, ItemStack::toItemNBT);
component -> NBT.String(GsonComponentSerializer.gson().serialize(component))); static final Entry<Component, StringBinaryTag> COMPONENT = new Entry<>(BinaryTagTypes.STRING, input -> GsonComponentSerializer.gson().deserialize(input.value()),
component -> StringBinaryTag.stringBinaryTag(GsonComponentSerializer.gson().serialize(component)));
static final Entry<Object, NBTByte> EMPTY = new Entry<>(NBTType.TAG_Byte, unused -> null, component -> null); static final Entry<Object, ByteBinaryTag> EMPTY = new Entry<>(BinaryTagTypes.BYTE, unused -> null, component -> null);
static <T> Entry<T, NBTCompound> fromTagSerializer(TagSerializer<T> serializer) { static <T> Entry<T, CompoundBinaryTag> fromTagSerializer(TagSerializer<T> serializer) {
return new Serializers.Entry<>(NBTType.TAG_Compound, return new Serializers.Entry<>(BinaryTagTypes.COMPOUND,
(NBTCompound compound) -> { (CompoundBinaryTag compound) -> {
if ((!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && compound.isEmpty()) return null; if ((!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && compound.size() == 0) return null;
return serializer.read(TagHandler.fromCompound(compound)); return serializer.read(TagHandler.fromCompound(compound));
}, },
(value) -> { (value) -> {
if (value == null) return NBTCompound.EMPTY; if (value == null) return CompoundBinaryTag.empty();
TagHandler handler = TagHandler.newHandler(); TagHandler handler = TagHandler.newHandler();
serializer.write(handler, value); serializer.write(handler, value);
return handler.asCompound(); return handler.asCompound();
}); });
} }
record Entry<T, N extends NBT>(NBTType<N> nbtType, Function<N, T> reader, Function<T, N> writer, boolean isPath) { record Entry<T, N extends BinaryTag>(BinaryTagType<N> nbtType, Function<N, T> reader, Function<T, N> writer, boolean isPath) {
Entry(NBTType<N> nbtType, Function<N, T> reader, Function<T, N> writer) { Entry(BinaryTagType<N> nbtType, Function<N, T> reader, Function<T, N> writer) {
this(nbtType, reader, writer, false); this(nbtType, reader, writer, false);
} }

View File

@ -1,5 +1,6 @@
package net.minestom.server.tag; package net.minestom.server.tag;
import net.kyori.adventure.nbt.*;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.collection.AutoIncrementMap; import net.minestom.server.utils.collection.AutoIncrementMap;
@ -7,11 +8,6 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompoundLike;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -37,7 +33,7 @@ public class Tag<T> {
final int index; final int index;
private final String key; private final String key;
final Serializers.Entry<T, NBT> entry; final Serializers.Entry<T, BinaryTag> entry;
private final Supplier<T> defaultValue; private final Supplier<T> defaultValue;
final Function<?, ?> readComparator; final Function<?, ?> readComparator;
@ -48,7 +44,7 @@ public class Tag<T> {
Tag(int index, String key, Tag(int index, String key,
Function<?, ?> readComparator, Function<?, ?> readComparator,
Serializers.Entry<T, NBT> entry, Serializers.Entry<T, BinaryTag> entry,
Supplier<T> defaultValue, PathEntry[] path, UnaryOperator<T> copy, int listScope) { Supplier<T> defaultValue, PathEntry[] path, UnaryOperator<T> copy, int listScope) {
assert index == INDEX_MAP.get(key); assert index == INDEX_MAP.get(key);
this.index = index; this.index = index;
@ -61,8 +57,8 @@ public class Tag<T> {
this.listScope = listScope; this.listScope = listScope;
} }
static <T, N extends NBT> Tag<T> tag(@NotNull String key, @NotNull Serializers.Entry<T, N> entry) { static <T, N extends BinaryTag> Tag<T> tag(@NotNull String key, @NotNull Serializers.Entry<T, N> entry) {
return new Tag<>(INDEX_MAP.get(key), key, entry.reader(), (Serializers.Entry<T, NBT>) entry, return new Tag<>(INDEX_MAP.get(key), key, entry.reader(), (Serializers.Entry<T, BinaryTag>) entry,
null, null, null, 0); null, null, null, 0);
} }
@ -98,11 +94,11 @@ public class Tag<T> {
public <R> Tag<R> map(@NotNull Function<T, R> readMap, public <R> Tag<R> map(@NotNull Function<T, R> readMap,
@NotNull Function<R, T> writeMap) { @NotNull Function<R, T> writeMap) {
var entry = this.entry; var entry = this.entry;
final Function<NBT, R> readFunction = entry.reader().andThen(t -> { final Function<BinaryTag, R> readFunction = entry.reader().andThen(t -> {
if (t == null) return null; if (t == null) return null;
return readMap.apply(t); return readMap.apply(t);
}); });
final Function<R, NBT> writeFunction = writeMap.andThen(entry.writer()); final Function<R, BinaryTag> writeFunction = writeMap.andThen(entry.writer());
return new Tag<>(index, key, readMap, return new Tag<>(index, key, readMap,
new Serializers.Entry<>(entry.nbtType(), readFunction, writeFunction), new Serializers.Entry<>(entry.nbtType(), readFunction, writeFunction),
// Default value // Default value
@ -120,18 +116,18 @@ public class Tag<T> {
var entry = this.entry; var entry = this.entry;
var readFunction = entry.reader(); var readFunction = entry.reader();
var writeFunction = entry.writer(); var writeFunction = entry.writer();
var listEntry = new Serializers.Entry<List<T>, NBTList<?>>( var listEntry = new Serializers.Entry<List<T>, ListBinaryTag>(
NBTType.TAG_List, BinaryTagTypes.LIST,
read -> { read -> {
if (read.isEmpty()) return List.of(); if (read.size() == 0) return List.of();
return read.asListView().stream().map(readFunction).toList(); return read.stream().map(readFunction).toList();
}, },
write -> { write -> {
if (write.isEmpty()) if (write.isEmpty())
return NBT.List(NBTType.TAG_String); // String is the default type for lists return ListBinaryTag.empty();
final List<NBT> list = write.stream().map(writeFunction).toList(); final List<BinaryTag> list = write.stream().map(writeFunction).toList();
final NBTType<?> type = list.get(0).getID(); final BinaryTagType<?> type = list.get(0).type();
return NBT.List(type, list); return ListBinaryTag.listBinaryTag(type, list);
}); });
UnaryOperator<List<T>> co = this.copy != null ? ts -> { UnaryOperator<List<T>> co = this.copy != null ? ts -> {
final int size = ts.size(); final int size = ts.size();
@ -165,8 +161,8 @@ public class Tag<T> {
return new Tag<>(index, key, readComparator, entry, defaultValue, pathEntries, copy, listScope); return new Tag<>(index, key, readComparator, entry, defaultValue, pathEntries, copy, listScope);
} }
public @Nullable T read(@NotNull NBTCompoundLike nbt) { public @Nullable T read(@NotNull CompoundBinaryTag nbt) {
final NBT readable = isView() ? nbt.toCompound() : nbt.get(key); final BinaryTag readable = isView() ? nbt : nbt.get(key);
final T result; final T result;
try { try {
if (readable == null || (result = entry.read(readable)) == null) if (readable == null || (result = entry.read(readable)) == null)
@ -177,18 +173,20 @@ public class Tag<T> {
} }
} }
public void write(@NotNull MutableNBTCompound nbtCompound, @Nullable T value) { public void write(@NotNull CompoundBinaryTag.Builder nbtCompound, @Nullable T value) {
if (value != null) { if (value != null) {
final NBT nbt = entry.write(value); final BinaryTag nbt = entry.write(value);
if (isView()) nbtCompound.copyFrom((NBTCompoundLike) nbt); if (isView()) nbtCompound.put((CompoundBinaryTag) nbt);
else nbtCompound.set(key, nbt); else nbtCompound.put(key, nbt);
} else { } else {
if (isView()) nbtCompound.clear(); if (isView()) {
else nbtCompound.remove(key); // Adventure compound builder doesn't currently have a clear method.
nbtCompound.build().keySet().forEach(nbtCompound::remove);
} else nbtCompound.remove(key);
} }
} }
public void writeUnsafe(@NotNull MutableNBTCompound nbtCompound, @Nullable Object value) { public void writeUnsafe(@NotNull CompoundBinaryTag.Builder nbtCompound, @Nullable Object value) {
//noinspection unchecked //noinspection unchecked
write(nbtCompound, (T) value); write(nbtCompound, (T) value);
} }
@ -279,11 +277,11 @@ public class Tag<T> {
} }
/** /**
* Creates a flexible tag able to read and write any {@link NBT} objects. * Creates a flexible tag able to read and write any {@link BinaryTag} objects.
* <p> * <p>
* Specialized tags are recommended if the type is known as conversion will be required both way (read and write). * Specialized tags are recommended if the type is known as conversion will be required both way (read and write).
*/ */
public static @NotNull Tag<NBT> NBT(@NotNull String key) { public static @NotNull Tag<BinaryTag> NBT(@NotNull String key) {
return tag(key, Serializers.NBT_ENTRY); return tag(key, Serializers.NBT_ENTRY);
} }

View File

@ -1,10 +1,9 @@
package net.minestom.server.tag; package net.minestom.server.tag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.UnknownNullability; import org.jetbrains.annotations.UnknownNullability;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTCompoundLike;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
@ -26,7 +25,7 @@ public interface TagHandler extends TagReadable, TagWritable {
/** /**
* Creates a copy of this handler. * Creates a copy of this handler.
* <p> * <p>
* Similar to {@link #fromCompound(NBTCompoundLike)} using {@link #asCompound()} * Similar to {@link #fromCompound(CompoundBinaryTag)} using {@link #asCompound()}
* with the advantage that cached objects and adaptive optimizations may be reused. * with the advantage that cached objects and adaptive optimizations may be reused.
* *
* @return a copy of this handler * @return a copy of this handler
@ -36,18 +35,18 @@ public interface TagHandler extends TagReadable, TagWritable {
/** /**
* Updates the content of this handler. * Updates the content of this handler.
* <p> * <p>
* Can be used as a clearing method with {@link NBTCompound#EMPTY}. * Can be used as a clearing method with {@link CompoundBinaryTag#empty()}.
* *
* @param compound the new content of this handler * @param compound the new content of this handler
*/ */
void updateContent(@NotNull NBTCompoundLike compound); void updateContent(@NotNull CompoundBinaryTag compound);
/** /**
* Converts the content of this handler into a {@link NBTCompound}. * Converts the content of this handler into a {@link CompoundBinaryTag}.
* *
* @return a nbt compound representation of this handler * @return a nbt compound representation of this handler
*/ */
@NotNull NBTCompound asCompound(); @NotNull CompoundBinaryTag asCompound();
@ApiStatus.Experimental @ApiStatus.Experimental
<T> void updateTag(@NotNull Tag<T> tag, <T> void updateTag(@NotNull Tag<T> tag,
@ -67,12 +66,12 @@ public interface TagHandler extends TagReadable, TagWritable {
} }
/** /**
* Copy the content of the given {@link NBTCompoundLike} into a new {@link TagHandler}. * Copy the content of the given {@link CompoundBinaryTag} into a new {@link TagHandler}.
* *
* @param compound the compound to read tags from * @param compound the compound to read tags from
* @return a new tag handler with the content of the given compound * @return a new tag handler with the content of the given compound
*/ */
static @NotNull TagHandler fromCompound(@NotNull NBTCompoundLike compound) { static @NotNull TagHandler fromCompound(@NotNull CompoundBinaryTag compound) {
return TagHandlerImpl.fromCompound(compound); return TagHandlerImpl.fromCompound(compound);
} }
} }

View File

@ -1,22 +1,21 @@
package net.minestom.server.tag; package net.minestom.server.tag;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.BinaryTagType;
import net.kyori.adventure.nbt.BinaryTagTypes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.ServerFlag; import net.minestom.server.ServerFlag;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability; import org.jetbrains.annotations.UnknownNullability;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTCompoundLike;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import java.lang.invoke.VarHandle; import java.lang.invoke.VarHandle;
import java.util.Map; import java.util.Map;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
final class TagHandlerImpl implements TagHandler { final class TagHandlerImpl implements TagHandler {
static final Serializers.Entry<Node, NBTCompound> NODE_SERIALIZER = new Serializers.Entry<>(NBTType.TAG_Compound, entries -> fromCompound(entries).root, Node::compound, true); static final Serializers.Entry<Node, CompoundBinaryTag> NODE_SERIALIZER = new Serializers.Entry<>(BinaryTagTypes.COMPOUND, entries -> fromCompound(entries).root, Node::compound, true);
private final Node root; private final Node root;
private volatile Node copy; private volatile Node copy;
@ -29,8 +28,7 @@ final class TagHandlerImpl implements TagHandler {
this.root = new Node(); this.root = new Node();
} }
static TagHandlerImpl fromCompound(NBTCompoundLike compoundLike) { static TagHandlerImpl fromCompound(CompoundBinaryTag compound) {
final NBTCompound compound = compoundLike.toCompound();
TagHandlerImpl handler = new TagHandlerImpl(); TagHandlerImpl handler = new TagHandlerImpl();
TagNbtSeparator.separate(compound, entry -> handler.setTag(entry.tag(), entry.value())); TagNbtSeparator.separate(compound, entry -> handler.setTag(entry.tag(), entry.value()));
handler.root.compound = compound; handler.root.compound = compound;
@ -50,7 +48,7 @@ final class TagHandlerImpl implements TagHandler {
synchronized (this) { synchronized (this) {
Node syncNode = traversePathWrite(root, tag, value != null); Node syncNode = traversePathWrite(root, tag, value != null);
if (syncNode != null) { if (syncNode != null) {
syncNode.updateContent(value != null ? (NBTCompound) tag.entry.write(value) : NBTCompound.EMPTY); syncNode.updateContent(value != null ? (CompoundBinaryTag) tag.entry.write(value) : CompoundBinaryTag.empty());
syncNode.invalidate(); syncNode.invalidate();
} }
} }
@ -103,7 +101,7 @@ final class TagHandlerImpl implements TagHandler {
if (tag.isView()) { if (tag.isView()) {
final T previousValue = tag.read(node.compound()); final T previousValue = tag.read(node.compound());
final T newValue = value.apply(previousValue); final T newValue = value.apply(previousValue);
node.updateContent((NBTCompoundLike) tag.entry.write(newValue)); node.updateContent((CompoundBinaryTag) tag.entry.write(newValue));
node.invalidate(); node.invalidate();
return returnPrevious ? previousValue : newValue; return returnPrevious ? previousValue : newValue;
} }
@ -116,7 +114,7 @@ final class TagHandlerImpl implements TagHandler {
if (previousEntry != null) { if (previousEntry != null) {
final Object previousTmp = previousEntry.value; final Object previousTmp = previousEntry.value;
if (previousTmp instanceof Node n) { if (previousTmp instanceof Node n) {
final NBTCompound compound = NBT.Compound(Map.of(tag.getKey(), n.compound())); final CompoundBinaryTag compound = CompoundBinaryTag.from(Map.of(tag.getKey(), n.compound()));
previousValue = tag.read(compound); previousValue = tag.read(compound);
} else { } else {
previousValue = (T) previousTmp; previousValue = (T) previousTmp;
@ -149,12 +147,12 @@ final class TagHandlerImpl implements TagHandler {
} }
@Override @Override
public synchronized void updateContent(@NotNull NBTCompoundLike compound) { public synchronized void updateContent(@NotNull CompoundBinaryTag compound) {
this.root.updateContent(compound); this.root.updateContent(compound);
} }
@Override @Override
public @NotNull NBTCompound asCompound() { public @NotNull CompoundBinaryTag asCompound() {
VarHandle.fullFence(); VarHandle.fullFence();
return root.compound(); return root.compound();
} }
@ -200,7 +198,7 @@ final class TagHandlerImpl implements TagHandler {
// Slow path is taken if the entry comes from a Structure tag, requiring conversion from NBT // Slow path is taken if the entry comes from a Structure tag, requiring conversion from NBT
Node tmp = local; Node tmp = local;
local = new Node(tmp); local = new Node(tmp);
if (synEntry != null && synEntry.updatedNbt() instanceof NBTCompound compound) { if (synEntry != null && synEntry.updatedNbt() instanceof CompoundBinaryTag compound) {
local.updateContent(compound); local.updateContent(compound);
} }
tmp.entries.put(pathIndex, Entry.makePathEntry(path.name(), local)); tmp.entries.put(pathIndex, Entry.makePathEntry(path.name(), local));
@ -211,8 +209,8 @@ final class TagHandlerImpl implements TagHandler {
} }
private <T> Entry<?> valueToEntry(Node parent, Tag<T> tag, @NotNull T value) { private <T> Entry<?> valueToEntry(Node parent, Tag<T> tag, @NotNull T value) {
if (value instanceof NBT nbt) { if (value instanceof BinaryTag nbt) {
if (nbt instanceof NBTCompound compound) { if (nbt instanceof CompoundBinaryTag compound) {
final TagHandlerImpl handler = fromCompound(compound); final TagHandlerImpl handler = fromCompound(compound);
return Entry.makePathEntry(tag, new Node(parent, handler.root.entries)); return Entry.makePathEntry(tag, new Node(parent, handler.root.entries));
} else { } else {
@ -227,7 +225,7 @@ final class TagHandlerImpl implements TagHandler {
final class Node implements TagReadable { final class Node implements TagReadable {
final Node parent; final Node parent;
final StaticIntMap<Entry<?>> entries; final StaticIntMap<Entry<?>> entries;
NBTCompound compound; CompoundBinaryTag compound;
public Node(Node parent, StaticIntMap<Entry<?>> entries) { public Node(Node parent, StaticIntMap<Entry<?>> entries) {
this.parent = parent; this.parent = parent;
@ -260,44 +258,43 @@ final class TagHandlerImpl implements TagHandler {
return (T) entry.value; return (T) entry.value;
} }
// Value must be parsed from nbt if the tag is different // Value must be parsed from nbt if the tag is different
final NBT nbt = entry.updatedNbt(); final BinaryTag nbt = entry.updatedNbt();
final Serializers.Entry<T, NBT> serializerEntry = tag.entry; final Serializers.Entry<T, BinaryTag> serializerEntry = tag.entry;
final NBTType<NBT> type = serializerEntry.nbtType(); final BinaryTagType<BinaryTag> type = serializerEntry.nbtType();
return type == null || type == nbt.getID() ? serializerEntry.read(nbt) : tag.createDefault(); return type == null || type.equals(nbt.type()) ? serializerEntry.read(nbt) : tag.createDefault();
} }
void updateContent(@NotNull NBTCompoundLike compoundLike) { void updateContent(@NotNull CompoundBinaryTag compound) {
final NBTCompound compound = compoundLike.toCompound();
final TagHandlerImpl converted = fromCompound(compound); final TagHandlerImpl converted = fromCompound(compound);
this.entries.updateContent(converted.root.entries); this.entries.updateContent(converted.root.entries);
this.compound = compound; this.compound = compound;
} }
NBTCompound compound() { CompoundBinaryTag compound() {
NBTCompound compound; CompoundBinaryTag compound;
if (!ServerFlag.TAG_HANDLER_CACHE_ENABLED || (compound = this.compound) == null) { if (!ServerFlag.TAG_HANDLER_CACHE_ENABLED || (compound = this.compound) == null) {
MutableNBTCompound tmp = new MutableNBTCompound(); CompoundBinaryTag.Builder tmp = CompoundBinaryTag.builder();
this.entries.forValues(entry -> { this.entries.forValues(entry -> {
final Tag tag = entry.tag; final Tag tag = entry.tag;
final NBT nbt = entry.updatedNbt(); final BinaryTag nbt = entry.updatedNbt();
if (nbt != null && (!tag.entry.isPath() || (!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && !((NBTCompound) nbt).isEmpty())) { if (nbt != null && (!tag.entry.isPath() || (!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && ((CompoundBinaryTag) nbt).size() > 0)) {
tmp.put(tag.getKey(), nbt); tmp.put(tag.getKey(), nbt);
} }
}); });
this.compound = compound = tmp.toCompound(); this.compound = compound = tmp.build();
} }
return compound; return compound;
} }
@Contract("null -> !null") @Contract("null -> !null")
Node copy(Node parent) { Node copy(Node parent) {
MutableNBTCompound tmp = new MutableNBTCompound(); CompoundBinaryTag.Builder tmp = CompoundBinaryTag.builder();
Node result = new Node(parent, new StaticIntMap.Array<>()); Node result = new Node(parent, new StaticIntMap.Array<>());
StaticIntMap<Entry<?>> entries = result.entries; StaticIntMap<Entry<?>> entries = result.entries;
this.entries.forValues(entry -> { this.entries.forValues(entry -> {
Tag tag = entry.tag; Tag tag = entry.tag;
Object value = entry.value; Object value = entry.value;
NBT nbt; BinaryTag nbt;
if (value instanceof Node node) { if (value instanceof Node node) {
Node copy = node.copy(result); Node copy = node.copy(result);
if (copy == null) if (copy == null)
@ -313,9 +310,10 @@ final class TagHandlerImpl implements TagHandler {
tmp.put(tag.getKey(), nbt); tmp.put(tag.getKey(), nbt);
entries.put(tag.index, valueToEntry(result, tag, value)); entries.put(tag.index, valueToEntry(result, tag, value));
}); });
if ((!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && tmp.isEmpty() && parent != null) var compound = tmp.build();
if ((!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && compound.size() == 0 && parent != null)
return null; // Empty child node return null; // Empty child node
result.compound = tmp.toCompound(); result.compound = compound;
return result; return result;
} }
@ -330,7 +328,7 @@ final class TagHandlerImpl implements TagHandler {
private static final class Entry<T> { private static final class Entry<T> {
private final Tag<T> tag; private final Tag<T> tag;
T value; T value;
NBT nbt; BinaryTag nbt;
Entry(Tag<T> tag, T value) { Entry(Tag<T> tag, T value) {
this.tag = tag; this.tag = tag;
@ -345,9 +343,9 @@ final class TagHandlerImpl implements TagHandler {
return makePathEntry(tag.getKey(), node); return makePathEntry(tag.getKey(), node);
} }
NBT updatedNbt() { BinaryTag updatedNbt() {
if (tag.entry.isPath()) return ((Node) value).compound(); if (tag.entry.isPath()) return ((Node) value).compound();
NBT nbt = this.nbt; BinaryTag nbt = this.nbt;
if (nbt == null) this.nbt = nbt = tag.entry.write(value); if (nbt == null) this.nbt = nbt = tag.entry.write(value);
return nbt; return nbt;
} }
@ -360,7 +358,7 @@ final class TagHandlerImpl implements TagHandler {
Node toNode() { Node toNode() {
if (tag.entry.isPath()) return (Node) value; if (tag.entry.isPath()) return (Node) value;
if (updatedNbt() instanceof NBTCompound compound) { if (updatedNbt() instanceof CompoundBinaryTag compound) {
// Slow path forcing a conversion of the structure to NBTCompound // Slow path forcing a conversion of the structure to NBTCompound
// TODO should the handler be cached inside the entry? // TODO should the handler be cached inside the entry?
return fromCompound(compound).root; return fromCompound(compound).root;

View File

@ -1,9 +1,7 @@
package net.minestom.server.tag; package net.minestom.server.tag;
import org.jglrxavpok.hephaistos.nbt.NBT; import net.kyori.adventure.nbt.*;
import org.jglrxavpok.hephaistos.nbt.NBTCompound; import net.minestom.server.utils.NBTUtils;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -15,30 +13,30 @@ import java.util.function.Function;
import static java.util.Map.entry; import static java.util.Map.entry;
/** /**
* Handles conversion of {@link NBT} subtypes into one or multiple primitive {@link Tag tags}. * Handles conversion of {@link BinaryTag} subtypes into one or multiple primitive {@link Tag tags}.
*/ */
final class TagNbtSeparator { final class TagNbtSeparator {
static final Map<NBTType<?>, Function<String, Tag<?>>> SUPPORTED_TYPES = Map.ofEntries( static final Map<BinaryTagType<?>, Function<String, Tag<?>>> SUPPORTED_TYPES = Map.ofEntries(
entry(NBTType.TAG_Byte, Tag::Byte), entry(BinaryTagTypes.BYTE, Tag::Byte),
entry(NBTType.TAG_Short, Tag::Short), entry(BinaryTagTypes.SHORT, Tag::Short),
entry(NBTType.TAG_Int, Tag::Integer), entry(BinaryTagTypes.INT, Tag::Integer),
entry(NBTType.TAG_Long, Tag::Long), entry(BinaryTagTypes.LONG, Tag::Long),
entry(NBTType.TAG_Float, Tag::Float), entry(BinaryTagTypes.FLOAT, Tag::Float),
entry(NBTType.TAG_Double, Tag::Double), entry(BinaryTagTypes.DOUBLE, Tag::Double),
entry(NBTType.TAG_String, Tag::String)); entry(BinaryTagTypes.STRING, Tag::String));
static void separate(NBTCompound nbtCompound, Consumer<Entry> consumer) { static void separate(CompoundBinaryTag nbtCompound, Consumer<Entry> consumer) {
for (var ent : nbtCompound) { for (var ent : nbtCompound) {
convert(new ArrayList<>(), ent.getKey(), ent.getValue(), consumer); convert(new ArrayList<>(), ent.getKey(), ent.getValue(), consumer);
} }
} }
static void separate(String key, NBT nbt, Consumer<Entry> consumer) { static void separate(String key, BinaryTag nbt, Consumer<Entry> consumer) {
convert(new ArrayList<>(), key, nbt, consumer); convert(new ArrayList<>(), key, nbt, consumer);
} }
static Entry separateSingle(String key, NBT nbt) { static Entry separateSingle(String key, BinaryTag nbt) {
assert !(nbt instanceof NBTCompound); assert !(nbt instanceof CompoundBinaryTag);
AtomicReference<Entry<?>> entryRef = new AtomicReference<>(); AtomicReference<Entry<?>> entryRef = new AtomicReference<>();
convert(new ArrayList<>(), key, nbt, entry -> { convert(new ArrayList<>(), key, nbt, entry -> {
assert entryRef.getPlain() == null : "Multiple entries found for nbt tag: " + key + " -> " + nbt; assert entryRef.getPlain() == null : "Multiple entries found for nbt tag: " + key + " -> " + nbt;
@ -49,28 +47,28 @@ final class TagNbtSeparator {
return entry; return entry;
} }
private static void convert(List<String> path, String key, NBT nbt, Consumer<Entry> consumer) { private static void convert(List<String> path, String key, BinaryTag nbt, Consumer<Entry> consumer) {
var tagFunction = SUPPORTED_TYPES.get(nbt.getID()); var tagFunction = SUPPORTED_TYPES.get(nbt.type());
if (tagFunction != null) { if (tagFunction != null) {
Tag tag = tagFunction.apply(key); Tag tag = tagFunction.apply(key);
consumer.accept(makeEntry(path, tag, nbt.getValue())); consumer.accept(makeEntry(path, tag, NBTUtils.nbtValueFromTag(nbt)));
} else if (nbt instanceof NBTCompound nbtCompound) { } else if (nbt instanceof CompoundBinaryTag nbtCompound) {
for (var ent : nbtCompound) { for (var ent : nbtCompound) {
var newPath = new ArrayList<>(path); var newPath = new ArrayList<>(path);
newPath.add(key); newPath.add(key);
convert(newPath, ent.getKey(), ent.getValue(), consumer); convert(newPath, ent.getKey(), ent.getValue(), consumer);
} }
} else if (nbt instanceof NBTList<?> nbtList) { } else if (nbt instanceof ListBinaryTag nbtList) {
tagFunction = SUPPORTED_TYPES.get(nbtList.getSubtagType()); tagFunction = SUPPORTED_TYPES.get(nbtList.elementType());
if (tagFunction == null) { if (tagFunction == null) {
// Invalid list subtype, fallback to nbt // Invalid list subtype, fallback to nbt
consumer.accept(makeEntry(path, Tag.NBT(key), nbt)); consumer.accept(makeEntry(path, Tag.NBT(key), nbt));
} else { } else {
try { try {
var tag = tagFunction.apply(key).list(); var tag = tagFunction.apply(key).list();
Object[] values = new Object[nbtList.getSize()]; Object[] values = new Object[nbtList.size()];
for (int i = 0; i < values.length; i++) { for (int i = 0; i < values.length; i++) {
values[i] = nbtList.get(i).getValue(); values[i] = NBTUtils.nbtValueFromTag(nbtList.get(i));
} }
consumer.accept(makeEntry(path, Tag.class.cast(tag), List.of(values))); consumer.accept(makeEntry(path, Tag.class.cast(tag), List.of(values)));
} catch (Exception e) { } catch (Exception e) {

View File

@ -1,11 +1,11 @@
package net.minestom.server.tag; package net.minestom.server.tag;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -44,7 +44,7 @@ final class TagRecord {
final Tag<?> tag; final Tag<?> tag;
if (componentType.isRecord()) { if (componentType.isRecord()) {
tag = Tag.Structure(componentName, serializers.get(componentType)); tag = Tag.Structure(componentName, serializers.get(componentType));
} else if (NBT.class.isAssignableFrom(componentType)) { } else if (BinaryTag.class.isAssignableFrom(componentType)) {
tag = Tag.NBT(componentName); tag = Tag.NBT(componentName);
} else { } else {
final var fun = SUPPORTED_TYPES.get(componentType); final var fun = SUPPORTED_TYPES.get(componentType);
@ -73,7 +73,7 @@ final class TagRecord {
static final class Serializer<T extends Record> implements TagSerializer<T> { static final class Serializer<T extends Record> implements TagSerializer<T> {
final Constructor<T> constructor; final Constructor<T> constructor;
final Entry[] entries; final Entry[] entries;
final Serializers.Entry<T, NBTCompound> serializerEntry; final Serializers.Entry<T, CompoundBinaryTag> serializerEntry;
Serializer(Constructor<T> constructor, Entry[] entries) { Serializer(Constructor<T> constructor, Entry[] entries) {
this.constructor = constructor; this.constructor = constructor;

View File

@ -1,9 +1,9 @@
package net.minestom.server.tag; package net.minestom.server.tag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.function.Function; import java.util.function.Function;
@ -31,11 +31,11 @@ public interface TagSerializer<T> {
void write(@NotNull TagWritable writer, @NotNull T value); void write(@NotNull TagWritable writer, @NotNull T value);
@ApiStatus.Experimental @ApiStatus.Experimental
TagSerializer<NBTCompound> COMPOUND = TagSerializerImpl.COMPOUND; TagSerializer<CompoundBinaryTag> COMPOUND = TagSerializerImpl.COMPOUND;
@ApiStatus.Experimental @ApiStatus.Experimental
static <T> TagSerializer<T> fromCompound(@NotNull Function<NBTCompound, T> reader, static <T> TagSerializer<T> fromCompound(@NotNull Function<CompoundBinaryTag, T> reader,
@NotNull Function<T, NBTCompound> writer) { @NotNull Function<T, CompoundBinaryTag> writer) {
return TagSerializerImpl.fromCompound(reader, writer); return TagSerializerImpl.fromCompound(reader, writer);
} }
} }

View File

@ -1,35 +1,35 @@
package net.minestom.server.tag; package net.minestom.server.tag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.function.Function; import java.util.function.Function;
final class TagSerializerImpl { final class TagSerializerImpl {
public static final TagSerializer<NBTCompound> COMPOUND = new TagSerializer<>() { public static final TagSerializer<CompoundBinaryTag> COMPOUND = new TagSerializer<>() {
@Override @Override
public @NotNull NBTCompound read(@NotNull TagReadable reader) { public @NotNull CompoundBinaryTag read(@NotNull TagReadable reader) {
return ((TagHandler) reader).asCompound(); return ((TagHandler) reader).asCompound();
} }
@Override @Override
public void write(@NotNull TagWritable writer, @NotNull NBTCompound value) { public void write(@NotNull TagWritable writer, @NotNull CompoundBinaryTag value) {
TagNbtSeparator.separate(value, entry -> writer.setTag(entry.tag(), entry.value())); TagNbtSeparator.separate(value, entry -> writer.setTag(entry.tag(), entry.value()));
} }
}; };
static <T> TagSerializer<T> fromCompound(Function<NBTCompound, T> readFunc, Function<T, NBTCompound> writeFunc) { static <T> TagSerializer<T> fromCompound(Function<CompoundBinaryTag, T> readFunc, Function<T, CompoundBinaryTag> writeFunc) {
return new TagSerializer<>() { return new TagSerializer<>() {
@Override @Override
public @Nullable T read(@NotNull TagReadable reader) { public @Nullable T read(@NotNull TagReadable reader) {
final NBTCompound compound = COMPOUND.read(reader); final CompoundBinaryTag compound = COMPOUND.read(reader);
return readFunc.apply(compound); return readFunc.apply(compound);
} }
@Override @Override
public void write(@NotNull TagWritable writer, @NotNull T value) { public void write(@NotNull TagWritable writer, @NotNull T value) {
final NBTCompound compound = writeFunc.apply(value); final CompoundBinaryTag compound = writeFunc.apply(value);
COMPOUND.write(writer, compound); COMPOUND.write(writer, compound);
} }
}; };

View File

@ -0,0 +1,59 @@
package net.minestom.server.utils;
import net.kyori.adventure.nbt.*;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@ApiStatus.Internal
public final class NBTUtils {
private static final BinaryTagType<?>[] TYPES = new BinaryTagType[]{
BinaryTagTypes.END,
BinaryTagTypes.BYTE,
BinaryTagTypes.SHORT,
BinaryTagTypes.INT,
BinaryTagTypes.LONG,
BinaryTagTypes.FLOAT,
BinaryTagTypes.DOUBLE,
BinaryTagTypes.BYTE_ARRAY,
BinaryTagTypes.STRING,
BinaryTagTypes.LIST,
BinaryTagTypes.COMPOUND,
BinaryTagTypes.INT_ARRAY,
BinaryTagTypes.LONG_ARRAY,
};
public static @NotNull BinaryTagType<?> nbtTypeFromId(byte id) {
Check.argCondition(id < 0 || id >= TYPES.length, "Invalid NBT type id: " + id);
return TYPES[id];
}
public static @NotNull Object nbtValueFromTag(@NotNull BinaryTag tag) {
if (tag instanceof ByteBinaryTag byteTag) {
return byteTag.value();
} else if (tag instanceof ShortBinaryTag shortTag) {
return shortTag.value();
} else if (tag instanceof IntBinaryTag intTag) {
return intTag.value();
} else if (tag instanceof LongBinaryTag longTag) {
return longTag.value();
} else if (tag instanceof FloatBinaryTag floatTag) {
return floatTag.value();
} else if (tag instanceof DoubleBinaryTag doubleTag) {
return doubleTag.value();
} else if (tag instanceof ByteArrayBinaryTag byteArrayTag) {
return byteArrayTag.value();
} else if (tag instanceof StringBinaryTag stringTag) {
return stringTag.value();
} else if (tag instanceof IntArrayBinaryTag intArrayTag) {
return intArrayTag.value();
} else if (tag instanceof LongArrayBinaryTag longArrayTag) {
return longArrayTag.value();
} else {
throw new UnsupportedOperationException("Unsupported NBT type: " + tag.getClass());
}
}
private NBTUtils() {
}
}

View File

@ -2,8 +2,6 @@ package net.minestom.server.utils.binary;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTReader;
import org.jglrxavpok.hephaistos.nbt.NBTWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -17,8 +15,6 @@ import java.nio.channels.WritableByteChannel;
@ApiStatus.Internal @ApiStatus.Internal
public final class BinaryBuffer { public final class BinaryBuffer {
private ByteBuffer nioBuffer; // To become a `MemorySegment` once released private ByteBuffer nioBuffer; // To become a `MemorySegment` once released
private NBTReader nbtReader;
private NBTWriter nbtWriter;
private final int capacity; private final int capacity;
private int readerOffset, writerOffset; private int readerOffset, writerOffset;

View File

@ -1,5 +1,6 @@
package net.minestom.server.utils.binary; package net.minestom.server.utils.binary;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
@ -8,7 +9,6 @@ import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.Either; import net.minestom.server.utils.Either;
import net.minestom.server.utils.validate.Check; import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import java.io.InputStream; import java.io.InputStream;
import java.nio.BufferUnderflowException; import java.nio.BufferUnderflowException;
@ -263,7 +263,7 @@ public class BinaryReader extends InputStream {
return buffer.readableBytes(); return buffer.readableBytes();
} }
public NBT readTag() { public BinaryTag readTag() {
return buffer.read(NBT); return buffer.read(NBT);
} }

View File

@ -1,5 +1,6 @@
package net.minestom.server.utils.binary; package net.minestom.server.utils.binary;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
@ -8,7 +9,6 @@ import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.Either; import net.minestom.server.utils.Either;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -167,7 +167,7 @@ public class BinaryWriter extends OutputStream {
this.buffer.write(ITEM, itemStack); this.buffer.write(ITEM, itemStack);
} }
public void writeNBT(@NotNull String name, @NotNull NBT tag) { public void writeNBT(@NotNull String name, @NotNull BinaryTag tag) {
this.buffer.write(NBT, tag); this.buffer.write(NBT, tag);
} }

View File

@ -1,16 +1,14 @@
package net.minestom.server.utils.block; package net.minestom.server.utils.block;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockHandler; import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.tag.Tag; import net.minestom.server.tag.Tag;
import net.minestom.server.utils.StringUtils; import net.minestom.server.utils.StringUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -90,22 +88,22 @@ public class BlockUtils {
return new Object2ObjectArrayMap<>(keys, values, entryCount); return new Object2ObjectArrayMap<>(keys, values, entryCount);
} }
public static @Nullable NBTCompound extractClientNbt(@NotNull Block block) { public static @Nullable CompoundBinaryTag extractClientNbt(@NotNull Block block) {
if (!block.registry().isBlockEntity()) return null; if (!block.registry().isBlockEntity()) return null;
// Append handler tags // Append handler tags
final BlockHandler handler = block.handler(); final BlockHandler handler = block.handler();
final NBTCompound blockNbt = Objects.requireNonNullElseGet(block.nbt(), NBTCompound::new); final CompoundBinaryTag blockNbt = Objects.requireNonNullElseGet(block.nbt(), CompoundBinaryTag::empty);
if (handler != null) { if (handler != null) {
// Extract explicitly defined tags and keep the rest server-side // Extract explicitly defined tags and keep the rest server-side
return NBT.Compound(nbt -> { var builder = CompoundBinaryTag.builder();
for (Tag<?> tag : handler.getBlockEntityTags()) { for (Tag<?> tag : handler.getBlockEntityTags()) {
final var value = tag.read(blockNbt); final var value = tag.read(blockNbt);
if (value != null) { if (value != null) {
// Tag is present and valid // Tag is present and valid
tag.writeUnsafe(nbt, value); tag.writeUnsafe(builder, value);
}
} }
}); }
return builder.build();
} }
// Complete nbt shall be sent if the block has no handler // Complete nbt shall be sent if the block has no handler
// Necessary to support all vanilla blocks // Necessary to support all vanilla blocks

View File

@ -1,13 +1,10 @@
package net.minestom.server.world; package net.minestom.server.world;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.mcdata.SizesKt;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -18,6 +15,9 @@ public class DimensionType {
private static final AtomicInteger idCounter = new AtomicInteger(0); private static final AtomicInteger idCounter = new AtomicInteger(0);
private static final int VANILLA_MIN_Y = -64;
private static final int VANILLA_MAX_Y = 319;
public static final DimensionType OVERWORLD = DimensionType.builder(NamespaceID.from("minecraft:overworld")) public static final DimensionType OVERWORLD = DimensionType.builder(NamespaceID.from("minecraft:overworld"))
.ultrawarm(false) .ultrawarm(false)
.natural(true) .natural(true)
@ -91,55 +91,56 @@ public class DimensionType {
return new DimensionTypeBuilder(); return new DimensionTypeBuilder();
} }
public static DimensionType fromNBT(NBTCompound nbt) { public static DimensionType fromNBT(CompoundBinaryTag nbt) {
return DimensionType.builder(NamespaceID.from(nbt.getString("name"))) return DimensionType.builder(NamespaceID.from(nbt.getString("name")))
.ambientLight(nbt.getFloat("ambient_light")) .ambientLight(nbt.getFloat("ambient_light"))
.infiniburn(NamespaceID.from(nbt.getString("infiniburn").replaceFirst("#", ""))) .infiniburn(NamespaceID.from(nbt.getString("infiniburn").replaceFirst("#", "")))
.natural(nbt.getByte("natural") != 0) .natural(nbt.getBoolean("natural"))
.ceilingEnabled(nbt.getByte("has_ceiling") != 0) .ceilingEnabled(nbt.getBoolean("has_ceiling"))
.skylightEnabled(nbt.getByte("has_skylight") != 0) .skylightEnabled(nbt.getBoolean("has_skylight"))
.ultrawarm(nbt.getByte("ultrawarm") != 0) .ultrawarm(nbt.getBoolean("ultrawarm"))
.raidCapable(nbt.getByte("has_raids") != 0) .raidCapable(nbt.getBoolean("has_raids"))
.respawnAnchorSafe(nbt.getByte("respawn_anchor_works") != 0) .respawnAnchorSafe(nbt.getBoolean("respawn_anchor_works"))
.bedSafe(nbt.getByte("bed_works") != 0) .bedSafe(nbt.getBoolean("bed_works"))
.effects(nbt.getString("effects")) .effects(nbt.getString("effects"))
.piglinSafe(nbt.getByte("piglin_safe") != 0) .piglinSafe(nbt.getBoolean("piglin_safe"))
.logicalHeight(nbt.getInt("logical_height")) .logicalHeight(nbt.getInt("logical_height"))
.coordinateScale(nbt.getDouble("coordinate_scale")) .coordinateScale(nbt.getDouble("coordinate_scale"))
.build(); .build();
} }
@NotNull @NotNull
public NBTCompound toIndexedNBT() { public CompoundBinaryTag toIndexedNBT() {
return NBT.Compound(Map.of( return CompoundBinaryTag.builder()
"name", NBT.String(name.toString()), .putString("name", name.toString())
"id", NBT.Int(id), .putInt("id", id)
"element", toNBT())); .put("element", toNBT())
.build();
} }
@NotNull @NotNull
public NBTCompound toNBT() { public CompoundBinaryTag toNBT() {
return NBT.Compound(nbt -> { CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
nbt.setFloat("ambient_light", ambientLight); builder.putFloat("ambient_light", ambientLight);
nbt.setString("infiniburn", "#" + infiniburn.toString()); builder.putString("infiniburn", "#" + infiniburn.toString());
nbt.setByte("natural", (byte) (natural ? 0x01 : 0x00)); builder.putByte("natural", (byte) (natural ? 0x01 : 0x00));
nbt.setByte("has_ceiling", (byte) (ceilingEnabled ? 0x01 : 0x00)); builder.putByte("has_ceiling", (byte) (ceilingEnabled ? 0x01 : 0x00));
nbt.setByte("has_skylight", (byte) (skylightEnabled ? 0x01 : 0x00)); builder.putByte("has_skylight", (byte) (skylightEnabled ? 0x01 : 0x00));
nbt.setByte("ultrawarm", (byte) (ultrawarm ? 0x01 : 0x00)); builder.putByte("ultrawarm", (byte) (ultrawarm ? 0x01 : 0x00));
nbt.setByte("has_raids", (byte) (raidCapable ? 0x01 : 0x00)); builder.putByte("has_raids", (byte) (raidCapable ? 0x01 : 0x00));
nbt.setByte("respawn_anchor_works", (byte) (respawnAnchorSafe ? 0x01 : 0x00)); builder.putByte("respawn_anchor_works", (byte) (respawnAnchorSafe ? 0x01 : 0x00));
nbt.setByte("bed_works", (byte) (bedSafe ? 0x01 : 0x00)); builder.putByte("bed_works", (byte) (bedSafe ? 0x01 : 0x00));
nbt.setString("effects", effects); builder.putString("effects", effects);
nbt.setByte("piglin_safe", (byte) (piglinSafe ? 0x01 : 0x00)); builder.putByte("piglin_safe", (byte) (piglinSafe ? 0x01 : 0x00));
nbt.setInt("min_y", minY); builder.putInt("min_y", minY);
nbt.setInt("height", height); builder.putInt("height", height);
nbt.setInt("logical_height", logicalHeight); builder.putInt("logical_height", logicalHeight);
nbt.setDouble("coordinate_scale", coordinateScale); builder.putDouble("coordinate_scale", coordinateScale);
nbt.setString("name", name.toString()); builder.putString("name", name.toString());
nbt.setInt("monster_spawn_block_light_limit", 0); builder.putInt("monster_spawn_block_light_limit", 0);
nbt.setInt("monster_spawn_light_level", 11); builder.putInt("monster_spawn_light_level", 11);
if (fixedTime != null) nbt.setLong("fixed_time", fixedTime); if (fixedTime != null) builder.putLong("fixed_time", fixedTime);
}); return builder.build();
} }
@Override @Override
@ -261,9 +262,9 @@ public class DimensionType {
private boolean bedSafe = true; private boolean bedSafe = true;
private String effects = "minecraft:overworld"; private String effects = "minecraft:overworld";
private boolean piglinSafe = false; private boolean piglinSafe = false;
private int minY = SizesKt.getVanillaMinY(); private int minY = VANILLA_MIN_Y;
private int logicalHeight = SizesKt.getVanillaMaxY() - SizesKt.getVanillaMinY() + 1; private int logicalHeight = VANILLA_MAX_Y - VANILLA_MIN_Y + 1;
private int height = SizesKt.getVanillaMaxY() - SizesKt.getVanillaMinY() + 1; private int height = VANILLA_MAX_Y - VANILLA_MIN_Y + 1;
private double coordinateScale = 1.0; private double coordinateScale = 1.0;
private NamespaceID infiniburn = NamespaceID.from("minecraft:infiniburn_overworld"); private NamespaceID infiniburn = NamespaceID.from("minecraft:infiniburn_overworld");

View File

@ -1,11 +1,11 @@
package net.minestom.server.world; package net.minestom.server.world;
import net.kyori.adventure.nbt.BinaryTagTypes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.ListBinaryTag;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -81,21 +81,19 @@ public final class DimensionTypeManager {
} }
/** /**
* Creates the {@link NBTCompound} containing all the registered dimensions. * Creates the {@link CompoundBinaryTag} containing all the registered dimensions.
* <p> * <p>
* Used when a player connects. * Used when a player connects.
* *
* @return an nbt compound containing the registered dimensions * @return an nbt compound containing the registered dimensions
*/ */
public @NotNull NBTCompound toNBT() { public @NotNull CompoundBinaryTag toNBT() {
return NBT.Compound(dimensions -> { ListBinaryTag.Builder<CompoundBinaryTag> entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
dimensions.setString("type", "minecraft:dimension_type"); for (DimensionType dimensionType : dimensionTypes)
dimensions.set("value", NBT.List( entries.add(dimensionType.toIndexedNBT());
NBTType.TAG_Compound, return CompoundBinaryTag.builder()
dimensionTypes.stream() .putString("type", "minecraft:dimension_type")
.map(DimensionType::toIndexedNBT) .put("value", entries.build())
.toList() .build();
));
});
} }
} }

View File

@ -1,5 +1,6 @@
package net.minestom.server.world.biomes; package net.minestom.server.world.biomes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.registry.ProtocolObject; import net.minestom.server.registry.ProtocolObject;
import net.minestom.server.registry.Registry; import net.minestom.server.registry.Registry;
@ -8,8 +9,6 @@ import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Locale; import java.util.Locale;
@ -54,18 +53,20 @@ sealed public interface Biome extends ProtocolObject permits BiomeImpl {
} }
} }
default @NotNull NBTCompound toNbt() { default @NotNull CompoundBinaryTag toNbt() {
Check.notNull(name(), "The biome namespace cannot be null"); Check.notNull(name(), "The biome namespace cannot be null");
Check.notNull(effects(), "The biome effects cannot be null"); Check.notNull(effects(), "The biome effects cannot be null");
return NBT.Compound(element -> { CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
element.setFloat("temperature", temperature()); .putFloat("temperature", temperature())
element.setFloat("downfall", downfall()); .putFloat("downfall", downfall())
element.setByte("has_precipitation", (byte) (precipitation() == Precipitation.NONE ? 0 : 1)); .putByte("has_precipitation", (byte) (precipitation() == Precipitation.NONE ? 0 : 1))
if (temperatureModifier() != TemperatureModifier.NONE) .putString("precipitation", precipitation().name().toLowerCase(Locale.ROOT));
element.setString("temperature_modifier", temperatureModifier().name().toLowerCase(Locale.ROOT)); if (temperatureModifier() != TemperatureModifier.NONE)
element.set("effects", effects().toNbt()); builder.putString("temperature_modifier", temperatureModifier().name().toLowerCase(Locale.ROOT));
}); return builder
.put("effects", effects().toNbt())
.build();
} }
static @NotNull Builder builder() { static @NotNull Builder builder() {

View File

@ -1,12 +1,10 @@
package net.minestom.server.world.biomes; package net.minestom.server.world.biomes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
public record BiomeEffects(int fogColor, int skyColor, int waterColor, int waterFogColor, int foliageColor, public record BiomeEffects(int fogColor, int skyColor, int waterColor, int waterFogColor, int foliageColor,
int grassColor, int grassColor,
@ -18,29 +16,29 @@ public record BiomeEffects(int fogColor, int skyColor, int waterColor, int water
return new Builder(); return new Builder();
} }
public NBTCompound toNbt() { public CompoundBinaryTag toNbt() {
return NBT.Compound(nbt -> { var builder = CompoundBinaryTag.builder();
nbt.setInt("fog_color", fogColor); builder.putInt("fog_color", fogColor);
if (foliageColor != -1) if (foliageColor != -1)
nbt.setInt("foliage_color", foliageColor); builder.putInt("foliage_color", foliageColor);
if (grassColor != -1) if (grassColor != -1)
nbt.setInt("grass_color", grassColor); builder.putInt("grass_color", grassColor);
nbt.setInt("sky_color", skyColor); builder.putInt("sky_color", skyColor);
nbt.setInt("water_color", waterColor); builder.putInt("water_color", waterColor);
nbt.setInt("water_fog_color", waterFogColor); builder.putInt("water_fog_color", waterFogColor);
if (grassColorModifier != null) if (grassColorModifier != null)
nbt.setString("grass_color_modifier", grassColorModifier.name().toLowerCase(Locale.ROOT)); builder.putString("grass_color_modifier", grassColorModifier.name().toLowerCase(Locale.ROOT));
if (biomeParticle != null) if (biomeParticle != null)
nbt.set("particle", biomeParticle.toNbt()); builder.put("particle", biomeParticle.toNbt());
if (ambientSound != null) if (ambientSound != null)
nbt.setString("ambient_sound", ambientSound.toString()); builder.putString("ambient_sound", ambientSound.toString());
if (moodSound != null) if (moodSound != null)
nbt.set("mood_sound", moodSound.toNbt()); builder.put("mood_sound", moodSound.toNbt());
if (additionsSound != null) if (additionsSound != null)
nbt.set("additions_sound", additionsSound.toNbt()); builder.put("additions_sound", additionsSound.toNbt());
if (music != null) if (music != null)
nbt.set("music", music.toNbt()); builder.put("music", music.toNbt());
}); return builder.build();
} }
public enum GrassColorModifier { public enum GrassColorModifier {
@ -48,30 +46,33 @@ public record BiomeEffects(int fogColor, int skyColor, int waterColor, int water
} }
public record MoodSound(NamespaceID sound, int tickDelay, int blockSearchExtent, double offset) { public record MoodSound(NamespaceID sound, int tickDelay, int blockSearchExtent, double offset) {
public @NotNull NBTCompound toNbt() { public @NotNull CompoundBinaryTag toNbt() {
return NBT.Compound(Map.of( return CompoundBinaryTag.builder()
"sound", NBT.String(sound.toString()), .putString("sound", sound.toString())
"tick_delay", NBT.Int(tickDelay), .putInt("tick_delay", tickDelay)
"block_search_extent", NBT.Int(blockSearchExtent), .putInt("block_search_extent", blockSearchExtent)
"offset", NBT.Double(offset))); .putDouble("offset", offset)
.build();
} }
} }
public record AdditionsSound(NamespaceID sound, double tickChance) { public record AdditionsSound(NamespaceID sound, double tickChance) {
public @NotNull NBTCompound toNbt() { public @NotNull CompoundBinaryTag toNbt() {
return NBT.Compound(Map.of( return CompoundBinaryTag.builder()
"sound", NBT.String(sound.toString()), .putString("sound", sound.toString())
"tick_chance", NBT.Double(tickChance))); .putDouble("tick_chance", tickChance)
.build();
} }
} }
public record Music(NamespaceID sound, int minDelay, int maxDelay, boolean replaceCurrentMusic) { public record Music(NamespaceID sound, int minDelay, int maxDelay, boolean replaceCurrentMusic) {
public @NotNull NBTCompound toNbt() { public @NotNull CompoundBinaryTag toNbt() {
return NBT.Compound(Map.of( return CompoundBinaryTag.builder()
"sound", NBT.String(sound.toString()), .putString("sound", sound.toString())
"min_delay", NBT.Int(minDelay), .putInt("min_delay", minDelay)
"max_delay", NBT.Int(maxDelay), .putInt("max_delay", maxDelay)
"replace_current_music", NBT.Boolean(replaceCurrentMusic))); .putBoolean("replace_current_music", replaceCurrentMusic)
.build();
} }
} }

View File

@ -1,12 +1,12 @@
package net.minestom.server.world.biomes; package net.minestom.server.world.biomes;
import net.kyori.adventure.nbt.BinaryTagTypes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.ListBinaryTag;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.validate.Check; import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -25,7 +25,7 @@ public final class BiomeManager {
private final Map<NamespaceID, Integer> idMappings = new ConcurrentHashMap<>(); private final Map<NamespaceID, Integer> idMappings = new ConcurrentHashMap<>();
private final AtomicInteger ID_COUNTER = new AtomicInteger(0); private final AtomicInteger ID_COUNTER = new AtomicInteger(0);
private NBTCompound nbtCache = null; private CompoundBinaryTag nbtCache = null;
public BiomeManager() { public BiomeManager() {
// Need to register plains for the client to work properly // Need to register plains for the client to work properly
@ -101,18 +101,21 @@ public final class BiomeManager {
return getByName(namespace); return getByName(namespace);
} }
public @NotNull NBTCompound toNBT() { public @NotNull CompoundBinaryTag toNBT() {
if (nbtCache != null) return nbtCache; if (nbtCache != null) return nbtCache;
nbtCache = NBT.Compound(Map.of(
"type", NBT.String("minecraft:worldgen/biome"),
"value", NBT.List(NBTType.TAG_Compound, biomes.values().stream().map(biome -> {
return NBT.Compound(Map.of(
"id", NBT.Int(getId(biome)),
"name", NBT.String(biome.namespace().toString()),
"element", biome.toNbt()
));
}).toList())));
ListBinaryTag.Builder<CompoundBinaryTag> entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
for (Biome biome : biomes.values()) {
entries.add(CompoundBinaryTag.builder()
.putInt("id", getId(biome))
.putString("name", biome.namespace().toString())
.put("element", biome.toNbt())
.build());
}
nbtCache = CompoundBinaryTag.builder()
.putString("type", "minecraft:worldgen/biome")
.put("value", entries.build())
.build();
return nbtCache; return nbtCache;
} }

View File

@ -1,22 +1,22 @@
package net.minestom.server.world.biomes; package net.minestom.server.world.biomes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Map; import java.util.Map;
public record BiomeParticle(float probability, Option option) { public record BiomeParticle(float probability, Option option) {
public NBTCompound toNbt() { public CompoundBinaryTag toNbt() {
return NBT.Compound(Map.of( return CompoundBinaryTag.builder()
"probability", NBT.Float(probability), .putFloat("probability", probability)
"options", option.toNbt())); .put("options", option.toNbt())
.build();
} }
public interface Option { public interface Option {
NBTCompound toNbt(); CompoundBinaryTag toNbt();
} }
public record BlockOption(Block block) implements Option { public record BlockOption(Block block) implements Option {
@ -24,15 +24,17 @@ public record BiomeParticle(float probability, Option option) {
private static final String type = "block"; private static final String type = "block";
@Override @Override
public NBTCompound toNbt() { public CompoundBinaryTag toNbt() {
return NBT.Compound(nbtCompound -> { CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
nbtCompound.setString("type", type); builder.putString("type", type);
nbtCompound.setString("Name", block.name()); builder.putString("Name", block.name());
Map<String, String> propertiesMap = block.properties(); Map<String, String> propertiesMap = block.properties();
if (propertiesMap.size() != 0) { if (!propertiesMap.isEmpty()) {
nbtCompound.set("Properties", NBT.Compound(p -> propertiesMap.forEach(p::setString))); CompoundBinaryTag.Builder properties = CompoundBinaryTag.builder();
} propertiesMap.forEach(properties::putString);
}); builder.put("Properties", properties.build());
}
return builder.build();
} }
} }
@ -40,13 +42,14 @@ public record BiomeParticle(float probability, Option option) {
private static final String type = "dust"; private static final String type = "dust";
@Override @Override
public NBTCompound toNbt() { public CompoundBinaryTag toNbt() {
return NBT.Compound(Map.of( return CompoundBinaryTag.builder()
"type", NBT.String(type), .putString("type", type)
"r", NBT.Float(red), .putFloat("r", red)
"g", NBT.Float(green), .putFloat("g", green)
"b", NBT.Float(blue), .putFloat("b", blue)
"scale", NBT.Float(scale))); .putFloat("scale", scale)
.build();
} }
} }
@ -54,17 +57,19 @@ public record BiomeParticle(float probability, Option option) {
private static final String type = "item"; private static final String type = "item";
@Override @Override
public NBTCompound toNbt() { public CompoundBinaryTag toNbt() {
//todo test count might be wrong type //todo test count might be wrong type
NBTCompound nbtCompound = item.meta().toNBT(); return item.meta().toNBT()
return nbtCompound.modify(n -> n.setString("type", type)); .putString("type", type);
} }
} }
public record NormalOption(NamespaceID type) implements Option { public record NormalOption(NamespaceID type) implements Option {
@Override @Override
public NBTCompound toNbt() { public CompoundBinaryTag toNbt() {
return NBT.Compound(Map.of("type", NBT.String(type.toString()))); return CompoundBinaryTag.builder()
.putString("type", type.toString())
.build();
} }
} }
} }