From 687968eea06cf6c6365f1b706f0b126fcfcb65c5 Mon Sep 17 00:00:00 2001 From: mworzala Date: Sun, 17 Mar 2024 16:07:29 -0400 Subject: [PATCH] feat: initial conversion to adventure nbt. no tests, no anvil --- build.gradle.kts | 3 - .../minestom/demo/block/CampfireHandler.java | 31 +- gradle/libs.versions.toml | 14 +- .../server/adventure/MinestomAdventure.java | 13 +- .../NBTLegacyHoverEventSerializer.java | 91 +- .../nbt/NbtComponentSerializer.java | 4 +- .../nbt/NbtComponentSerializerImpl.java | 233 +++-- .../minecraft/ArgumentItemStack.java | 13 +- .../minecraft/ArgumentNbtCompoundTag.java | 23 +- .../arguments/minecraft/ArgumentNbtTag.java | 21 +- .../net/minestom/server/entity/Metadata.java | 4 +- .../minestom/server/entity/MetadataImpl.java | 4 +- .../server/entity/damage/DamageType.java | 8 +- .../server/entity/damage/DamageTypeImpl.java | 47 +- .../server/entity/metadata/PlayerMeta.java | 17 +- .../minestom/server/instance/AnvilLoader.java | 797 +++++++++--------- .../server/instance/DynamicChunk.java | 14 +- .../server/instance/ExplosionSupplier.java | 6 +- .../minestom/server/instance/Instance.java | 4 +- .../server/instance/InstanceContainer.java | 4 +- .../server/instance/LightingChunk.java | 15 +- .../minestom/server/instance/block/Block.java | 8 +- .../server/instance/block/BlockImpl.java | 19 +- .../net/minestom/server/item/ItemMeta.java | 4 +- .../minestom/server/item/ItemMetaImpl.java | 20 +- .../net/minestom/server/item/ItemStack.java | 24 +- .../minestom/server/item/ItemStackImpl.java | 21 +- .../server/item/armor/TrimManager.java | 53 +- .../server/item/armor/TrimMaterial.java | 6 +- .../server/item/armor/TrimMaterialImpl.java | 26 +- .../server/item/armor/TrimPattern.java | 6 +- .../server/item/armor/TrimPatternImpl.java | 17 +- .../server/item/firework/FireworkEffect.java | 41 +- .../server/item/metadata/PlayerHeadMeta.java | 24 +- .../listener/PlayerDiggingListener.java | 4 +- .../minestom/server/message/Messenger.java | 17 +- .../server/network/ConnectionManager.java | 21 +- .../server/network/NetworkBuffer.java | 12 +- .../configuration/RegistryDataPacket.java | 6 +- .../server/play/BlockEntityDataPacket.java | 6 +- .../server/play/EntityEffectPacket.java | 6 +- .../server/play/NbtQueryResponsePacket.java | 7 +- .../packet/server/play/data/ChunkData.java | 10 +- .../server/permission/Permission.java | 10 +- .../server/permission/PermissionHandler.java | 5 +- .../server/permission/PermissionVerifier.java | 6 +- .../net/minestom/server/tag/Serializers.java | 47 +- .../java/net/minestom/server/tag/Tag.java | 58 +- .../net/minestom/server/tag/TagHandler.java | 17 +- .../minestom/server/tag/TagHandlerImpl.java | 72 +- .../minestom/server/tag/TagNbtSeparator.java | 48 +- .../net/minestom/server/tag/TagRecord.java | 8 +- .../minestom/server/tag/TagSerializer.java | 8 +- .../server/tag/TagSerializerImpl.java | 14 +- .../net/minestom/server/utils/NBTUtils.java | 59 ++ .../server/utils/binary/BinaryBuffer.java | 4 - .../server/utils/binary/BinaryReader.java | 4 +- .../server/utils/binary/BinaryWriter.java | 4 +- .../server/utils/block/BlockUtils.java | 24 +- .../minestom/server/world/DimensionType.java | 87 +- .../server/world/DimensionTypeManager.java | 26 +- .../minestom/server/world/biomes/Biome.java | 23 +- .../server/world/biomes/BiomeEffects.java | 85 +- .../server/world/biomes/BiomeManager.java | 31 +- .../server/world/biomes/BiomeParticle.java | 61 +- 65 files changed, 1195 insertions(+), 1230 deletions(-) create mode 100644 src/main/java/net/minestom/server/utils/NBTUtils.java diff --git a/build.gradle.kts b/build.gradle.kts index 7140bb97d..b1916f02d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -72,10 +72,7 @@ dependencies { api(libs.jetbrainsAnnotations) api(libs.bundles.adventure) api(libs.hydrazine) - api(libs.bundles.kotlin) - api(libs.bundles.hephaistos) implementation(libs.minestomData) - implementation(libs.dependencyGetter) // Performance/data structures implementation(libs.caffeine) diff --git a/demo/src/main/java/net/minestom/demo/block/CampfireHandler.java b/demo/src/main/java/net/minestom/demo/block/CampfireHandler.java index c399993e3..663c10914 100644 --- a/demo/src/main/java/net/minestom/demo/block/CampfireHandler.java +++ b/demo/src/main/java/net/minestom/demo/block/CampfireHandler.java @@ -1,5 +1,9 @@ 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.item.ItemStack; import net.minestom.server.item.Material; @@ -10,10 +14,6 @@ import net.minestom.server.tag.TagWritable; import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.NotNull; 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.Collection; @@ -22,16 +22,17 @@ import java.util.List; public class CampfireHandler implements BlockHandler { public static final Tag> ITEMS = Tag.View(new TagSerializer<>() { - private final Tag internal = Tag.NBT("Items"); + private final Tag internal = Tag.NBT("Items"); @Override public @Nullable List read(@NotNull TagReadable reader) { - NBTList item = (NBTList) reader.getTag(internal); + ListBinaryTag item = (ListBinaryTag) reader.getTag(internal); if (item == null) return null; List result = new ArrayList<>(); - item.forEach(nbtCompound -> { - int amount = nbtCompound.getAsByte("Count"); + item.forEach(childTag -> { + CompoundBinaryTag nbtCompound = (CompoundBinaryTag) childTag; + int amount = nbtCompound.getByte("Count"); String id = nbtCompound.getString("id"); Material material = Material.fromNamespaceId(id); result.add(ItemStack.of(material, amount)); @@ -45,14 +46,14 @@ public class CampfireHandler implements BlockHandler { writer.removeTag(internal); return; } - writer.setTag(internal, NBT.List( - NBTType.TAG_Compound, + writer.setTag(internal, ListBinaryTag.listBinaryTag( + BinaryTagTypes.COMPOUND, value.stream() - .map(item -> NBT.Compound(nbt -> { - nbt.setByte("Count", (byte) item.amount()); - nbt.setByte("Slot", (byte) 1); - nbt.setString("id", item.material().name()); - })) + .map(item -> (BinaryTag) CompoundBinaryTag.builder() + .putByte("Count", (byte) item.amount()) + .putByte("Slot", (byte) 1) + .putString("id", item.material().name()) + .build()) .toList() )); } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fb1a5af9d..8230be930 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,7 +4,7 @@ metadata.format.version = "1.1" # Important dependencies data = "1.20.4-rv4" -adventure = "4.15.0" +adventure = "4.16.0" kotlin = "1.7.22" dependencyGetter = "v1.0.1" hydrazine = "1.7.2" @@ -41,22 +41,16 @@ nexuspublish = "1.3.0" # Important Dependencies # 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-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-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 hydrazine = { group = "com.github.MadMartian", name = "hydrazine-path-finding", version.ref = "hydrazine" } 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" } -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"} # Performance / Data Structures @@ -86,11 +80,9 @@ logback-classic = { group = "ch.qos.logback", name = "logback-classic", version. [bundles] -kotlin = ["kotlin-stdlib-jdk8", "kotlin-reflect"] 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"] -hephaistos = ["hephaistos-common", "hephaistos-gson"] logback = ["logback-core", "logback-classic"] [plugins] diff --git a/src/main/java/net/minestom/server/adventure/MinestomAdventure.java b/src/main/java/net/minestom/server/adventure/MinestomAdventure.java index fe62f85e6..10ffcdfa7 100644 --- a/src/main/java/net/minestom/server/adventure/MinestomAdventure.java +++ b/src/main/java/net/minestom/server/adventure/MinestomAdventure.java @@ -1,21 +1,18 @@ 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.translation.GlobalTranslator; import net.kyori.adventure.util.Codec; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.IOException; import java.util.Locale; import java.util.Objects; 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. */ @@ -23,8 +20,8 @@ public final class MinestomAdventure { /** * A codec to convert between strings and NBT. */ - public static final Codec NBT_CODEC - = Codec.codec(encoded -> new SNBTParser(new StringReader(encoded)).parse(), NBT::toSNBT); + public static final Codec NBT_CODEC + = Codec.codec(TagStringIO.get()::asCompound, TagStringIO.get()::asString); /** * If components should be automatically translated in outgoing packets. diff --git a/src/main/java/net/minestom/server/adventure/provider/NBTLegacyHoverEventSerializer.java b/src/main/java/net/minestom/server/adventure/provider/NBTLegacyHoverEventSerializer.java index 690592629..12770ffe6 100644 --- a/src/main/java/net/minestom/server/adventure/provider/NBTLegacyHoverEventSerializer.java +++ b/src/main/java/net/minestom/server/adventure/provider/NBTLegacyHoverEventSerializer.java @@ -1,6 +1,7 @@ package net.minestom.server.adventure.provider; import net.kyori.adventure.key.Key; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.nbt.api.BinaryTagHolder; import net.kyori.adventure.text.Component; 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.minestom.server.adventure.MinestomAdventure; 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.util.Objects; import java.util.UUID; -import java.util.concurrent.atomic.AtomicReference; final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer { static final NBTLegacyHoverEventSerializer INSTANCE = new NBTLegacyHoverEventSerializer(); @@ -30,76 +27,46 @@ final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer @Override public HoverEvent.@NotNull ShowItem deserializeShowItem(@NotNull Component input) throws IOException { final String raw = PlainTextComponentSerializer.plainText().serialize(input); - try { - // attempt the parse - final NBT nbt = MinestomAdventure.NBT_CODEC.decode(raw); - if (!(nbt instanceof NBTCompound contents)) throw new IOException("contents were not a compound"); - final NBTCompound tag = contents.getCompound(ITEM_TAG); + // attempt the parse + final CompoundBinaryTag contents = MinestomAdventure.NBT_CODEC.decode(raw); + final CompoundBinaryTag tag = contents.getCompound(ITEM_TAG); - // create the event - return HoverEvent.ShowItem.showItem( - Key.key(Objects.requireNonNullElse(contents.getString(ITEM_TYPE), "")), - Objects.requireNonNullElse(contents.getByte(ITEM_COUNT), (byte) 1), - tag == null ? null : BinaryTagHolder.encode(tag, MinestomAdventure.NBT_CODEC) - ); - } catch (final NBTException e) { - throw new IOException(e); - } + // create the event + return HoverEvent.ShowItem.showItem( + Key.key(contents.getString(ITEM_TYPE, "")), + contents.getByte(ITEM_COUNT, (byte) 1), + tag.size() == 0 ? null : BinaryTagHolder.encode(tag, MinestomAdventure.NBT_CODEC) + ); } @Override public HoverEvent.@NotNull ShowEntity deserializeShowEntity(@NotNull Component input, Codec.Decoder componentDecoder) throws IOException { final String raw = PlainTextComponentSerializer.plainText().serialize(input); - try { - final NBT nbt = MinestomAdventure.NBT_CODEC.decode(raw); - if (!(nbt instanceof NBTCompound contents)) throw new IOException("contents were not a compound"); - - return HoverEvent.ShowEntity.showEntity( - 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); - } + final CompoundBinaryTag contents = MinestomAdventure.NBT_CODEC.decode(raw); + return HoverEvent.ShowEntity.showEntity( + Key.key(contents.getString(ENTITY_TYPE, "")), + UUID.fromString(Objects.requireNonNullElse(contents.getString(ENTITY_ID), "")), + componentDecoder.decode(Objects.requireNonNullElse(contents.getString(ENTITY_NAME), "")) + ); } @Override public @NotNull Component serializeShowItem(HoverEvent.@NotNull ShowItem input) throws IOException { - AtomicReference exception = new AtomicReference<>(null); - final NBTCompound tag = NBT.Compound(t -> { - t.setString(ITEM_TYPE, input.item().asString()); - t.setByte(ITEM_COUNT, (byte) input.count()); - - final BinaryTagHolder nbt = input.nbt(); - 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)); + CompoundBinaryTag.Builder tag = CompoundBinaryTag.builder(); + tag.putString(ITEM_TYPE, input.item().asString()); + tag.putByte(ITEM_COUNT, (byte) input.count()); + final BinaryTagHolder nbt = input.nbt(); + if (nbt != null) tag.put(ITEM_TAG, nbt.get(MinestomAdventure.NBT_CODEC)); + return Component.text(MinestomAdventure.NBT_CODEC.encode(tag.build())); } @Override - public @NotNull Component serializeShowEntity(HoverEvent.@NotNull ShowEntity input, Codec.Encoder componentEncoder) { - final NBTCompound tag = NBT.Compound(t -> { - t.setString(ENTITY_ID, input.id().toString()); - t.setString(ENTITY_TYPE, input.type().asString()); - - final Component name = input.name(); - if (name != null) { - t.setString(ENTITY_NAME, componentEncoder.encode(name)); - } - }); - - return Component.text(MinestomAdventure.NBT_CODEC.encode(tag)); + public @NotNull Component serializeShowEntity(HoverEvent.@NotNull ShowEntity input, Codec.Encoder componentEncoder) throws IOException { + CompoundBinaryTag.Builder tag = CompoundBinaryTag.builder(); + tag.putString(ENTITY_ID, input.id().toString()); + tag.putString(ENTITY_TYPE, input.type().asString()); + final Component name = input.name(); + if (name != null) tag.putString(ENTITY_NAME, componentEncoder.encode(name)); + return Component.text(MinestomAdventure.NBT_CODEC.encode(tag.build())); } } diff --git a/src/main/java/net/minestom/server/adventure/serializer/nbt/NbtComponentSerializer.java b/src/main/java/net/minestom/server/adventure/serializer/nbt/NbtComponentSerializer.java index a397352e9..e707655ae 100644 --- a/src/main/java/net/minestom/server/adventure/serializer/nbt/NbtComponentSerializer.java +++ b/src/main/java/net/minestom/server/adventure/serializer/nbt/NbtComponentSerializer.java @@ -1,11 +1,11 @@ package net.minestom.server.adventure.serializer.nbt; +import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.ComponentSerializer; import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBT; -public interface NbtComponentSerializer extends ComponentSerializer { +public interface NbtComponentSerializer extends ComponentSerializer { static @NotNull NbtComponentSerializer nbt() { return NbtComponentSerializerImpl.INSTANCE; } diff --git a/src/main/java/net/minestom/server/adventure/serializer/nbt/NbtComponentSerializerImpl.java b/src/main/java/net/minestom/server/adventure/serializer/nbt/NbtComponentSerializerImpl.java index 5920920c5..b459b05da 100644 --- a/src/main/java/net/minestom/server/adventure/serializer/nbt/NbtComponentSerializerImpl.java +++ b/src/main/java/net/minestom/server/adventure/serializer/nbt/NbtComponentSerializerImpl.java @@ -1,6 +1,7 @@ package net.minestom.server.adventure.serializer.nbt; import net.kyori.adventure.key.Key; +import net.kyori.adventure.nbt.*; import net.kyori.adventure.nbt.api.BinaryTagHolder; import net.kyori.adventure.text.*; 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 org.intellij.lang.annotations.Subst; 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.Collection; +import java.util.Set; import java.util.UUID; //todo write tests for me!! @@ -27,19 +24,19 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer { static final NbtComponentSerializer INSTANCE = new NbtComponentSerializerImpl(); @Override - public @NotNull Component deserialize(@NotNull NBT input) { + public @NotNull Component deserialize(@NotNull BinaryTag input) { return deserializeAnyComponent(input); } @Override - public @NotNull NBT serialize(@NotNull Component component) { + public @NotNull BinaryTag serialize(@NotNull Component component) { return serializeComponent(component); } // DESERIALIZATION - private @NotNull Component deserializeAnyComponent(@NotNull NBT nbt) { - if (nbt instanceof NBTCompound compound) { + private @NotNull Component deserializeAnyComponent(@NotNull BinaryTag nbt) { + if (nbt instanceof CompoundBinaryTag compound) { return deserializeComponent(compound); } else { //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; - var type = compound.getString("type"); - if (type != null) { + var type = compound.get("type"); + if (type instanceof StringBinaryTag sType) { // If type is specified, use that - builder = switch (type) { + builder = switch (sType.value()) { case "text" -> deserializeTextComponent(compound); case "translatable" -> deserializeTranslatableComponent(compound); case "score" -> deserializeScoreComponent(compound); @@ -63,26 +60,25 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer { }; } else { // Try to infer the type from the fields present. - if (compound.containsKey("text")) { + Set keys = compound.keySet(); + if (keys.contains("text")) { builder = deserializeTextComponent(compound); - } else if (compound.containsKey("translate")) { + } else if (keys.contains("translate")) { builder = deserializeTranslatableComponent(compound); - } else if (compound.containsKey("score")) { + } else if (keys.contains("score")) { builder = deserializeScoreComponent(compound); - } else if (compound.containsKey("selector")) { + } else if (keys.contains("selector")) { builder = deserializeSelectorComponent(compound); - } else if (compound.containsKey("keybind")) { + } else if (keys.contains("keybind")) { builder = deserializeKeybindComponent(compound); - } else if (compound.containsKey("nbt")) { + } else if (keys.contains("nbt")) { builder = deserializeNbtComponent(compound); } else throw new UnsupportedOperationException("Unable to infer component type"); } // Children - var extra = compound.getList("extra"); - Check.argCondition(extra != null && !extra.getSubtagType().equals(NBTType.TAG_Compound), - "Extra field must be a list of compounds"); - if (extra != null) { + var extra = compound.getList("extra", BinaryTagTypes.COMPOUND); + if (extra.size() > 0) { var list = new ArrayList(); for (var child : extra) list.add(deserializeAnyComponent(child)); builder.append(list); @@ -91,7 +87,7 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer { // Formatting var style = Style.style(); var color = compound.getString("color"); - if (color != null) { + if (!color.isEmpty()) { var hexColor = TextColor.fromHexString(color); if (hexColor != null) { style.color(hexColor); @@ -105,57 +101,60 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer { } } @Subst("minecraft:default") var font = compound.getString("font"); - if (font != null) style.font(Key.key(font)); - var bold = compound.getByte("bold"); - if (bold != null) style.decoration(TextDecoration.BOLD, bold == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE); - var italic = compound.getByte("italic"); - if (italic != null) style.decoration(TextDecoration.ITALIC, italic == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE); - var underlined = compound.getByte("underlined"); - if (underlined != null) style.decoration(TextDecoration.UNDERLINED, underlined == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE); - var strikethrough = compound.getByte("strikethrough"); - if (strikethrough != null) style.decoration(TextDecoration.STRIKETHROUGH, strikethrough == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE); - var obfuscated = compound.getByte("obfuscated"); - if (obfuscated != null) style.decoration(TextDecoration.OBFUSCATED, obfuscated == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE); + if (!font.isEmpty()) style.font(Key.key(font)); + BinaryTag bold = compound.get("bold"); + if (bold instanceof ByteBinaryTag b) + style.decoration(TextDecoration.BOLD, b.value() == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE); + BinaryTag italic = compound.get("italic"); + if (italic instanceof ByteBinaryTag b) + style.decoration(TextDecoration.ITALIC, b.value() == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE); + BinaryTag underlined = compound.get("underlined"); + if (underlined instanceof ByteBinaryTag b) + style.decoration(TextDecoration.UNDERLINED, b.value() == 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()); // Interactivity var insertion = compound.getString("insertion"); - if (insertion != null) builder.insertion(insertion); + if (!insertion.isEmpty()) builder.insertion(insertion); 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"); - if (hoverEvent != null) builder.hoverEvent(deserializeHoverEvent(hoverEvent)); + if (hoverEvent.size() > 0) builder.hoverEvent(deserializeHoverEvent(hoverEvent)); return builder.build(); } - private @NotNull ComponentBuilder deserializeTextComponent(@NotNull NBTCompound compound) { + private @NotNull ComponentBuilder deserializeTextComponent(@NotNull CompoundBinaryTag compound) { var text = compound.getString("text"); Check.notNull(text, "Text component must have a text field"); return Component.text().content(text); } - private @NotNull ComponentBuilder deserializeTranslatableComponent(@NotNull NBTCompound compound) { + private @NotNull ComponentBuilder deserializeTranslatableComponent(@NotNull CompoundBinaryTag compound) { var key = compound.getString("translate"); Check.notNull(key, "Translatable component must have a translate field"); var builder = Component.translatable().key(key); - var fallback = compound.getString("fallback"); - if (fallback != null) builder.fallback(fallback); + var fallback = compound.get("fallback"); + if (fallback instanceof StringBinaryTag s) builder.fallback(s.value()); - NBTList args = compound.getList("with"); - Check.argCondition(args != null && !args.getSubtagType().equals(NBTType.TAG_Compound), - "Translatable component with field must be a list of compounds"); - if (args != null) { + ListBinaryTag args = compound.getList("with", BinaryTagTypes.COMPOUND); + if (args.size() > 0) { var list = new ArrayList(); - for (var arg : args) list.add(deserializeComponent(arg)); + for (var arg : args) list.add(deserializeComponent((CompoundBinaryTag) arg)); builder.arguments(list); } return builder; } - private @NotNull ComponentBuilder deserializeScoreComponent(@NotNull NBTCompound compound) { + private @NotNull ComponentBuilder deserializeScoreComponent(@NotNull CompoundBinaryTag compound) { var scoreCompound = compound.getCompound("score"); Check.notNull(scoreCompound, "Score component must have a score field"); var name = scoreCompound.getString("name"); @@ -165,14 +164,14 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer { var builder = Component.score().name(name).objective(objective); var value = scoreCompound.getString("value"); - if (value != null) + if (!value.isEmpty()) //noinspection deprecation builder.value(value); return builder; } - private @NotNull ComponentBuilder deserializeSelectorComponent(@NotNull NBTCompound compound) { + private @NotNull ComponentBuilder deserializeSelectorComponent(@NotNull CompoundBinaryTag compound) { var selector = compound.getString("selector"); Check.notNull(selector, "Selector component must have a selector field"); var builder = Component.selector().pattern(selector); @@ -183,17 +182,17 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer { return builder; } - private @NotNull ComponentBuilder deserializeKeybindComponent(@NotNull NBTCompound compound) { + private @NotNull ComponentBuilder deserializeKeybindComponent(@NotNull CompoundBinaryTag compound) { var keybind = compound.getString("keybind"); Check.notNull(keybind, "Keybind component must have a keybind field"); 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"); } - private @NotNull ClickEvent deserializeClickEvent(@NotNull NBTCompound compound) { + private @NotNull ClickEvent deserializeClickEvent(@NotNull CompoundBinaryTag compound) { var actionName = compound.getString("action"); Check.notNull(actionName, "Click event must have an action field"); var action = ClickEvent.Action.NAMES.value(actionName); @@ -203,7 +202,7 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer { return ClickEvent.clickEvent(action, value); } - private @NotNull HoverEvent deserializeHoverEvent(@NotNull NBTCompound compound) { + private @NotNull HoverEvent deserializeHoverEvent(@NotNull CompoundBinaryTag compound) { var actionName = compound.getString("action"); Check.notNull(actionName, "Hover event must have an action field"); var contents = compound.getCompound("contents"); @@ -216,13 +215,12 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer { @Subst("minecraft:stick") var id = contents.getString("id"); Check.notNull(id, "Show item hover event must have an id field"); var count = contents.getInt("count"); - var countInt = count == null ? 1 : count; var tag = contents.getString("tag"); - var binaryTag = tag == null ? null : BinaryTagHolder.binaryTagHolder(tag); - return HoverEvent.showItem(Key.key(id), countInt, binaryTag); + var binaryTag = tag.isEmpty() ? null : BinaryTagHolder.binaryTagHolder(tag); + return HoverEvent.showItem(Key.key(id), count, binaryTag); } else if (action == HoverEvent.Action.SHOW_ENTITY) { 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"); Check.notNull(type, "Show entity hover event must have a type field"); var id = contents.getString("id"); @@ -235,36 +233,36 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer { // SERIALIZATION - private @NotNull NBT serializeComponent(@NotNull Component component) { - MutableNBTCompound compound = new MutableNBTCompound(); + private @NotNull CompoundBinaryTag serializeComponent(@NotNull Component component) { + CompoundBinaryTag.Builder compound = CompoundBinaryTag.builder(); // Base component types if (component instanceof TextComponent text) { - compound.setString("type", "text"); - compound.setString("text", text.content()); + compound.putString("type", "text"); + compound.putString("text", text.content()); } else if (component instanceof TranslatableComponent translatable) { - compound.setString("type", "translatable"); - compound.setString("translate", translatable.key()); + compound.putString("type", "translatable"); + compound.putString("translate", translatable.key()); var fallback = translatable.fallback(); - if (fallback != null) compound.setString("fallback", fallback); + if (fallback != null) compound.putString("fallback", fallback); 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) { - compound.setString("type", "score"); - var scoreCompound = new MutableNBTCompound(); - scoreCompound.setString("name", score.name()); - scoreCompound.setString("objective", score.objective()); + compound.putString("type", "score"); + CompoundBinaryTag.Builder scoreCompound = CompoundBinaryTag.builder(); + scoreCompound.putString("name", score.name()); + scoreCompound.putString("objective", score.objective()); @SuppressWarnings("deprecation") var value = score.value(); - if (value != null) scoreCompound.setString("value", value); - compound.set("score", scoreCompound.toCompound()); + if (value != null) scoreCompound.putString("value", value); + compound.put("score", scoreCompound.build()); } else if (component instanceof SelectorComponent selector) { - compound.setString("type", "selector"); - compound.setString("selector", selector.pattern()); + compound.putString("type", "selector"); + compound.putString("selector", selector.pattern()); 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) { - compound.setString("type", "keybind"); - compound.setString("keybind", keybind.keybind()); + compound.putString("type", "keybind"); + compound.putString("keybind", keybind.keybind()); } else if (component instanceof NBTComponent nbt) { //todo throw new UnsupportedOperationException("NBTComponent is not implemented yet"); @@ -274,10 +272,10 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer { // Children if (!component.children().isEmpty()) { - var children = new ArrayList(); + ListBinaryTag.Builder children = ListBinaryTag.builder(BinaryTagTypes.COMPOUND); for (var child : component.children()) children.add(serializeComponent(child)); - compound.set("extra", new NBTList<>(NBTType.TAG_Compound, children)); + compound.put("extra", children.build()); } // Formatting @@ -285,94 +283,89 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer { var color = style.color(); if (color != null) { if (color instanceof NamedTextColor named) { - compound.setString("color", named.toString()); + compound.putString("color", named.toString()); } else { - compound.setString("color", color.asHexString()); + compound.putString("color", color.asHexString()); } } var font = style.font(); if (font != null) - compound.setString("font", font.toString()); + compound.putString("font", font.toString()); var bold = style.decoration(TextDecoration.BOLD); 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); 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); 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); 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); if (obfuscated != TextDecoration.State.NOT_SET) - setBool(compound, "obfuscated", obfuscated == TextDecoration.State.TRUE); + compound.putBoolean("obfuscated", obfuscated == TextDecoration.State.TRUE); // Interactivity var insertion = component.insertion(); - if (insertion != null) compound.setString("insertion", insertion); + if (insertion != null) compound.putString("insertion", insertion); var clickEvent = component.clickEvent(); - if (clickEvent != null) compound.set("clickEvent", serializeClickEvent(clickEvent)); + if (clickEvent != null) compound.put("clickEvent", serializeClickEvent(clickEvent)); 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 args) { - var list = new ArrayList(); + private @NotNull BinaryTag serializeTranslationArgs(@NotNull Collection args) { + ListBinaryTag.Builder argList = ListBinaryTag.builder(BinaryTagTypes.COMPOUND); for (var arg : args) - list.add(serializeComponent(arg.asComponent())); - return new NBTList<>(NBTType.TAG_Compound, list); + argList.add(serializeComponent(arg.asComponent())); + return argList.build(); } - private @NotNull NBT serializeClickEvent(@NotNull ClickEvent event) { - var compound = new MutableNBTCompound(); - compound.setString("action", event.action().toString()); - compound.setString("value", event.value()); - return compound.toCompound(); + private @NotNull BinaryTag serializeClickEvent(@NotNull ClickEvent event) { + return CompoundBinaryTag.builder() + .putString("action", event.action().toString()) + .putString("value", event.value()) + .build(); } @SuppressWarnings("unchecked") - private @NotNull NBT serializeHoverEvent(@NotNull HoverEvent event) { - var compound = new MutableNBTCompound(); + private @NotNull BinaryTag serializeHoverEvent(@NotNull HoverEvent event) { + CompoundBinaryTag.Builder compound = CompoundBinaryTag.builder(); //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) { var value = ((HoverEvent) event).value(); - compound.set("contents", serializeComponent(value)); + compound.put("contents", serializeComponent(value)); } else if (event.action() == HoverEvent.Action.SHOW_ITEM) { var value = ((HoverEvent) event).value(); - var itemCompound = new MutableNBTCompound(); - itemCompound.setString("id", value.item().asString()); - if (value.count() != 1) itemCompound.setInt("count", value.count()); + CompoundBinaryTag.Builder itemCompound = CompoundBinaryTag.builder(); + itemCompound.putString("id", value.item().asString()); + if (value.count() != 1) itemCompound.putInt("count", value.count()); 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) { var value = ((HoverEvent) event).value(); - var entityCompound = new MutableNBTCompound(); + CompoundBinaryTag.Builder entityCompound = CompoundBinaryTag.builder(); var name = value.name(); - if (name != null) entityCompound.set("name", serializeComponent(name)); - entityCompound.setString("type", value.type().asString()); - entityCompound.setString("id", value.id().toString()); + if (name != null) entityCompound.put("name", serializeComponent(name)); + entityCompound.putString("type", value.type().asString()); + entityCompound.putString("id", value.id().toString()); - compound.set("contents", entityCompound.toCompound()); + compound.put("contents", entityCompound.build()); } else { 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); - } - - } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentItemStack.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentItemStack.java index 1b6841111..18e5ef25e 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentItemStack.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentItemStack.java @@ -1,16 +1,15 @@ 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.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; 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. @@ -65,10 +64,10 @@ public class ArgumentItemStack extends Argument { final String sNBT = input.substring(nbtIndex).replace("\\\"", "\""); - NBTCompound compound; + CompoundBinaryTag compound; try { - compound = (NBTCompound) new SNBTParser(new StringReader(sNBT)).parse(); - } catch (NBTException e) { + compound = TagStringIO.get().asCompound(sNBT); + } catch (IOException e) { throw new ArgumentSyntaxException("Item NBT is invalid", input, INVALID_NBT); } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentNbtCompoundTag.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentNbtCompoundTag.java index 92fb5b3e9..54633a46b 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentNbtCompoundTag.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentNbtCompoundTag.java @@ -1,22 +1,21 @@ 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.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; 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. *

* Example: {display:{Name:"{\"text\":\"Sword of Power\"}"}} */ -public class ArgumentNbtCompoundTag extends Argument { +public class ArgumentNbtCompoundTag extends Argument { public static final int INVALID_NBT = 1; @@ -26,15 +25,15 @@ public class ArgumentNbtCompoundTag extends Argument { @NotNull @Override - public NBTCompound parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException { + public CompoundBinaryTag parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException { 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); - return (NBTCompound) nbt; - } catch (NBTException e) { + return compound; + } catch (IOException e) { throw new ArgumentSyntaxException("NBTCompound is invalid", input, INVALID_NBT); } } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentNbtTag.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentNbtTag.java index 86dac51ef..7e5d4ab8c 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentNbtTag.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentNbtTag.java @@ -1,23 +1,22 @@ 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.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; 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 - * {@link org.jglrxavpok.hephaistos.nbt.NBTCompound}, {@link org.jglrxavpok.hephaistos.nbt.NBTList}, - * {@link org.jglrxavpok.hephaistos.nbt.NBTInt}, etc... + * Argument used to retrieve a {@link BinaryTag} based object, can be any kind of tag like + * {@link net.kyori.adventure.nbt.CompoundBinaryTag}, {@link net.kyori.adventure.nbt.ListBinaryTag}, + * {@link net.kyori.adventure.nbt.IntBinaryTag}, etc... *

* Example: {display:{Name:"{\"text\":\"Sword of Power\"}"}} or [{display:{Name:"{\"text\":\"Sword of Power\"}"}}] */ -public class ArgumentNbtTag extends Argument { +public class ArgumentNbtTag extends Argument { public static final int INVALID_NBT = 1; @@ -27,10 +26,10 @@ public class ArgumentNbtTag extends Argument { @NotNull @Override - public NBT parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException { + public BinaryTag parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException { try { - return new SNBTParser(new StringReader(input)).parse(); - } catch (NBTException e) { + return TagStringIO.get().asCompound(input); + } catch (IOException e) { throw new ArgumentSyntaxException("Invalid NBT", input, INVALID_NBT); } } diff --git a/src/main/java/net/minestom/server/entity/Metadata.java b/src/main/java/net/minestom/server/entity/Metadata.java index ff126cb8c..0a9adfc44 100644 --- a/src/main/java/net/minestom/server/entity/Metadata.java +++ b/src/main/java/net/minestom/server/entity/Metadata.java @@ -1,5 +1,6 @@ package net.minestom.server.entity; +import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.text.Component; import net.minestom.server.coordinate.Point; 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.Nullable; import org.jetbrains.annotations.UnknownNullability; -import org.jglrxavpok.hephaistos.nbt.NBT; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; @@ -89,7 +89,7 @@ public final class Metadata { return new MetadataImpl.EntryImpl<>(TYPE_OPTBLOCKSTATE, value, NetworkBuffer.OPT_BLOCK_STATE); } - public static Entry NBT(@NotNull NBT nbt) { + public static Entry NBT(@NotNull BinaryTag nbt) { return new MetadataImpl.EntryImpl<>(TYPE_NBT, nbt, NetworkBuffer.NBT); } diff --git a/src/main/java/net/minestom/server/entity/MetadataImpl.java b/src/main/java/net/minestom/server/entity/MetadataImpl.java index d2d89cb92..8a58a9d4e 100644 --- a/src/main/java/net/minestom/server/entity/MetadataImpl.java +++ b/src/main/java/net/minestom/server/entity/MetadataImpl.java @@ -1,5 +1,6 @@ package net.minestom.server.entity; +import net.kyori.adventure.nbt.EndBinaryTag; import net.kyori.adventure.text.Component; import net.minestom.server.coordinate.Vec; 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 org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.UnknownNullability; -import org.jglrxavpok.hephaistos.nbt.NBTEnd; import static net.minestom.server.entity.Metadata.*; 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_BLOCKSTATE, BlockState(Block.AIR.id())); 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_VILLAGERDATA, VillagerData(0, 0, 0)); EMPTY_VALUES.set(TYPE_OPTVARINT, OptVarInt(null)); diff --git a/src/main/java/net/minestom/server/entity/damage/DamageType.java b/src/main/java/net/minestom/server/entity/damage/DamageType.java index 6f6fec6fd..2d2a20cc2 100644 --- a/src/main/java/net/minestom/server/entity/damage/DamageType.java +++ b/src/main/java/net/minestom/server/entity/damage/DamageType.java @@ -1,12 +1,12 @@ 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.StaticProtocolObject; import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.Collection; @@ -36,7 +36,7 @@ public sealed interface DamageType extends StaticProtocolObject, DamageTypes per return registry().scaling(); } - NBTCompound asNBT(); + CompoundBinaryTag asNBT(); static @NotNull Collection<@NotNull DamageType> values() { return DamageTypeImpl.values(); @@ -54,7 +54,7 @@ public sealed interface DamageType extends StaticProtocolObject, DamageTypes per return DamageTypeImpl.getId(id); } - static NBTCompound getNBT() { + static CompoundBinaryTag getNBT() { return DamageTypeImpl.getNBT(); } } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/entity/damage/DamageTypeImpl.java b/src/main/java/net/minestom/server/entity/damage/DamageTypeImpl.java index 70f97ff4c..b8480e656 100644 --- a/src/main/java/net/minestom/server/entity/damage/DamageTypeImpl.java +++ b/src/main/java/net/minestom/server/entity/damage/DamageTypeImpl.java @@ -1,14 +1,12 @@ 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 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.HashMap; -import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; record DamageTypeImpl(Registry.DamageTypeEntry registry, int id) implements DamageType { @@ -33,12 +31,12 @@ record DamageTypeImpl(Registry.DamageTypeEntry registry, int id) implements Dama } @Override - public NBTCompound asNBT() { - var elem = new HashMap(); - elem.put("exhaustion", NBT.Float(registry.exhaustion())); - elem.put("message_id", NBT.String(registry.messageId())); - elem.put("scaling", NBT.String(registry.scaling())); - return NBT.Compound(elem); + public CompoundBinaryTag asNBT() { + return CompoundBinaryTag.builder() + .putFloat("exhaustion", registry.exhaustion()) + .putString("message_id", registry.messageId()) + .putString("scaling", registry.scaling()) + .build(); } static Collection values() { @@ -55,22 +53,23 @@ record DamageTypeImpl(Registry.DamageTypeEntry registry, int id) implements Dama return id; } - private static NBTCompound lazyNbt = null; + private static CompoundBinaryTag lazyNbt = null; - static NBTCompound getNBT() { + static CompoundBinaryTag getNBT() { if (lazyNbt == null) { - var damageTypes = values().stream() - .map((damageType) -> NBT.Compound(Map.of( - "id", NBT.Int(damageType.id()), - "name", NBT.String(damageType.name()), - "element", damageType.asNBT() - ))) - .toList(); + var entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND); + for (var damageType : values()) { + entries.add(CompoundBinaryTag.builder() + .putInt("id", damageType.id()) + .putString("name", damageType.name()) + .put("element", damageType.asNBT()) + .build()); + } - lazyNbt = NBT.Compound(Map.of( - "type", NBT.String("minecraft:damage_type"), - "value", NBT.List(NBTType.TAG_Compound, damageTypes) - )); + lazyNbt = CompoundBinaryTag.builder() + .putString("type", "minecraft:damage_type") + .put("value", entries.build()) + .build(); } return lazyNbt; } diff --git a/src/main/java/net/minestom/server/entity/metadata/PlayerMeta.java b/src/main/java/net/minestom/server/entity/metadata/PlayerMeta.java index 565229964..9eac1aad0 100644 --- a/src/main/java/net/minestom/server/entity/metadata/PlayerMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/PlayerMeta.java @@ -1,12 +1,11 @@ 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.Metadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBT; - -import java.util.Map; public class PlayerMeta extends LivingEntityMeta { public static final byte OFFSET = LivingEntityMeta.MAX_OFFSET; @@ -109,23 +108,23 @@ public class PlayerMeta extends LivingEntityMeta { } @Nullable - public NBT getLeftShoulderEntityData() { + public BinaryTag getLeftShoulderEntityData() { return super.metadata.getIndex(OFFSET + 4, null); } - public void setLeftShoulderEntityData(@Nullable NBT value) { - if (value == null) value = NBT.Compound(Map.of()); + public void setLeftShoulderEntityData(@Nullable BinaryTag value) { + if (value == null) value = CompoundBinaryTag.empty(); super.metadata.setIndex(OFFSET + 4, Metadata.NBT(value)); } @Nullable - public NBT getRightShoulderEntityData() { + public BinaryTag getRightShoulderEntityData() { return super.metadata.getIndex(OFFSET + 5, null); } - public void setRightShoulderEntityData(@Nullable NBT value) { - if (value == null) value = NBT.Compound(Map.of()); + public void setRightShoulderEntityData(@Nullable BinaryTag value) { + if (value == null) value = CompoundBinaryTag.empty(); super.metadata.setIndex(OFFSET + 5, Metadata.NBT(value)); } diff --git a/src/main/java/net/minestom/server/instance/AnvilLoader.java b/src/main/java/net/minestom/server/instance/AnvilLoader.java index 93048a71b..02c96a477 100644 --- a/src/main/java/net/minestom/server/instance/AnvilLoader.java +++ b/src/main/java/net/minestom/server/instance/AnvilLoader.java @@ -1,34 +1,17 @@ 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 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.async.AsyncUtils; import net.minestom.server.world.biomes.Biome; import org.jetbrains.annotations.NotNull; 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.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.StandardCopyOption; -import java.util.*; +import java.util.Set; import java.util.concurrent.CompletableFuture; 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 Biome PLAINS = MinecraftServer.getBiomeManager().getByName(NamespaceID.from("minecraft:plains")); - private final Map alreadyLoaded = new ConcurrentHashMap<>(); +// private final Map alreadyLoaded = new ConcurrentHashMap<>(); private final Path path; private final Path levelPath; private final Path regionPath; @@ -50,7 +33,7 @@ public class AnvilLoader implements IChunkLoader { private final RegionCache perRegionLoadedChunks = new RegionCache(); // thread local to avoid contention issues with locks - private final ThreadLocal> blockStateId2ObjectCacheTLS = ThreadLocal.withInitial(Int2ObjectArrayMap::new); +// private final ThreadLocal> blockStateId2ObjectCacheTLS = ThreadLocal.withInitial(Int2ObjectArrayMap::new); public AnvilLoader(@NotNull Path path) { this.path = path; @@ -64,409 +47,409 @@ public class AnvilLoader implements IChunkLoader { @Override public void loadInstance(@NotNull Instance instance) { - if (!Files.exists(levelPath)) { - return; - } - try (var reader = new NBTReader(Files.newInputStream(levelPath))) { - final NBTCompound tag = (NBTCompound) reader.read(); - Files.copy(levelPath, path.resolve("level.dat_old"), StandardCopyOption.REPLACE_EXISTING); - instance.tagHandler().updateContent(tag); - } catch (IOException | NBTException e) { - MinecraftServer.getExceptionManager().handleException(e); - } +// if (!Files.exists(levelPath)) { +// return; +// } +// try (var reader = new NBTReader(Files.newInputStream(levelPath))) { +// final NBTCompound tag = (NBTCompound) reader.read(); +// Files.copy(levelPath, path.resolve("level.dat_old"), StandardCopyOption.REPLACE_EXISTING); +// instance.tagHandler().updateContent(tag); +// } catch (IOException | NBTException e) { +// MinecraftServer.getExceptionManager().handleException(e); +// } } @Override public @NotNull CompletableFuture<@Nullable Chunk> loadChunk(@NotNull Instance instance, int chunkX, int chunkZ) { - if (!Files.exists(path)) { - // No world folder - return CompletableFuture.completedFuture(null); - } - try { - return loadMCA(instance, chunkX, chunkZ); - } catch (Exception e) { - MinecraftServer.getExceptionManager().handleException(e); - } +// if (!Files.exists(path)) { +// // No world folder +// return CompletableFuture.completedFuture(null); +// } +// try { +// return loadMCA(instance, chunkX, chunkZ); +// } catch (Exception e) { +// MinecraftServer.getExceptionManager().handleException(e); +// } return CompletableFuture.completedFuture(null); } - - private @NotNull CompletableFuture<@Nullable Chunk> loadMCA(Instance instance, int chunkX, int chunkZ) throws IOException, AnvilException { - final RegionFile mcaFile = getMCAFile(instance, chunkX, chunkZ); - if (mcaFile == null) - return CompletableFuture.completedFuture(null); - final NBTCompound chunkData = mcaFile.getChunkData(chunkX, chunkZ); - if (chunkData == null) - return CompletableFuture.completedFuture(null); - - final ChunkReader chunkReader = new ChunkReader(chunkData); - - Chunk chunk = instance.getChunkSupplier().createChunk(instance, chunkX, chunkZ); - synchronized (chunk) { - var yRange = chunkReader.getYRange(); - if (yRange.getStart() < instance.getDimensionType().getMinY()) { - throw new AnvilException( - String.format("Trying to load chunk with minY = %d, but instance dimension type (%s) has a minY of %d", - yRange.getStart(), - instance.getDimensionType().getName().asString(), - instance.getDimensionType().getMinY() - )); - } - if (yRange.getEndInclusive() > instance.getDimensionType().getMaxY()) { - throw new AnvilException( - String.format("Trying to load chunk with maxY = %d, but instance dimension type (%s) has a maxY of %d", - yRange.getEndInclusive(), - instance.getDimensionType().getName().asString(), - instance.getDimensionType().getMaxY() - )); - } - - // TODO: Parallelize block, block entities and biome loading - // Blocks + Biomes - loadSections(chunk, chunkReader); - - // Block entities - loadBlockEntities(chunk, chunkReader); - } - synchronized (perRegionLoadedChunks) { - int regionX = CoordinatesKt.chunkToRegion(chunkX); - 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 - chunks.add(new IntIntImmutablePair(chunkX, chunkZ)); - } - return CompletableFuture.completedFuture(chunk); - } - - private @Nullable RegionFile getMCAFile(Instance instance, int chunkX, int chunkZ) { - final int regionX = CoordinatesKt.chunkToRegion(chunkX); - final int regionZ = CoordinatesKt.chunkToRegion(chunkZ); - return alreadyLoaded.computeIfAbsent(RegionFile.Companion.createFileName(regionX, regionZ), n -> { - try { - final Path regionPath = this.regionPath.resolve(n); - if (!Files.exists(regionPath)) { - return null; - } - synchronized (perRegionLoadedChunks) { - Set previousVersion = perRegionLoadedChunks.put(new IntIntImmutablePair(regionX, regionZ), new HashSet<>()); - 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); - } catch (IOException | AnvilException e) { - MinecraftServer.getExceptionManager().handleException(e); - return null; - } - }); - } - - private void loadSections(Chunk chunk, ChunkReader chunkReader) { - final HashMap biomeCache = new HashMap<>(); - for (NBTCompound sectionNBT : chunkReader.getSections()) { - ChunkSectionReader sectionReader = new ChunkSectionReader(chunkReader.getMinecraftVersion(), sectionNBT); - - if (sectionReader.isSectionEmpty()) continue; - final int sectionY = sectionReader.getY(); - final int yOffset = Chunk.CHUNK_SECTION_SIZE * sectionY; - - Section section = chunk.getSection(sectionY); - - if (sectionReader.getSkyLight() != null) { - section.setSkyLight(sectionReader.getSkyLight().copyArray()); - } - if (sectionReader.getBlockLight() != null) { - section.setBlockLight(sectionReader.getBlockLight().copyArray()); - } - - // Biomes - if (chunkReader.getGenerationStatus().compareTo(ChunkColumn.GenerationStatus.Biomes) > 0) { - SectionBiomeInformation sectionBiomeInformation = chunkReader.readSectionBiomes(sectionReader); - - if (sectionBiomeInformation != null && sectionBiomeInformation.hasBiomeInformation()) { - if (sectionBiomeInformation.isFilledWithSingleBiome()) { - for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) { - for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { - for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) { - int finalX = chunk.chunkX * Chunk.CHUNK_SIZE_X + x; - int finalZ = chunk.chunkZ * Chunk.CHUNK_SIZE_Z + z; - int finalY = sectionY * Chunk.CHUNK_SECTION_SIZE + y; - String biomeName = sectionBiomeInformation.getBaseBiome(); - Biome biome = biomeCache.computeIfAbsent(biomeName, n -> - Objects.requireNonNullElse(MinecraftServer.getBiomeManager().getByName(NamespaceID.from(n)), PLAINS)); - chunk.setBiome(finalX, finalY, finalZ, biome); - } - } - } - } else { - for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) { - for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { - for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) { - int finalX = chunk.chunkX * Chunk.CHUNK_SIZE_X + x; - int finalZ = chunk.chunkZ * Chunk.CHUNK_SIZE_Z + z; - int finalY = sectionY * Chunk.CHUNK_SECTION_SIZE + y; - - int index = x / 4 + (z / 4) * 4 + (y / 4) * 16; - String biomeName = sectionBiomeInformation.getBiomes()[index]; - Biome biome = biomeCache.computeIfAbsent(biomeName, n -> - Objects.requireNonNullElse(MinecraftServer.getBiomeManager().getByName(NamespaceID.from(n)), PLAINS)); - chunk.setBiome(finalX, finalY, finalZ, biome); - } - } - } - } - } - } - - // Blocks - final NBTList blockPalette = sectionReader.getBlockPalette(); - if (blockPalette != null) { - final int[] blockStateIndices = sectionReader.getUncompressedBlockStateIDs(); - Block[] convertedPalette = new Block[blockPalette.getSize()]; - for (int i = 0; i < convertedPalette.length; i++) { - final NBTCompound paletteEntry = blockPalette.get(i); - String blockName = Objects.requireNonNull(paletteEntry.getString("Name")); - if (blockName.equals("minecraft:air")) { - convertedPalette[i] = Block.AIR; - } else { - if (blockName.equals("minecraft:grass")) { - blockName = "minecraft:short_grass"; - } - Block block = Objects.requireNonNull(Block.fromNamespaceId(blockName)); - // Properties - final Map properties = new HashMap<>(); - NBTCompound propertiesNBT = paletteEntry.getCompound("Properties"); - if (propertiesNBT != null) { - for (var property : propertiesNBT) { - if (property.getValue().getID() != NBTType.TAG_String) { - LOGGER.warn("Fail to parse block state properties {}, expected a TAG_String for {}, but contents were {}", - propertiesNBT, - property.getKey(), - property.getValue().toSNBT()); - } else { - properties.put(property.getKey(), ((NBTString) property.getValue()).getValue()); - } - } - } - - if (!properties.isEmpty()) block = block.withProperties(properties); - // Handler - final BlockHandler handler = MinecraftServer.getBlockManager().getHandler(block.name()); - if (handler != null) block = block.withHandler(handler); - - convertedPalette[i] = block; - } - } - - for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) { - for (int z = 0; z < Chunk.CHUNK_SECTION_SIZE; z++) { - for (int x = 0; x < Chunk.CHUNK_SECTION_SIZE; x++) { - try { - final int blockIndex = y * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SECTION_SIZE + z * Chunk.CHUNK_SECTION_SIZE + x; - final int paletteIndex = blockStateIndices[blockIndex]; - final Block block = convertedPalette[paletteIndex]; - - chunk.setBlock(x, y + yOffset, z, block); - } catch (Exception e) { - MinecraftServer.getExceptionManager().handleException(e); - } - } - } - } - } - } - } - - private void loadBlockEntities(Chunk loadedChunk, ChunkReader chunkReader) { - for (NBTCompound te : chunkReader.getBlockEntities()) { - final var x = te.getInt("x"); - final var y = te.getInt("y"); - final var z = te.getInt("z"); - if (x == null || y == null || z == null) { - LOGGER.warn("Tile entity has failed to load due to invalid coordinate"); - continue; - } - Block block = loadedChunk.getBlock(x, y, z); - - final String tileEntityID = te.getString("id"); - if (tileEntityID != null) { - final BlockHandler handler = MinecraftServer.getBlockManager().getHandlerOrDummy(tileEntityID); - block = block.withHandler(handler); - } - // Remove anvil tags - MutableNBTCompound mutableCopy = te.toMutableCompound(); - mutableCopy.remove("id"); - mutableCopy.remove("x"); - mutableCopy.remove("y"); - mutableCopy.remove("z"); - mutableCopy.remove("keepPacked"); - // Place block - final var finalBlock = mutableCopy.getSize() > 0 ? - block.withNbt(mutableCopy.toCompound()) : block; - loadedChunk.setBlock(x, y, z, finalBlock); - } - } - +// +// private @NotNull CompletableFuture<@Nullable Chunk> loadMCA(Instance instance, int chunkX, int chunkZ) throws IOException, AnvilException { +// final RegionFile mcaFile = getMCAFile(instance, chunkX, chunkZ); +// if (mcaFile == null) +// return CompletableFuture.completedFuture(null); +// final NBTCompound chunkData = mcaFile.getChunkData(chunkX, chunkZ); +// if (chunkData == null) +// return CompletableFuture.completedFuture(null); +// +// final ChunkReader chunkReader = new ChunkReader(chunkData); +// +// Chunk chunk = instance.getChunkSupplier().createChunk(instance, chunkX, chunkZ); +// synchronized (chunk) { +// var yRange = chunkReader.getYRange(); +// if (yRange.getStart() < instance.getDimensionType().getMinY()) { +// throw new AnvilException( +// String.format("Trying to load chunk with minY = %d, but instance dimension type (%s) has a minY of %d", +// yRange.getStart(), +// instance.getDimensionType().getName().asString(), +// instance.getDimensionType().getMinY() +// )); +// } +// if (yRange.getEndInclusive() > instance.getDimensionType().getMaxY()) { +// throw new AnvilException( +// String.format("Trying to load chunk with maxY = %d, but instance dimension type (%s) has a maxY of %d", +// yRange.getEndInclusive(), +// instance.getDimensionType().getName().asString(), +// instance.getDimensionType().getMaxY() +// )); +// } +// +// // TODO: Parallelize block, block entities and biome loading +// // Blocks + Biomes +// loadSections(chunk, chunkReader); +// +// // Block entities +// loadBlockEntities(chunk, chunkReader); +// } +// synchronized (perRegionLoadedChunks) { +// int regionX = CoordinatesKt.chunkToRegion(chunkX); +// 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 +// chunks.add(new IntIntImmutablePair(chunkX, chunkZ)); +// } +// return CompletableFuture.completedFuture(chunk); +// } +// +// private @Nullable RegionFile getMCAFile(Instance instance, int chunkX, int chunkZ) { +// final int regionX = CoordinatesKt.chunkToRegion(chunkX); +// final int regionZ = CoordinatesKt.chunkToRegion(chunkZ); +// return alreadyLoaded.computeIfAbsent(RegionFile.Companion.createFileName(regionX, regionZ), n -> { +// try { +// final Path regionPath = this.regionPath.resolve(n); +// if (!Files.exists(regionPath)) { +// return null; +// } +// synchronized (perRegionLoadedChunks) { +// Set previousVersion = perRegionLoadedChunks.put(new IntIntImmutablePair(regionX, regionZ), new HashSet<>()); +// 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); +// } catch (IOException | AnvilException e) { +// MinecraftServer.getExceptionManager().handleException(e); +// return null; +// } +// }); +// } +// +// private void loadSections(Chunk chunk, ChunkReader chunkReader) { +// final HashMap biomeCache = new HashMap<>(); +// for (NBTCompound sectionNBT : chunkReader.getSections()) { +// ChunkSectionReader sectionReader = new ChunkSectionReader(chunkReader.getMinecraftVersion(), sectionNBT); +// +// if (sectionReader.isSectionEmpty()) continue; +// final int sectionY = sectionReader.getY(); +// final int yOffset = Chunk.CHUNK_SECTION_SIZE * sectionY; +// +// Section section = chunk.getSection(sectionY); +// +// if (sectionReader.getSkyLight() != null) { +// section.setSkyLight(sectionReader.getSkyLight().copyArray()); +// } +// if (sectionReader.getBlockLight() != null) { +// section.setBlockLight(sectionReader.getBlockLight().copyArray()); +// } +// +// // Biomes +// if (chunkReader.getGenerationStatus().compareTo(ChunkColumn.GenerationStatus.Biomes) > 0) { +// SectionBiomeInformation sectionBiomeInformation = chunkReader.readSectionBiomes(sectionReader); +// +// if (sectionBiomeInformation != null && sectionBiomeInformation.hasBiomeInformation()) { +// if (sectionBiomeInformation.isFilledWithSingleBiome()) { +// for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) { +// for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { +// for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) { +// int finalX = chunk.chunkX * Chunk.CHUNK_SIZE_X + x; +// int finalZ = chunk.chunkZ * Chunk.CHUNK_SIZE_Z + z; +// int finalY = sectionY * Chunk.CHUNK_SECTION_SIZE + y; +// String biomeName = sectionBiomeInformation.getBaseBiome(); +// Biome biome = biomeCache.computeIfAbsent(biomeName, n -> +// Objects.requireNonNullElse(MinecraftServer.getBiomeManager().getByName(NamespaceID.from(n)), PLAINS)); +// chunk.setBiome(finalX, finalY, finalZ, biome); +// } +// } +// } +// } else { +// for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) { +// for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { +// for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) { +// int finalX = chunk.chunkX * Chunk.CHUNK_SIZE_X + x; +// int finalZ = chunk.chunkZ * Chunk.CHUNK_SIZE_Z + z; +// int finalY = sectionY * Chunk.CHUNK_SECTION_SIZE + y; +// +// int index = x / 4 + (z / 4) * 4 + (y / 4) * 16; +// String biomeName = sectionBiomeInformation.getBiomes()[index]; +// Biome biome = biomeCache.computeIfAbsent(biomeName, n -> +// Objects.requireNonNullElse(MinecraftServer.getBiomeManager().getByName(NamespaceID.from(n)), PLAINS)); +// chunk.setBiome(finalX, finalY, finalZ, biome); +// } +// } +// } +// } +// } +// } +// +// // Blocks +// final NBTList blockPalette = sectionReader.getBlockPalette(); +// if (blockPalette != null) { +// final int[] blockStateIndices = sectionReader.getUncompressedBlockStateIDs(); +// Block[] convertedPalette = new Block[blockPalette.getSize()]; +// for (int i = 0; i < convertedPalette.length; i++) { +// final NBTCompound paletteEntry = blockPalette.get(i); +// String blockName = Objects.requireNonNull(paletteEntry.getString("Name")); +// if (blockName.equals("minecraft:air")) { +// convertedPalette[i] = Block.AIR; +// } else { +// if (blockName.equals("minecraft:grass")) { +// blockName = "minecraft:short_grass"; +// } +// Block block = Objects.requireNonNull(Block.fromNamespaceId(blockName)); +// // Properties +// final Map properties = new HashMap<>(); +// NBTCompound propertiesNBT = paletteEntry.getCompound("Properties"); +// if (propertiesNBT != null) { +// for (var property : propertiesNBT) { +// if (property.getValue().getID() != NBTType.TAG_String) { +// LOGGER.warn("Fail to parse block state properties {}, expected a TAG_String for {}, but contents were {}", +// propertiesNBT, +// property.getKey(), +// property.getValue().toSNBT()); +// } else { +// properties.put(property.getKey(), ((NBTString) property.getValue()).getValue()); +// } +// } +// } +// +// if (!properties.isEmpty()) block = block.withProperties(properties); +// // Handler +// final BlockHandler handler = MinecraftServer.getBlockManager().getHandler(block.name()); +// if (handler != null) block = block.withHandler(handler); +// +// convertedPalette[i] = block; +// } +// } +// +// for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) { +// for (int z = 0; z < Chunk.CHUNK_SECTION_SIZE; z++) { +// for (int x = 0; x < Chunk.CHUNK_SECTION_SIZE; x++) { +// try { +// final int blockIndex = y * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SECTION_SIZE + z * Chunk.CHUNK_SECTION_SIZE + x; +// final int paletteIndex = blockStateIndices[blockIndex]; +// final Block block = convertedPalette[paletteIndex]; +// +// chunk.setBlock(x, y + yOffset, z, block); +// } catch (Exception e) { +// MinecraftServer.getExceptionManager().handleException(e); +// } +// } +// } +// } +// } +// } +// } +// +// private void loadBlockEntities(Chunk loadedChunk, ChunkReader chunkReader) { +// for (NBTCompound te : chunkReader.getBlockEntities()) { +// final var x = te.getInt("x"); +// final var y = te.getInt("y"); +// final var z = te.getInt("z"); +// if (x == null || y == null || z == null) { +// LOGGER.warn("Tile entity has failed to load due to invalid coordinate"); +// continue; +// } +// Block block = loadedChunk.getBlock(x, y, z); +// +// final String tileEntityID = te.getString("id"); +// if (tileEntityID != null) { +// final BlockHandler handler = MinecraftServer.getBlockManager().getHandlerOrDummy(tileEntityID); +// block = block.withHandler(handler); +// } +// // Remove anvil tags +// MutableNBTCompound mutableCopy = te.toMutableCompound(); +// mutableCopy.remove("id"); +// mutableCopy.remove("x"); +// mutableCopy.remove("y"); +// mutableCopy.remove("z"); +// mutableCopy.remove("keepPacked"); +// // Place block +// final var finalBlock = mutableCopy.getSize() > 0 ? +// block.withNbt(mutableCopy.toCompound()) : block; +// loadedChunk.setBlock(x, y, z, finalBlock); +// } +// } +// @Override public @NotNull CompletableFuture saveInstance(@NotNull Instance instance) { - final NBTCompound nbt = instance.tagHandler().asCompound(); - if (nbt.isEmpty()) { - // Instance has no data - return AsyncUtils.VOID_FUTURE; - } - try (NBTWriter writer = new NBTWriter(Files.newOutputStream(levelPath))) { - writer.writeNamed("", nbt); - } catch (IOException e) { - e.printStackTrace(); - } +// final NBTCompound nbt = instance.tagHandler().asCompound(); +// if (nbt.isEmpty()) { +// // Instance has no data +// return AsyncUtils.VOID_FUTURE; +// } +// try (NBTWriter writer = new NBTWriter(Files.newOutputStream(levelPath))) { +// writer.writeNamed("", nbt); +// } catch (IOException e) { +// e.printStackTrace(); +// } return AsyncUtils.VOID_FUTURE; } @Override public @NotNull CompletableFuture saveChunk(@NotNull Chunk chunk) { - final int chunkX = chunk.getChunkX(); - final int chunkZ = chunk.getChunkZ(); - RegionFile mcaFile; - synchronized (alreadyLoaded) { - mcaFile = getMCAFile(chunk.instance, chunkX, chunkZ); - if (mcaFile == null) { - final int regionX = CoordinatesKt.chunkToRegion(chunkX); - final int regionZ = CoordinatesKt.chunkToRegion(chunkZ); - final String n = RegionFile.Companion.createFileName(regionX, regionZ); - File regionFile = new File(regionPath.toFile(), n); - try { - if (!regionFile.exists()) { - if (!regionFile.getParentFile().exists()) { - regionFile.getParentFile().mkdirs(); - } - regionFile.createNewFile(); - } - mcaFile = new RegionFile(new RandomAccessFile(regionFile, "rw"), regionX, regionZ); - alreadyLoaded.put(n, mcaFile); - } catch (AnvilException | IOException e) { - LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e); - MinecraftServer.getExceptionManager().handleException(e); - return AsyncUtils.VOID_FUTURE; - } - } - } - ChunkWriter writer = new ChunkWriter(SupportedVersion.Companion.getLatest()); - save(chunk, writer); - try { - LOGGER.debug("Attempt saving at {} {}", chunk.getChunkX(), chunk.getChunkZ()); - mcaFile.writeColumnData(writer.toNBT(), chunk.getChunkX(), chunk.getChunkZ()); - } catch (IOException e) { - LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e); - MinecraftServer.getExceptionManager().handleException(e); - return AsyncUtils.VOID_FUTURE; - } +// final int chunkX = chunk.getChunkX(); +// final int chunkZ = chunk.getChunkZ(); +// RegionFile mcaFile; +// synchronized (alreadyLoaded) { +// mcaFile = getMCAFile(chunk.instance, chunkX, chunkZ); +// if (mcaFile == null) { +// final int regionX = CoordinatesKt.chunkToRegion(chunkX); +// final int regionZ = CoordinatesKt.chunkToRegion(chunkZ); +// final String n = RegionFile.Companion.createFileName(regionX, regionZ); +// File regionFile = new File(regionPath.toFile(), n); +// try { +// if (!regionFile.exists()) { +// if (!regionFile.getParentFile().exists()) { +// regionFile.getParentFile().mkdirs(); +// } +// regionFile.createNewFile(); +// } +// mcaFile = new RegionFile(new RandomAccessFile(regionFile, "rw"), regionX, regionZ); +// alreadyLoaded.put(n, mcaFile); +// } catch (AnvilException | IOException e) { +// LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e); +// MinecraftServer.getExceptionManager().handleException(e); +// return AsyncUtils.VOID_FUTURE; +// } +// } +// } +// ChunkWriter writer = new ChunkWriter(SupportedVersion.Companion.getLatest()); +// save(chunk, writer); +// try { +// LOGGER.debug("Attempt saving at {} {}", chunk.getChunkX(), chunk.getChunkZ()); +// mcaFile.writeColumnData(writer.toNBT(), chunk.getChunkX(), chunk.getChunkZ()); +// } catch (IOException e) { +// LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e); +// MinecraftServer.getExceptionManager().handleException(e); +// return AsyncUtils.VOID_FUTURE; +// } return AsyncUtils.VOID_FUTURE; } - private BlockState getBlockState(final Block block) { - return blockStateId2ObjectCacheTLS.get().computeIfAbsent(block.stateId(), _unused -> new BlockState(block.name(), block.properties())); - } - - private void save(Chunk chunk, ChunkWriter chunkWriter) { - final int minY = chunk.getMinSection() * Chunk.CHUNK_SECTION_SIZE; - final int maxY = chunk.getMaxSection() * Chunk.CHUNK_SECTION_SIZE - 1; - chunkWriter.setYPos(minY); - List blockEntities = new ArrayList<>(); - chunkWriter.setStatus(ChunkColumn.GenerationStatus.Full); - - List sectionData = new ArrayList<>((maxY - minY + 1) / Chunk.CHUNK_SECTION_SIZE); - int[] palettedBiomes = new int[ChunkSection.Companion.getBiomeArraySize()]; - 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++) { - ChunkSectionWriter sectionWriter = new ChunkSectionWriter(SupportedVersion.Companion.getLatest(), (byte) sectionY); - - Section section = chunk.getSection(sectionY); - sectionWriter.setSkyLights(section.skyLight().array()); - sectionWriter.setBlockLights(section.blockLight().array()); - - BiomePalette biomePalette = new BiomePalette(); - BlockPalette blockPalette = new BlockPalette(); - for (int sectionLocalY = 0; sectionLocalY < Chunk.CHUNK_SECTION_SIZE; sectionLocalY++) { - for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { - for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) { - final int y = sectionLocalY + sectionY * Chunk.CHUNK_SECTION_SIZE; - - final int blockIndex = x + sectionLocalY * 16 * 16 + z * 16; - - final Block block = chunk.getBlock(x, y, z); - - final BlockState hephaistosBlockState = getBlockState(block); - blockPalette.increaseReference(hephaistosBlockState); - - palettedBlockStates[blockIndex] = blockPalette.getPaletteIndex(hephaistosBlockState); - - // biome are stored for 4x4x4 volumes, avoid unnecessary work - if (x % 4 == 0 && sectionLocalY % 4 == 0 && z % 4 == 0) { - int biomeIndex = (x / 4) + (sectionLocalY / 4) * 4 * 4 + (z / 4) * 4; - final Biome biome = chunk.getBiome(x, y, z); - final String biomeName = biome.name(); - - biomePalette.increaseReference(biomeName); - palettedBiomes[biomeIndex] = biomePalette.getPaletteIndex(biomeName); - } - - // Block entities - final BlockHandler handler = block.handler(); - final NBTCompound originalNBT = block.nbt(); - if (originalNBT != null || handler != null) { - MutableNBTCompound nbt = originalNBT != null ? - originalNBT.toMutableCompound() : new MutableNBTCompound(); - - if (handler != null) { - nbt.setString("id", handler.getNamespaceId().asString()); - } - nbt.setInt("x", x + Chunk.CHUNK_SIZE_X * chunk.getChunkX()); - nbt.setInt("y", y); - nbt.setInt("z", z + Chunk.CHUNK_SIZE_Z * chunk.getChunkZ()); - nbt.setByte("keepPacked", (byte) 0); - blockEntities.add(nbt.toCompound()); - } - } - } - } - - sectionWriter.setPalettedBiomes(biomePalette, palettedBiomes); - sectionWriter.setPalettedBlockStates(blockPalette, palettedBlockStates); - - sectionData.add(sectionWriter.toNBT()); - } - - chunkWriter.setSectionsData(NBT.List(NBTType.TAG_Compound, sectionData)); - chunkWriter.setBlockEntityData(NBT.List(NBTType.TAG_Compound, blockEntities)); - } - - /** - * Unload a given chunk. Also unloads a region when no chunk from that region is loaded. - * - * @param chunk the chunk to unload - */ - @Override - public void unloadChunk(Chunk chunk) { - final int regionX = CoordinatesKt.chunkToRegion(chunk.chunkX); - final int regionZ = CoordinatesKt.chunkToRegion(chunk.chunkZ); - - final IntIntImmutablePair regionKey = new IntIntImmutablePair(regionX, regionZ); - synchronized (perRegionLoadedChunks) { - Set chunks = perRegionLoadedChunks.get(regionKey); - 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 - chunks.remove(new IntIntImmutablePair(chunk.chunkX, chunk.chunkZ)); - - if (chunks.isEmpty()) { - perRegionLoadedChunks.remove(regionKey); - RegionFile regionFile = alreadyLoaded.remove(RegionFile.Companion.createFileName(regionX, regionZ)); - if (regionFile != null) { - try { - regionFile.close(); - } catch (IOException e) { - MinecraftServer.getExceptionManager().handleException(e); - } - } - } - } - } - } +// private BlockState getBlockState(final Block block) { +// return blockStateId2ObjectCacheTLS.get().computeIfAbsent(block.stateId(), _unused -> new BlockState(block.name(), block.properties())); +// } +// +// private void save(Chunk chunk, ChunkWriter chunkWriter) { +// final int minY = chunk.getMinSection() * Chunk.CHUNK_SECTION_SIZE; +// final int maxY = chunk.getMaxSection() * Chunk.CHUNK_SECTION_SIZE - 1; +// chunkWriter.setYPos(minY); +// List blockEntities = new ArrayList<>(); +// chunkWriter.setStatus(ChunkColumn.GenerationStatus.Full); +// +// List sectionData = new ArrayList<>((maxY - minY + 1) / Chunk.CHUNK_SECTION_SIZE); +// int[] palettedBiomes = new int[ChunkSection.Companion.getBiomeArraySize()]; +// 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++) { +// ChunkSectionWriter sectionWriter = new ChunkSectionWriter(SupportedVersion.Companion.getLatest(), (byte) sectionY); +// +// Section section = chunk.getSection(sectionY); +// sectionWriter.setSkyLights(section.skyLight().array()); +// sectionWriter.setBlockLights(section.blockLight().array()); +// +// BiomePalette biomePalette = new BiomePalette(); +// BlockPalette blockPalette = new BlockPalette(); +// for (int sectionLocalY = 0; sectionLocalY < Chunk.CHUNK_SECTION_SIZE; sectionLocalY++) { +// for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { +// for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) { +// final int y = sectionLocalY + sectionY * Chunk.CHUNK_SECTION_SIZE; +// +// final int blockIndex = x + sectionLocalY * 16 * 16 + z * 16; +// +// final Block block = chunk.getBlock(x, y, z); +// +// final BlockState hephaistosBlockState = getBlockState(block); +// blockPalette.increaseReference(hephaistosBlockState); +// +// palettedBlockStates[blockIndex] = blockPalette.getPaletteIndex(hephaistosBlockState); +// +// // biome are stored for 4x4x4 volumes, avoid unnecessary work +// if (x % 4 == 0 && sectionLocalY % 4 == 0 && z % 4 == 0) { +// int biomeIndex = (x / 4) + (sectionLocalY / 4) * 4 * 4 + (z / 4) * 4; +// final Biome biome = chunk.getBiome(x, y, z); +// final String biomeName = biome.name(); +// +// biomePalette.increaseReference(biomeName); +// palettedBiomes[biomeIndex] = biomePalette.getPaletteIndex(biomeName); +// } +// +// // Block entities +// final BlockHandler handler = block.handler(); +// final NBTCompound originalNBT = block.nbt(); +// if (originalNBT != null || handler != null) { +// MutableNBTCompound nbt = originalNBT != null ? +// originalNBT.toMutableCompound() : new MutableNBTCompound(); +// +// if (handler != null) { +// nbt.setString("id", handler.getNamespaceId().asString()); +// } +// nbt.setInt("x", x + Chunk.CHUNK_SIZE_X * chunk.getChunkX()); +// nbt.setInt("y", y); +// nbt.setInt("z", z + Chunk.CHUNK_SIZE_Z * chunk.getChunkZ()); +// nbt.setByte("keepPacked", (byte) 0); +// blockEntities.add(nbt.toCompound()); +// } +// } +// } +// } +// +// sectionWriter.setPalettedBiomes(biomePalette, palettedBiomes); +// sectionWriter.setPalettedBlockStates(blockPalette, palettedBlockStates); +// +// sectionData.add(sectionWriter.toNBT()); +// } +// +// chunkWriter.setSectionsData(NBT.List(NBTType.TAG_Compound, sectionData)); +// chunkWriter.setBlockEntityData(NBT.List(NBTType.TAG_Compound, blockEntities)); +// } +// +// /** +// * Unload a given chunk. Also unloads a region when no chunk from that region is loaded. +// * +// * @param chunk the chunk to unload +// */ +// @Override +// public void unloadChunk(Chunk chunk) { +// final int regionX = CoordinatesKt.chunkToRegion(chunk.chunkX); +// final int regionZ = CoordinatesKt.chunkToRegion(chunk.chunkZ); +// +// final IntIntImmutablePair regionKey = new IntIntImmutablePair(regionX, regionZ); +// synchronized (perRegionLoadedChunks) { +// Set chunks = perRegionLoadedChunks.get(regionKey); +// 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 +// chunks.remove(new IntIntImmutablePair(chunk.chunkX, chunk.chunkZ)); +// +// if (chunks.isEmpty()) { +// perRegionLoadedChunks.remove(regionKey); +// RegionFile regionFile = alreadyLoaded.remove(RegionFile.Companion.createFileName(regionX, regionZ)); +// if (regionFile != null) { +// try { +// regionFile.close(); +// } catch (IOException e) { +// MinecraftServer.getExceptionManager().handleException(e); +// } +// } +// } +// } +// } +// } @Override public boolean supportsParallelLoading() { diff --git a/src/main/java/net/minestom/server/instance/DynamicChunk.java b/src/main/java/net/minestom/server/instance/DynamicChunk.java index 87768d763..618084e65 100644 --- a/src/main/java/net/minestom/server/instance/DynamicChunk.java +++ b/src/main/java/net/minestom/server/instance/DynamicChunk.java @@ -2,6 +2,7 @@ package net.minestom.server.instance; import com.extollit.gaming.ai.path.model.ColumnarOcclusionFieldList; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Point; 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 org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBT; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -225,7 +224,7 @@ public class DynamicChunk extends Chunk { } private @NotNull ChunkDataPacket createChunkPacket() { - final NBTCompound heightmapsNBT = computeHeightmap(); + final CompoundBinaryTag heightmapsNBT = computeHeightmap(); // Data final byte[] data; @@ -242,7 +241,7 @@ public class DynamicChunk extends Chunk { ); } - protected NBTCompound computeHeightmap() { + protected CompoundBinaryTag computeHeightmap() { // TODO: don't hardcode heightmaps // Heightmap int dimensionHeight = getInstance().getDimensionType().getHeight(); @@ -255,9 +254,10 @@ public class DynamicChunk extends Chunk { } } final int bitsForHeight = MathUtils.bitsToRepresent(dimensionHeight); - return NBT.Compound(Map.of( - "MOTION_BLOCKING", NBT.LongArray(encodeBlocks(motionBlocking, bitsForHeight)), - "WORLD_SURFACE", NBT.LongArray(encodeBlocks(worldSurface, bitsForHeight)))); + return CompoundBinaryTag.builder() + .putLongArray("MOTION_BLOCKING", encodeBlocks(motionBlocking, bitsForHeight)) + .putLongArray("WORLD_SURFACE", encodeBlocks(worldSurface, bitsForHeight)) + .build(); } @NotNull UpdateLightPacket createLightPacket() { diff --git a/src/main/java/net/minestom/server/instance/ExplosionSupplier.java b/src/main/java/net/minestom/server/instance/ExplosionSupplier.java index ea408e310..bdb7fcbbe 100644 --- a/src/main/java/net/minestom/server/instance/ExplosionSupplier.java +++ b/src/main/java/net/minestom/server/instance/ExplosionSupplier.java @@ -1,6 +1,6 @@ package net.minestom.server.instance; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import net.kyori.adventure.nbt.CompoundBinaryTag; @FunctionalInterface public interface ExplosionSupplier { @@ -12,9 +12,9 @@ public interface ExplosionSupplier { * @param centerY center Y of the explosion * @param centerZ center Z 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 */ - Explosion createExplosion(float centerX, float centerY, float centerZ, float strength, NBTCompound additionalData); + Explosion createExplosion(float centerX, float centerY, float centerZ, float strength, CompoundBinaryTag additionalData); } diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index 3cfe29d21..7d959aa25 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -2,6 +2,7 @@ package net.minestom.server.instance; import it.unimi.dsi.fastutil.objects.ObjectArraySet; import net.kyori.adventure.identity.Identity; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.pointer.Pointers; import net.minestom.server.MinecraftServer; import net.minestom.server.ServerProcess; @@ -45,7 +46,6 @@ import net.minestom.server.world.DimensionType; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.time.Duration; 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 * @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(); Check.stateCondition(explosionSupplier == null, "Tried to create an explosion with no explosion supplier"); final Explosion explosion = explosionSupplier.createExplosion(centerX, centerY, centerZ, strength, additionalData); diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index f9fed417a..b62a9c1c7 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -1,6 +1,7 @@ package net.minestom.server.instance; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Point; 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.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import space.vectrix.flare.fastutil.Long2ObjectSyncMap; @@ -186,7 +186,7 @@ public class InstanceContainer extends Instance { chunk.sendPacketToViewers(new BlockChangePacket(blockPosition, block.stateId())); var registry = block.registry(); if (registry.isBlockEntity()) { - final NBTCompound data = BlockUtils.extractClientNbt(block); + final CompoundBinaryTag data = BlockUtils.extractClientNbt(block); chunk.sendPacketToViewers(new BlockEntityDataPacket(blockPosition, registry.blockEntityId(), data)); } } diff --git a/src/main/java/net/minestom/server/instance/LightingChunk.java b/src/main/java/net/minestom/server/instance/LightingChunk.java index 4bbd33c83..66fbbe01d 100644 --- a/src/main/java/net/minestom/server/instance/LightingChunk.java +++ b/src/main/java/net/minestom/server/instance/LightingChunk.java @@ -1,5 +1,7 @@ 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.ServerFlag; import net.minestom.server.collision.Shape; @@ -16,8 +18,6 @@ import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.chunk.ChunkUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBT; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.*; import java.util.concurrent.CompletableFuture; @@ -202,14 +202,17 @@ public class LightingChunk extends DynamicChunk { } @Override - protected NBTCompound computeHeightmap() { + protected CompoundBinaryTag computeHeightmap() { // Heightmap int[] heightmap = getHeightmap(); int dimensionHeight = getInstance().getDimensionType().getHeight(); final int bitsForHeight = MathUtils.bitsToRepresent(dimensionHeight); - return NBT.Compound(Map.of( - "MOTION_BLOCKING", NBT.LongArray(encodeBlocks(heightmap, bitsForHeight)), - "WORLD_SURFACE", NBT.LongArray(encodeBlocks(heightmap, bitsForHeight)))); + + LongArrayBinaryTag encoded = LongArrayBinaryTag.longArrayBinaryTag(encodeBlocks(heightmap, bitsForHeight)); + return CompoundBinaryTag.builder() + .put("MOTION_BLOCKING", encoded) + .put("WORLD_SURFACE", encoded) + .build(); } // Lazy compute heightmap diff --git a/src/main/java/net/minestom/server/instance/block/Block.java b/src/main/java/net/minestom/server/instance/block/Block.java index 2f4f90cfb..f12ed3aa2 100644 --- a/src/main/java/net/minestom/server/instance/block/Block.java +++ b/src/main/java/net/minestom/server/instance/block/Block.java @@ -1,15 +1,15 @@ package net.minestom.server.instance.block; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.coordinate.Point; import net.minestom.server.instance.Instance; import net.minestom.server.instance.batch.Batch; -import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.registry.Registry; +import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.tag.Tag; import net.minestom.server.tag.TagReadable; import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.*; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.Collection; import java.util.Map; @@ -67,7 +67,7 @@ public sealed interface Block extends StaticProtocolObject, TagReadable, Blocks * @return a new block with different nbt */ @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}. @@ -86,7 +86,7 @@ public sealed interface Block extends StaticProtocolObject, TagReadable, Blocks * @return the block nbt, null if not present */ @Contract(pure = true) - @Nullable NBTCompound nbt(); + @Nullable CompoundBinaryTag nbt(); @Contract(pure = true) default boolean hasNbt() { diff --git a/src/main/java/net/minestom/server/instance/block/BlockImpl.java b/src/main/java/net/minestom/server/instance/block/BlockImpl.java index 6140b7fbe..6760f9464 100644 --- a/src/main/java/net/minestom/server/instance/block/BlockImpl.java +++ b/src/main/java/net/minestom/server/instance/block/BlockImpl.java @@ -4,6 +4,7 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.registry.Registry; import net.minestom.server.tag.Tag; import net.minestom.server.utils.ArrayUtils; @@ -14,8 +15,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.UnknownNullability; import org.jetbrains.annotations.Unmodifiable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound; import java.time.Duration; import java.util.*; @@ -23,7 +22,7 @@ import java.util.function.Function; record BlockImpl(@NotNull Registry.BlockEntry registry, byte @NotNull [] propertiesArray, - @Nullable NBTCompound nbt, + @Nullable CompoundBinaryTag nbt, @Nullable BlockHandler handler) implements Block { // Block state -> block object private static final ObjectArray BLOCK_STATE_MAP = ObjectArray.singleThread(); @@ -86,7 +85,7 @@ record BlockImpl(@NotNull Registry.BlockEntry registry, final int defaultState = properties.getInt("defaultStateId"); return getState(defaultState); }); - private static final Cache NBT_CACHE = Caffeine.newBuilder() + private static final Cache NBT_CACHE = Caffeine.newBuilder() .expireAfterWrite(Duration.ofMinutes(5)) .weakValues() .build(); @@ -144,14 +143,16 @@ record BlockImpl(@NotNull Registry.BlockEntry registry, @Override public @NotNull Block withTag(@NotNull Tag tag, @Nullable T value) { - var temporaryNbt = new MutableNBTCompound(Objects.requireNonNullElse(nbt, NBTCompound.EMPTY)); - tag.write(temporaryNbt, value); - final var finalNbt = temporaryNbt.getSize() > 0 ? NBT_CACHE.get(temporaryNbt.toCompound(), Function.identity()) : null; + var builder = CompoundBinaryTag.builder(); + if (nbt != null) builder.put(nbt); + 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); } @Override - public @NotNull Block withNbt(@Nullable NBTCompound compound) { + public @NotNull Block withNbt(@Nullable CompoundBinaryTag compound) { return new BlockImpl(registry, propertiesArray, compound, handler); } @@ -183,7 +184,7 @@ record BlockImpl(@NotNull Registry.BlockEntry registry, @Override public @UnknownNullability T getTag(@NotNull Tag tag) { - return tag.read(Objects.requireNonNullElse(nbt, NBTCompound.EMPTY)); + return tag.read(Objects.requireNonNullElse(nbt, CompoundBinaryTag.empty())); } private Map possibleProperties() { diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index bb2a99038..b0c17517c 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -1,5 +1,6 @@ package net.minestom.server.item; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.Component; import net.minestom.server.instance.block.Block; 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.Nullable; import org.jetbrains.annotations.UnknownNullability; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.*; import java.util.function.Consumer; @@ -26,7 +26,7 @@ public sealed interface ItemMeta extends TagReadable, NetworkBuffer.Writer @Contract(value = "_, -> new", pure = true) @NotNull ItemMeta with(@NotNull Consumer<@NotNull Builder> builderConsumer); - @NotNull NBTCompound toNBT(); + @NotNull CompoundBinaryTag toNBT(); @NotNull String toSNBT(); diff --git a/src/main/java/net/minestom/server/item/ItemMetaImpl.java b/src/main/java/net/minestom/server/item/ItemMetaImpl.java index 22483b9e5..063b40111 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaImpl.java +++ b/src/main/java/net/minestom/server/item/ItemMetaImpl.java @@ -1,16 +1,17 @@ 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.tag.Tag; import net.minestom.server.tag.TagHandler; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.UnknownNullability; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import java.io.IOException; import java.util.Objects; import java.util.function.Consumer; -import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.NBT; record ItemMetaImpl(TagHandler tagHandler) implements ItemMeta { @@ -29,23 +30,22 @@ record ItemMetaImpl(TagHandler tagHandler) implements ItemMeta { } @Override - public @NotNull NBTCompound toNBT() { + public @NotNull CompoundBinaryTag toNBT() { return tagHandler.asCompound(); } @Override 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 public void write(@NotNull NetworkBuffer writer) { - final NBTCompound nbt = toNBT(); - if (nbt.isEmpty()) { - writer.write(BYTE, (byte) 0); - return; - } - writer.write(NBT, nbt); + writer.write(NBT, toNBT()); } @Override diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index 4a3ca866b..cf23fbc56 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -1,5 +1,6 @@ package net.minestom.server.item; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.nbt.api.BinaryTagHolder; import net.kyori.adventure.text.Component; 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.utils.validate.Check; import org.jetbrains.annotations.*; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import java.io.IOException; import java.util.List; import java.util.function.Consumer; import java.util.function.IntUnaryOperator; @@ -47,13 +48,13 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource asHoverEvent(@NotNull UnaryOperator op) { - final BinaryTagHolder tagHolder = BinaryTagHolder.encode(meta().toNBT(), MinestomAdventure.NBT_CODEC); - return HoverEvent.showItem(op.apply(HoverEvent.ShowItem.showItem(material(), amount(), tagHolder))); + try { + 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 0) builder.put("tag", nbt); + return builder.build(); } @Contract(value = "-> new", pure = true) @@ -129,7 +126,7 @@ record ItemStackImpl(Material material, int amount, ItemMetaImpl meta) implement } @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))); } diff --git a/src/main/java/net/minestom/server/item/armor/TrimManager.java b/src/main/java/net/minestom/server/item/armor/TrimManager.java index c9c94aa1a..697965fe8 100644 --- a/src/main/java/net/minestom/server/item/armor/TrimManager.java +++ b/src/main/java/net/minestom/server/item/armor/TrimManager.java @@ -1,20 +1,19 @@ 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 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.Map; import java.util.Set; public class TrimManager { private final Set trimMaterials; private final Set trimPatterns; - private NBTCompound trimMaterialCache = null; - private NBTCompound trimPatternCache = null; + private CompoundBinaryTag trimMaterialCache = null; + private CompoundBinaryTag trimPatternCache = null; public TrimManager() { this.trimMaterials = new HashSet<>(); @@ -30,38 +29,28 @@ public class TrimManager { } - public NBTCompound getTrimMaterialNBT() { + public CompoundBinaryTag getTrimMaterialNBT() { if (trimMaterialCache == null) { - var trimMaterials = this.trimMaterials.stream() - .map((trimMaterial) -> NBT.Compound(Map.of( - "id", NBT.Int(trimMaterial.id()), - "name", NBT.String(trimMaterial.name()), - "element", trimMaterial.asNBT() - ))) - .toList(); - - trimMaterialCache = NBT.Compound(Map.of( - "type", NBT.String("minecraft:trim_material"), - "value", NBT.List(NBTType.TAG_Compound, trimMaterials) - )); + ListBinaryTag.Builder entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND); + for (TrimMaterial trimMaterial : this.trimMaterials) + entries.add(trimMaterial.asNBT()); + trimMaterialCache = CompoundBinaryTag.builder() + .putString("type", "minecraft:trim_material") + .put("value", entries.build()) + .build(); } return trimMaterialCache; } - public NBTCompound getTrimPatternNBT() { + public CompoundBinaryTag getTrimPatternNBT() { if (trimPatternCache == null) { - var trimPatterns = this.trimPatterns.stream() - .map((trimPattern) -> NBT.Compound(Map.of( - "id", NBT.Int(trimPattern.id()), - "name", NBT.String(trimPattern.name()), - "element", trimPattern.asNBT() - ))) - .toList(); - - trimPatternCache = NBT.Compound(Map.of( - "type", NBT.String("minecraft:trim_pattern"), - "value", NBT.List(NBTType.TAG_Compound, trimPatterns) - )); + ListBinaryTag.Builder entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND); + for (TrimPattern trimPattern : this.trimPatterns) + entries.add(trimPattern.asNBT()); + trimPatternCache = CompoundBinaryTag.builder() + .putString("type", "minecraft:trim_pattern") + .put("value", entries.build()) + .build(); } return trimPatternCache; diff --git a/src/main/java/net/minestom/server/item/armor/TrimMaterial.java b/src/main/java/net/minestom/server/item/armor/TrimMaterial.java index adb80be3d..0bf3bb3b4 100644 --- a/src/main/java/net/minestom/server/item/armor/TrimMaterial.java +++ b/src/main/java/net/minestom/server/item/armor/TrimMaterial.java @@ -1,13 +1,13 @@ package net.minestom.server.item.armor; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.Component; import net.minestom.server.item.Material; -import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.registry.Registry; +import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.Collection; import java.util.Map; @@ -84,6 +84,6 @@ public interface TrimMaterial extends StaticProtocolObject { return registry().description(); } - NBTCompound asNBT(); + CompoundBinaryTag asNBT(); } diff --git a/src/main/java/net/minestom/server/item/armor/TrimMaterialImpl.java b/src/main/java/net/minestom/server/item/armor/TrimMaterialImpl.java index 95fe79b4d..2af492f28 100644 --- a/src/main/java/net/minestom/server/item/armor/TrimMaterialImpl.java +++ b/src/main/java/net/minestom/server/item/armor/TrimMaterialImpl.java @@ -1,9 +1,9 @@ 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.registry.Registry; -import org.jglrxavpok.hephaistos.nbt.NBT; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.Collection; import java.util.Map; @@ -31,19 +31,15 @@ record TrimMaterialImpl(Registry.TrimMaterialEntry registry, int id) implements return CONTAINER.values(); } - public NBTCompound asNBT() { - return NBT.Compound(nbt -> { - nbt.setString("asset_name", assetName()); - nbt.setString("ingredient", ingredient().namespace().asString()); - nbt.setFloat("item_model_index", itemModelIndex()); - nbt.set("override_armor_materials", NBT.Compound(overrideArmorMaterials().entrySet().stream() - .collect(Collectors.toMap( - Map.Entry::getKey, - entry -> NBT.String(entry.getValue()) - )) - )); - nbt.set("description", NbtComponentSerializer.nbt().serialize(description())); - }); + public CompoundBinaryTag asNBT() { + return CompoundBinaryTag.builder() + .putString("asset_name", assetName()) + .putString("ingredient", ingredient().namespace().asString()) + .putFloat("item_model_index", itemModelIndex()) + .put("override_armor_materials", CompoundBinaryTag.from(overrideArmorMaterials().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> StringBinaryTag.stringBinaryTag(entry.getValue()))))) + .put("description", NbtComponentSerializer.nbt().serialize(description())) + .build(); } } diff --git a/src/main/java/net/minestom/server/item/armor/TrimPattern.java b/src/main/java/net/minestom/server/item/armor/TrimPattern.java index 1823e42bc..7b824ba0d 100644 --- a/src/main/java/net/minestom/server/item/armor/TrimPattern.java +++ b/src/main/java/net/minestom/server/item/armor/TrimPattern.java @@ -1,13 +1,13 @@ package net.minestom.server.item.armor; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.Component; import net.minestom.server.item.Material; -import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.registry.Registry; +import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.Collection; @@ -61,6 +61,6 @@ public interface TrimPattern extends StaticProtocolObject { return registry().decal(); } - NBTCompound asNBT(); + CompoundBinaryTag asNBT(); } diff --git a/src/main/java/net/minestom/server/item/armor/TrimPatternImpl.java b/src/main/java/net/minestom/server/item/armor/TrimPatternImpl.java index 6b4ecd1aa..9d4df9ed0 100644 --- a/src/main/java/net/minestom/server/item/armor/TrimPatternImpl.java +++ b/src/main/java/net/minestom/server/item/armor/TrimPatternImpl.java @@ -1,9 +1,8 @@ package net.minestom.server.item.armor; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer; 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.concurrent.atomic.AtomicInteger; @@ -29,13 +28,13 @@ record TrimPatternImpl(Registry.TrimPatternEntry registry, int id) implements Tr return CONTAINER.values(); } - public NBTCompound asNBT() { - return NBT.Compound(nbt -> { - nbt.setString("asset_id", assetID().asString()); - nbt.setString("template_item", template().namespace().asString()); - nbt.set("description", NbtComponentSerializer.nbt().serialize(description())); - nbt.setByte("decal", (byte) (decal() ? 1 : 0)); - }); + public CompoundBinaryTag asNBT() { + return CompoundBinaryTag.builder() + .putString("asset_id", assetID().asString()) + .putString("template_item", template().namespace().asString()) + .put("description", NbtComponentSerializer.nbt().serialize(description())) + .putBoolean("decal", decal()) + .build(); } } diff --git a/src/main/java/net/minestom/server/item/firework/FireworkEffect.java b/src/main/java/net/minestom/server/item/firework/FireworkEffect.java index 4cbe1570f..e9feaebee 100644 --- a/src/main/java/net/minestom/server/item/firework/FireworkEffect.java +++ b/src/main/java/net/minestom/server/item/firework/FireworkEffect.java @@ -1,14 +1,11 @@ package net.minestom.server.item.firework; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.color.Color; 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.List; -import java.util.Map; public record FireworkEffect(boolean flicker, boolean trail, @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. * @return A new created firework effect. */ - public static @NotNull FireworkEffect fromCompound(@NotNull NBTCompound compound) { + public static @NotNull FireworkEffect fromCompound(@NotNull CompoundBinaryTag compound) { List primaryColor = new ArrayList<>(); List secondaryColor = new ArrayList<>(); - if (compound.get("Colors") instanceof NBTIntArray colors) { - for (int rgb : colors) primaryColor.add(new Color(rgb)); - } - if (compound.get("FadeColors") instanceof NBTIntArray fadeColors) { - for (int rgb : fadeColors) secondaryColor.add(new Color(rgb)); - } + for (int rgb : compound.getIntArray("Colors")) + primaryColor.add(new Color(rgb)); + for (int rgb : compound.getIntArray("FadeColors")) + secondaryColor.add(new Color(rgb)); - boolean flicker = compound.containsKey("Flicker") && compound.getBoolean("Flicker"); - boolean trail = compound.containsKey("Trail") && compound.getBoolean("Trail"); - FireworkEffectType type = compound.containsKey("Type") ? - FireworkEffectType.byId(compound.getAsByte("Type")) : FireworkEffectType.SMALL_BALL; + boolean flicker = compound.getBoolean("Flicker"); + boolean trail = compound.getBoolean("Trail"); + FireworkEffectType type = FireworkEffectType.byId(compound.getByte("Type")); 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. */ - public @NotNull NBTCompound asCompound() { - return NBT.Compound(Map.of( - "Flicker", NBT.Boolean(flicker), - "Trail", NBT.Boolean(trail), - "Type", NBT.Byte(type.getType()), - "Colors", NBT.IntArray(colors.stream().mapToInt(Color::asRGB).toArray()), - "FadeColors", NBT.IntArray(fadeColors.stream().mapToInt(Color::asRGB).toArray()))); + public @NotNull CompoundBinaryTag asCompound() { + return CompoundBinaryTag.builder() + .putBoolean("Flicker", flicker) + .putBoolean("Trail", trail) + .putByte("Type", (byte) type.getType()) + .putIntArray("Colors", colors.stream().mapToInt(Color::asRGB).toArray()) + .putIntArray("FadeColors", fadeColors.stream().mapToInt(Color::asRGB).toArray()) + .build(); } } diff --git a/src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java b/src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java index b22c19577..40b4ca98d 100644 --- a/src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java @@ -1,32 +1,30 @@ 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.item.ItemMetaView; import net.minestom.server.tag.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; 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.Map; import java.util.Objects; import java.util.UUID; public record PlayerHeadMeta(TagReadable readable) implements ItemMetaView { public static final Tag SKULL_OWNER = Tag.UUID("Id").path("SkullOwner"); public static final Tag SKIN = Tag.Structure("Properties", new TagSerializer() { - private static final Tag TEXTURES = Tag.NBT("textures"); + private static final Tag TEXTURES = Tag.NBT("textures"); @Override public @Nullable PlayerSkin read(@NotNull TagReadable reader) { - final NBT result = reader.getTag(TEXTURES); - if (!(result instanceof NBTList)) return null; - final NBTList textures = (NBTList) result; - final NBTCompound texture = textures.get(0); + final BinaryTag result = reader.getTag(TEXTURES); + if (!(result instanceof ListBinaryTag textures)) return null; + final CompoundBinaryTag texture = textures.getCompound(0); final String value = texture.getString("Value"); final String signature = texture.getString("Signature"); return new PlayerSkin(value, signature); @@ -36,9 +34,9 @@ public record PlayerHeadMeta(TagReadable readable) implements ItemMetaView textures = new NBTList<>(NBTType.TAG_Compound, - List.of(NBT.Compound(Map.of("Value", NBT.String(value), "Signature", NBT.String(signature))))); - writer.setTag(TEXTURES, textures); + writer.setTag(TEXTURES, ListBinaryTag.listBinaryTag(BinaryTagTypes.COMPOUND, List.of( + CompoundBinaryTag.builder().putString("Value", value).putString("Signature", signature).build() + ))); } }).path("SkullOwner"); diff --git a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java index 9c3beec2c..7949139ec 100644 --- a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java @@ -1,5 +1,6 @@ package net.minestom.server.listener; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; 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.utils.block.BlockUtils; import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; 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) var registry = diggingResult.block().registry(); 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)); } } diff --git a/src/main/java/net/minestom/server/message/Messenger.java b/src/main/java/net/minestom/server/message/Messenger.java index 16af3663e..df3d09acb 100644 --- a/src/main/java/net/minestom/server/message/Messenger.java +++ b/src/main/java/net/minestom/server/message/Messenger.java @@ -1,5 +1,7 @@ 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.format.NamedTextColor; 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 org.jetbrains.annotations.NotNull; 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.Objects; 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 SystemChatPacket CANNOT_SEND_PACKET = new SystemChatPacket(CANNOT_SEND_MESSAGE, false); - private static final NBTCompound CHAT_REGISTRY; + private static final CompoundBinaryTag CHAT_REGISTRY; static { try { - CHAT_REGISTRY = (NBTCompound) new SNBTParser(new StringReader( + CHAT_REGISTRY = TagStringIO.get().asCompound( """ { "type": "minecraft:chat_type", @@ -57,13 +56,13 @@ public final class Messenger { } } ] }""" - )).parse(); - } catch (NBTException e) { + ); + } catch (IOException e) { throw new RuntimeException(e); } } - public static @NotNull NBTCompound chatRegistry() { + public static @NotNull CompoundBinaryTag chatRegistry() { return CHAT_REGISTRY; } diff --git a/src/main/java/net/minestom/server/network/ConnectionManager.java b/src/main/java/net/minestom/server/network/ConnectionManager.java index 48508908f..ec78114e9 100644 --- a/src/main/java/net/minestom/server/network/ConnectionManager.java +++ b/src/main/java/net/minestom/server/network/ConnectionManager.java @@ -1,5 +1,6 @@ package net.minestom.server.network; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.MinecraftServer; @@ -32,7 +33,8 @@ import org.jctools.queues.MpscUnboundedArrayQueue; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; 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.concurrent.CompletableFuture; @@ -280,14 +282,15 @@ public final class ConnectionManager { // Registry data (if it should be sent) if (event.willSendRegistryData()) { - var registry = new HashMap(); - registry.put("minecraft:chat_type", Messenger.chatRegistry()); - registry.put("minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT()); - registry.put("minecraft:worldgen/biome", MinecraftServer.getBiomeManager().toNBT()); - registry.put("minecraft:damage_type", DamageType.getNBT()); - registry.put("minecraft:trim_material", MinecraftServer.getTrimManager().getTrimMaterialNBT()); - registry.put("minecraft:trim_pattern", MinecraftServer.getTrimManager().getTrimPatternNBT()); - player.sendPacket(new RegistryDataPacket(NBT.Compound(registry))); + var registryCompound = CompoundBinaryTag.builder() + .put("minecraft:chat_type", Messenger.chatRegistry()) + .put("minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT()) + .put("minecraft:worldgen/biome", MinecraftServer.getBiomeManager().toNBT()) + .put("minecraft:damage_type", DamageType.getNBT()) +// .put("minecraft:trim_material", MinecraftServer.getTrimManager().getTrimMaterialNBT()) +// .put("minecraft:trim_pattern", MinecraftServer.getTrimManager().getTrimPatternNBT()) + .build(); + player.sendPacket(new RegistryDataPacket(registryCompound)); player.sendPacket(TagsPacket.DEFAULT_TAGS); } diff --git a/src/main/java/net/minestom/server/network/NetworkBuffer.java b/src/main/java/net/minestom/server/network/NetworkBuffer.java index 67ad28666..cc8b5a3b2 100644 --- a/src/main/java/net/minestom/server/network/NetworkBuffer.java +++ b/src/main/java/net/minestom/server/network/NetworkBuffer.java @@ -1,5 +1,6 @@ package net.minestom.server.network; +import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.text.Component; import net.minestom.server.coordinate.Point; 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.NotNull; 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.ByteOrder; import java.util.*; @@ -40,7 +40,7 @@ public final class NetworkBuffer { public static final Type VAR_LONG = new NetworkBufferTypeImpl.VarLongType(); public static final Type RAW_BYTES = new NetworkBufferTypeImpl.RawBytesType(); public static final Type STRING = new NetworkBufferTypeImpl.StringType(); - public static final Type NBT = new NetworkBufferTypeImpl.NbtType(); + public static final Type NBT = new NetworkBufferTypeImpl.NbtType(); public static final Type BLOCK_POSITION = new NetworkBufferTypeImpl.BlockPositionType(); public static final Type COMPONENT = new NetworkBufferTypeImpl.ComponentType(); public static final Type JSON_COMPONENT = new NetworkBufferTypeImpl.JsonComponentType(); @@ -81,8 +81,8 @@ public final class NetworkBuffer { int writeIndex; int readIndex; - NBTWriter nbtWriter; - NBTReader nbtReader; + DataOutput nbtWriter; + DataInput nbtReader; public NetworkBuffer(@NotNull ByteBuffer buffer, boolean resizable) { this.nioBuffer = buffer.order(ByteOrder.BIG_ENDIAN); diff --git a/src/main/java/net/minestom/server/network/packet/server/configuration/RegistryDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/configuration/RegistryDataPacket.java index 2b0d4d2ca..1d8aa950a 100644 --- a/src/main/java/net/minestom/server/network/packet/server/configuration/RegistryDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/configuration/RegistryDataPacket.java @@ -1,16 +1,16 @@ 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.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; 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) { - this((NBTCompound) buffer.read(NBT)); + this((CompoundBinaryTag) buffer.read(NBT)); } @Override diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java index f878bfbeb..e990226a7 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java @@ -1,19 +1,19 @@ package net.minestom.server.network.packet.server.play; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import static net.minestom.server.network.NetworkBuffer.*; 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) { - 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 diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java index 0e0b02bf5..35e97f6f1 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java @@ -1,20 +1,20 @@ 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.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.potion.Potion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import static net.minestom.server.network.NetworkBuffer.*; 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) { 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 diff --git a/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java index 904009817..d48187ec2 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java @@ -1,16 +1,17 @@ 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.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; 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) { - this(reader.read(VAR_INT), (NBTCompound) reader.read(NBT)); + this(reader.read(VAR_INT), (CompoundBinaryTag) reader.read(NBT)); } @Override diff --git a/src/main/java/net/minestom/server/network/packet/server/play/data/ChunkData.java b/src/main/java/net/minestom/server/network/packet/server/play/data/ChunkData.java index c0126205d..877832732 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/data/ChunkData.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/data/ChunkData.java @@ -1,12 +1,12 @@ 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.instance.block.Block; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.block.BlockUtils; import net.minestom.server.utils.chunk.ChunkUtils; import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.HashMap; import java.util.Map; @@ -14,7 +14,7 @@ import java.util.stream.Collectors; 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 blockEntities) implements NetworkBuffer.Writer { public ChunkData { blockEntities = blockEntities.entrySet() @@ -24,7 +24,7 @@ public record ChunkData(@NotNull NBTCompound heightmaps, byte @NotNull [] data, } 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)); } @@ -46,7 +46,7 @@ public record ChunkData(@NotNull NBTCompound heightmaps, byte @NotNull [] data, writer.write(SHORT, (short) point.blockY()); // y writer.write(VAR_INT, registry.blockEntityId()); - final NBTCompound nbt = BlockUtils.extractClientNbt(block); + final CompoundBinaryTag nbt = BlockUtils.extractClientNbt(block); assert nbt != null; 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 short y = reader.read(SHORT); 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 } return blockEntities; diff --git a/src/main/java/net/minestom/server/permission/Permission.java b/src/main/java/net/minestom/server/permission/Permission.java index 1959e2569..1b7987572 100644 --- a/src/main/java/net/minestom/server/permission/Permission.java +++ b/src/main/java/net/minestom/server/permission/Permission.java @@ -1,23 +1,23 @@ package net.minestom.server.permission; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.Objects; /** * Representation of a permission granted to a {@link CommandSender}. * 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. *

* The class is immutable. */ public class Permission { private final String permissionName; - private final NBTCompound data; + private final CompoundBinaryTag data; /** * Creates a new permission object with optional data. @@ -25,7 +25,7 @@ public class Permission { * @param permissionName the name 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.data = data; } @@ -55,7 +55,7 @@ public class Permission { * @return the nbt data of this permission, can be null if not any */ @Nullable - public NBTCompound getNBTData() { + public CompoundBinaryTag getNBTData() { return data; } diff --git a/src/main/java/net/minestom/server/permission/PermissionHandler.java b/src/main/java/net/minestom/server/permission/PermissionHandler.java index 0683e3497..a4a028a2c 100644 --- a/src/main/java/net/minestom/server/permission/PermissionHandler.java +++ b/src/main/java/net/minestom/server/permission/PermissionHandler.java @@ -2,8 +2,6 @@ package net.minestom.server.permission; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.parser.SNBTParser; import java.util.Set; import java.util.regex.Pattern; @@ -14,8 +12,7 @@ import java.util.regex.Pattern; * Permissions are in-memory only by default. * You have however the capacity to store them persistently as the {@link Permission} object * is serializer-friendly, {@link Permission#getPermissionName()} being a {@link String} - * and {@link Permission#getNBTData()} serializable into a string using {@link NBTCompound#toSNBT()} - * and deserialized back with {@link SNBTParser#parse()}. + * and {@link Permission#getNBTData()} serializable into a string using {@link net.kyori.adventure.nbt.TagStringIO}. */ public interface PermissionHandler { diff --git a/src/main/java/net/minestom/server/permission/PermissionVerifier.java b/src/main/java/net/minestom/server/permission/PermissionVerifier.java index 51323b5d8..99797569c 100644 --- a/src/main/java/net/minestom/server/permission/PermissionVerifier.java +++ b/src/main/java/net/minestom/server/permission/PermissionVerifier.java @@ -1,10 +1,10 @@ package net.minestom.server.permission; +import net.kyori.adventure.nbt.CompoundBinaryTag; 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 public interface PermissionVerifier { @@ -16,5 +16,5 @@ public interface PermissionVerifier { * @return true if {@link PermissionHandler#hasPermission(String, PermissionVerifier)} * should return true, false otherwise */ - boolean isValid(@Nullable NBTCompound nbtCompound); + boolean isValid(@Nullable CompoundBinaryTag nbtCompound); } diff --git a/src/main/java/net/minestom/server/tag/Serializers.java b/src/main/java/net/minestom/server/tag/Serializers.java index 9d14f112b..8a37efc5e 100644 --- a/src/main/java/net/minestom/server/tag/Serializers.java +++ b/src/main/java/net/minestom/server/tag/Serializers.java @@ -1,10 +1,10 @@ package net.minestom.server.tag; +import net.kyori.adventure.nbt.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minestom.server.ServerFlag; import net.minestom.server.item.ItemStack; -import org.jglrxavpok.hephaistos.nbt.*; import java.util.UUID; import java.util.function.Function; @@ -13,40 +13,41 @@ import java.util.function.Function; * Basic serializers for {@link Tag tags}. */ final class Serializers { - static final Entry BYTE = new Entry<>(NBTType.TAG_Byte, NBTByte::getValue, NBT::Byte); - static final Entry BOOLEAN = new Entry<>(NBTType.TAG_Byte, NBTByte::asBoolean, NBT::Boolean); - static final Entry SHORT = new Entry<>(NBTType.TAG_Short, NBTShort::getValue, NBT::Short); - static final Entry INT = new Entry<>(NBTType.TAG_Int, NBTInt::getValue, NBT::Int); - static final Entry LONG = new Entry<>(NBTType.TAG_Long, NBTLong::getValue, NBT::Long); - static final Entry FLOAT = new Entry<>(NBTType.TAG_Float, NBTFloat::getValue, NBT::Float); - static final Entry DOUBLE = new Entry<>(NBTType.TAG_Double, NBTDouble::getValue, NBT::Double); - static final Entry STRING = new Entry<>(NBTType.TAG_String, NBTString::getValue, NBT::String); - static final Entry NBT_ENTRY = new Entry<>(null, Function.identity(), Function.identity()); + static final Entry BYTE = new Entry<>(BinaryTagTypes.BYTE, ByteBinaryTag::value, ByteBinaryTag::byteBinaryTag); + static final Entry BOOLEAN = new Entry<>(BinaryTagTypes.BYTE, b -> b.value() != 0, b -> b ? ByteBinaryTag.ONE : ByteBinaryTag.ZERO); + static final Entry SHORT = new Entry<>(BinaryTagTypes.SHORT, ShortBinaryTag::value, ShortBinaryTag::shortBinaryTag); + static final Entry INT = new Entry<>(BinaryTagTypes.INT, IntBinaryTag::value, IntBinaryTag::intBinaryTag); + static final Entry LONG = new Entry<>(BinaryTagTypes.LONG, LongBinaryTag::value, LongBinaryTag::longBinaryTag); + static final Entry FLOAT = new Entry<>(BinaryTagTypes.FLOAT, FloatBinaryTag::value, FloatBinaryTag::floatBinaryTag); + static final Entry DOUBLE = new Entry<>(BinaryTagTypes.DOUBLE, DoubleBinaryTag::value, DoubleBinaryTag::doubleBinaryTag); + static final Entry STRING = new Entry<>(BinaryTagTypes.STRING, StringBinaryTag::value, StringBinaryTag::stringBinaryTag); + static final Entry NBT_ENTRY = new Entry<>(null, Function.identity(), Function.identity()); - static final Entry UUID = new Entry<>(NBTType.TAG_Int_Array, intArray -> intArrayToUuid(intArray.getValue().copyArray()), - uuid -> NBT.IntArray(uuidToIntArray(uuid))); - static final Entry ITEM = new Entry<>(NBTType.TAG_Compound, ItemStack::fromItemNBT, ItemStack::toItemNBT); - static final Entry COMPONENT = new Entry<>(NBTType.TAG_String, input -> GsonComponentSerializer.gson().deserialize(input.getValue()), - component -> NBT.String(GsonComponentSerializer.gson().serialize(component))); + static final Entry UUID = new Entry<>(BinaryTagTypes.INT_ARRAY, + intArray -> intArrayToUuid(intArray.value()), + uuid -> IntArrayBinaryTag.intArrayBinaryTag(uuidToIntArray(uuid))); + static final Entry ITEM = new Entry<>(BinaryTagTypes.COMPOUND, ItemStack::fromItemNBT, ItemStack::toItemNBT); + static final Entry COMPONENT = new Entry<>(BinaryTagTypes.STRING, input -> GsonComponentSerializer.gson().deserialize(input.value()), + component -> StringBinaryTag.stringBinaryTag(GsonComponentSerializer.gson().serialize(component))); - static final Entry EMPTY = new Entry<>(NBTType.TAG_Byte, unused -> null, component -> null); + static final Entry EMPTY = new Entry<>(BinaryTagTypes.BYTE, unused -> null, component -> null); - static Entry fromTagSerializer(TagSerializer serializer) { - return new Serializers.Entry<>(NBTType.TAG_Compound, - (NBTCompound compound) -> { - if ((!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && compound.isEmpty()) return null; + static Entry fromTagSerializer(TagSerializer serializer) { + return new Serializers.Entry<>(BinaryTagTypes.COMPOUND, + (CompoundBinaryTag compound) -> { + if ((!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && compound.size() == 0) return null; return serializer.read(TagHandler.fromCompound(compound)); }, (value) -> { - if (value == null) return NBTCompound.EMPTY; + if (value == null) return CompoundBinaryTag.empty(); TagHandler handler = TagHandler.newHandler(); serializer.write(handler, value); return handler.asCompound(); }); } - record Entry(NBTType nbtType, Function reader, Function writer, boolean isPath) { - Entry(NBTType nbtType, Function reader, Function writer) { + record Entry(BinaryTagType nbtType, Function reader, Function writer, boolean isPath) { + Entry(BinaryTagType nbtType, Function reader, Function writer) { this(nbtType, reader, writer, false); } diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index 807cc3678..a6a448e28 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -1,5 +1,6 @@ package net.minestom.server.tag; +import net.kyori.adventure.nbt.*; import net.kyori.adventure.text.Component; import net.minestom.server.item.ItemStack; 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.NotNull; 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.List; @@ -37,7 +33,7 @@ public class Tag { final int index; private final String key; - final Serializers.Entry entry; + final Serializers.Entry entry; private final Supplier defaultValue; final Function readComparator; @@ -48,7 +44,7 @@ public class Tag { Tag(int index, String key, Function readComparator, - Serializers.Entry entry, + Serializers.Entry entry, Supplier defaultValue, PathEntry[] path, UnaryOperator copy, int listScope) { assert index == INDEX_MAP.get(key); this.index = index; @@ -61,8 +57,8 @@ public class Tag { this.listScope = listScope; } - static Tag tag(@NotNull String key, @NotNull Serializers.Entry entry) { - return new Tag<>(INDEX_MAP.get(key), key, entry.reader(), (Serializers.Entry) entry, + static Tag tag(@NotNull String key, @NotNull Serializers.Entry entry) { + return new Tag<>(INDEX_MAP.get(key), key, entry.reader(), (Serializers.Entry) entry, null, null, null, 0); } @@ -98,11 +94,11 @@ public class Tag { public Tag map(@NotNull Function readMap, @NotNull Function writeMap) { var entry = this.entry; - final Function readFunction = entry.reader().andThen(t -> { + final Function readFunction = entry.reader().andThen(t -> { if (t == null) return null; return readMap.apply(t); }); - final Function writeFunction = writeMap.andThen(entry.writer()); + final Function writeFunction = writeMap.andThen(entry.writer()); return new Tag<>(index, key, readMap, new Serializers.Entry<>(entry.nbtType(), readFunction, writeFunction), // Default value @@ -120,18 +116,18 @@ public class Tag { var entry = this.entry; var readFunction = entry.reader(); var writeFunction = entry.writer(); - var listEntry = new Serializers.Entry, NBTList>( - NBTType.TAG_List, + var listEntry = new Serializers.Entry, ListBinaryTag>( + BinaryTagTypes.LIST, read -> { - if (read.isEmpty()) return List.of(); - return read.asListView().stream().map(readFunction).toList(); + if (read.size() == 0) return List.of(); + return read.stream().map(readFunction).toList(); }, write -> { if (write.isEmpty()) - return NBT.List(NBTType.TAG_String); // String is the default type for lists - final List list = write.stream().map(writeFunction).toList(); - final NBTType type = list.get(0).getID(); - return NBT.List(type, list); + return ListBinaryTag.empty(); + final List list = write.stream().map(writeFunction).toList(); + final BinaryTagType type = list.get(0).type(); + return ListBinaryTag.listBinaryTag(type, list); }); UnaryOperator> co = this.copy != null ? ts -> { final int size = ts.size(); @@ -165,8 +161,8 @@ public class Tag { return new Tag<>(index, key, readComparator, entry, defaultValue, pathEntries, copy, listScope); } - public @Nullable T read(@NotNull NBTCompoundLike nbt) { - final NBT readable = isView() ? nbt.toCompound() : nbt.get(key); + public @Nullable T read(@NotNull CompoundBinaryTag nbt) { + final BinaryTag readable = isView() ? nbt : nbt.get(key); final T result; try { if (readable == null || (result = entry.read(readable)) == null) @@ -177,18 +173,20 @@ public class Tag { } } - public void write(@NotNull MutableNBTCompound nbtCompound, @Nullable T value) { + public void write(@NotNull CompoundBinaryTag.Builder nbtCompound, @Nullable T value) { if (value != null) { - final NBT nbt = entry.write(value); - if (isView()) nbtCompound.copyFrom((NBTCompoundLike) nbt); - else nbtCompound.set(key, nbt); + final BinaryTag nbt = entry.write(value); + if (isView()) nbtCompound.put((CompoundBinaryTag) nbt); + else nbtCompound.put(key, nbt); } else { - if (isView()) nbtCompound.clear(); - else nbtCompound.remove(key); + if (isView()) { + // 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 write(nbtCompound, (T) value); } @@ -279,11 +277,11 @@ public class Tag { } /** - * 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. *

* Specialized tags are recommended if the type is known as conversion will be required both way (read and write). */ - public static @NotNull Tag NBT(@NotNull String key) { + public static @NotNull Tag NBT(@NotNull String key) { return tag(key, Serializers.NBT_ENTRY); } diff --git a/src/main/java/net/minestom/server/tag/TagHandler.java b/src/main/java/net/minestom/server/tag/TagHandler.java index ded8d4487..241ccf4d4 100644 --- a/src/main/java/net/minestom/server/tag/TagHandler.java +++ b/src/main/java/net/minestom/server/tag/TagHandler.java @@ -1,10 +1,9 @@ package net.minestom.server.tag; +import net.kyori.adventure.nbt.CompoundBinaryTag; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.UnknownNullability; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.nbt.NBTCompoundLike; import java.util.function.UnaryOperator; @@ -26,7 +25,7 @@ public interface TagHandler extends TagReadable, TagWritable { /** * Creates a copy of this handler. *

- * 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. * * @return a copy of this handler @@ -36,18 +35,18 @@ public interface TagHandler extends TagReadable, TagWritable { /** * Updates the content of this handler. *

- * 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 */ - 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 */ - @NotNull NBTCompound asCompound(); + @NotNull CompoundBinaryTag asCompound(); @ApiStatus.Experimental void updateTag(@NotNull Tag 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 * @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); } } diff --git a/src/main/java/net/minestom/server/tag/TagHandlerImpl.java b/src/main/java/net/minestom/server/tag/TagHandlerImpl.java index 6f0403182..702d16cc3 100644 --- a/src/main/java/net/minestom/server/tag/TagHandlerImpl.java +++ b/src/main/java/net/minestom/server/tag/TagHandlerImpl.java @@ -1,22 +1,21 @@ 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 org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; 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.util.Map; import java.util.function.UnaryOperator; final class TagHandlerImpl implements TagHandler { - static final Serializers.Entry NODE_SERIALIZER = new Serializers.Entry<>(NBTType.TAG_Compound, entries -> fromCompound(entries).root, Node::compound, true); + static final Serializers.Entry NODE_SERIALIZER = new Serializers.Entry<>(BinaryTagTypes.COMPOUND, entries -> fromCompound(entries).root, Node::compound, true); private final Node root; private volatile Node copy; @@ -29,8 +28,7 @@ final class TagHandlerImpl implements TagHandler { this.root = new Node(); } - static TagHandlerImpl fromCompound(NBTCompoundLike compoundLike) { - final NBTCompound compound = compoundLike.toCompound(); + static TagHandlerImpl fromCompound(CompoundBinaryTag compound) { TagHandlerImpl handler = new TagHandlerImpl(); TagNbtSeparator.separate(compound, entry -> handler.setTag(entry.tag(), entry.value())); handler.root.compound = compound; @@ -50,7 +48,7 @@ final class TagHandlerImpl implements TagHandler { synchronized (this) { Node syncNode = traversePathWrite(root, tag, value != 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(); } } @@ -103,7 +101,7 @@ final class TagHandlerImpl implements TagHandler { if (tag.isView()) { final T previousValue = tag.read(node.compound()); final T newValue = value.apply(previousValue); - node.updateContent((NBTCompoundLike) tag.entry.write(newValue)); + node.updateContent((CompoundBinaryTag) tag.entry.write(newValue)); node.invalidate(); return returnPrevious ? previousValue : newValue; } @@ -116,7 +114,7 @@ final class TagHandlerImpl implements TagHandler { if (previousEntry != null) { final Object previousTmp = previousEntry.value; 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); } else { previousValue = (T) previousTmp; @@ -149,12 +147,12 @@ final class TagHandlerImpl implements TagHandler { } @Override - public synchronized void updateContent(@NotNull NBTCompoundLike compound) { + public synchronized void updateContent(@NotNull CompoundBinaryTag compound) { this.root.updateContent(compound); } @Override - public @NotNull NBTCompound asCompound() { + public @NotNull CompoundBinaryTag asCompound() { VarHandle.fullFence(); 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 Node tmp = local; local = new Node(tmp); - if (synEntry != null && synEntry.updatedNbt() instanceof NBTCompound compound) { + if (synEntry != null && synEntry.updatedNbt() instanceof CompoundBinaryTag compound) { local.updateContent(compound); } tmp.entries.put(pathIndex, Entry.makePathEntry(path.name(), local)); @@ -211,8 +209,8 @@ final class TagHandlerImpl implements TagHandler { } private Entry valueToEntry(Node parent, Tag tag, @NotNull T value) { - if (value instanceof NBT nbt) { - if (nbt instanceof NBTCompound compound) { + if (value instanceof BinaryTag nbt) { + if (nbt instanceof CompoundBinaryTag compound) { final TagHandlerImpl handler = fromCompound(compound); return Entry.makePathEntry(tag, new Node(parent, handler.root.entries)); } else { @@ -227,7 +225,7 @@ final class TagHandlerImpl implements TagHandler { final class Node implements TagReadable { final Node parent; final StaticIntMap> entries; - NBTCompound compound; + CompoundBinaryTag compound; public Node(Node parent, StaticIntMap> entries) { this.parent = parent; @@ -260,44 +258,43 @@ final class TagHandlerImpl implements TagHandler { return (T) entry.value; } // Value must be parsed from nbt if the tag is different - final NBT nbt = entry.updatedNbt(); - final Serializers.Entry serializerEntry = tag.entry; - final NBTType type = serializerEntry.nbtType(); - return type == null || type == nbt.getID() ? serializerEntry.read(nbt) : tag.createDefault(); + final BinaryTag nbt = entry.updatedNbt(); + final Serializers.Entry serializerEntry = tag.entry; + final BinaryTagType type = serializerEntry.nbtType(); + return type == null || type.equals(nbt.type()) ? serializerEntry.read(nbt) : tag.createDefault(); } - void updateContent(@NotNull NBTCompoundLike compoundLike) { - final NBTCompound compound = compoundLike.toCompound(); + void updateContent(@NotNull CompoundBinaryTag compound) { final TagHandlerImpl converted = fromCompound(compound); this.entries.updateContent(converted.root.entries); this.compound = compound; } - NBTCompound compound() { - NBTCompound compound; + CompoundBinaryTag compound() { + CompoundBinaryTag compound; if (!ServerFlag.TAG_HANDLER_CACHE_ENABLED || (compound = this.compound) == null) { - MutableNBTCompound tmp = new MutableNBTCompound(); + CompoundBinaryTag.Builder tmp = CompoundBinaryTag.builder(); this.entries.forValues(entry -> { final Tag tag = entry.tag; - final NBT nbt = entry.updatedNbt(); - if (nbt != null && (!tag.entry.isPath() || (!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && !((NBTCompound) nbt).isEmpty())) { + final BinaryTag nbt = entry.updatedNbt(); + if (nbt != null && (!tag.entry.isPath() || (!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && ((CompoundBinaryTag) nbt).size() > 0)) { tmp.put(tag.getKey(), nbt); } }); - this.compound = compound = tmp.toCompound(); + this.compound = compound = tmp.build(); } return compound; } @Contract("null -> !null") Node copy(Node parent) { - MutableNBTCompound tmp = new MutableNBTCompound(); + CompoundBinaryTag.Builder tmp = CompoundBinaryTag.builder(); Node result = new Node(parent, new StaticIntMap.Array<>()); StaticIntMap> entries = result.entries; this.entries.forValues(entry -> { Tag tag = entry.tag; Object value = entry.value; - NBT nbt; + BinaryTag nbt; if (value instanceof Node node) { Node copy = node.copy(result); if (copy == null) @@ -313,9 +310,10 @@ final class TagHandlerImpl implements TagHandler { tmp.put(tag.getKey(), nbt); 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 - result.compound = tmp.toCompound(); + result.compound = compound; return result; } @@ -330,7 +328,7 @@ final class TagHandlerImpl implements TagHandler { private static final class Entry { private final Tag tag; T value; - NBT nbt; + BinaryTag nbt; Entry(Tag tag, T value) { this.tag = tag; @@ -345,9 +343,9 @@ final class TagHandlerImpl implements TagHandler { return makePathEntry(tag.getKey(), node); } - NBT updatedNbt() { + BinaryTag updatedNbt() { 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); return nbt; } @@ -360,7 +358,7 @@ final class TagHandlerImpl implements TagHandler { Node toNode() { 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 // TODO should the handler be cached inside the entry? return fromCompound(compound).root; diff --git a/src/main/java/net/minestom/server/tag/TagNbtSeparator.java b/src/main/java/net/minestom/server/tag/TagNbtSeparator.java index d0300f1b6..f6e43cfd6 100644 --- a/src/main/java/net/minestom/server/tag/TagNbtSeparator.java +++ b/src/main/java/net/minestom/server/tag/TagNbtSeparator.java @@ -1,9 +1,7 @@ package net.minestom.server.tag; -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 net.kyori.adventure.nbt.*; +import net.minestom.server.utils.NBTUtils; import java.util.ArrayList; import java.util.List; @@ -15,30 +13,30 @@ import java.util.function.Function; 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 { - static final Map, Function>> SUPPORTED_TYPES = Map.ofEntries( - entry(NBTType.TAG_Byte, Tag::Byte), - entry(NBTType.TAG_Short, Tag::Short), - entry(NBTType.TAG_Int, Tag::Integer), - entry(NBTType.TAG_Long, Tag::Long), - entry(NBTType.TAG_Float, Tag::Float), - entry(NBTType.TAG_Double, Tag::Double), - entry(NBTType.TAG_String, Tag::String)); + static final Map, Function>> SUPPORTED_TYPES = Map.ofEntries( + entry(BinaryTagTypes.BYTE, Tag::Byte), + entry(BinaryTagTypes.SHORT, Tag::Short), + entry(BinaryTagTypes.INT, Tag::Integer), + entry(BinaryTagTypes.LONG, Tag::Long), + entry(BinaryTagTypes.FLOAT, Tag::Float), + entry(BinaryTagTypes.DOUBLE, Tag::Double), + entry(BinaryTagTypes.STRING, Tag::String)); - static void separate(NBTCompound nbtCompound, Consumer consumer) { + static void separate(CompoundBinaryTag nbtCompound, Consumer consumer) { for (var ent : nbtCompound) { convert(new ArrayList<>(), ent.getKey(), ent.getValue(), consumer); } } - static void separate(String key, NBT nbt, Consumer consumer) { + static void separate(String key, BinaryTag nbt, Consumer consumer) { convert(new ArrayList<>(), key, nbt, consumer); } - static Entry separateSingle(String key, NBT nbt) { - assert !(nbt instanceof NBTCompound); + static Entry separateSingle(String key, BinaryTag nbt) { + assert !(nbt instanceof CompoundBinaryTag); AtomicReference> entryRef = new AtomicReference<>(); convert(new ArrayList<>(), key, nbt, entry -> { assert entryRef.getPlain() == null : "Multiple entries found for nbt tag: " + key + " -> " + nbt; @@ -49,28 +47,28 @@ final class TagNbtSeparator { return entry; } - private static void convert(List path, String key, NBT nbt, Consumer consumer) { - var tagFunction = SUPPORTED_TYPES.get(nbt.getID()); + private static void convert(List path, String key, BinaryTag nbt, Consumer consumer) { + var tagFunction = SUPPORTED_TYPES.get(nbt.type()); if (tagFunction != null) { Tag tag = tagFunction.apply(key); - consumer.accept(makeEntry(path, tag, nbt.getValue())); - } else if (nbt instanceof NBTCompound nbtCompound) { + consumer.accept(makeEntry(path, tag, NBTUtils.nbtValueFromTag(nbt))); + } else if (nbt instanceof CompoundBinaryTag nbtCompound) { for (var ent : nbtCompound) { var newPath = new ArrayList<>(path); newPath.add(key); convert(newPath, ent.getKey(), ent.getValue(), consumer); } - } else if (nbt instanceof NBTList nbtList) { - tagFunction = SUPPORTED_TYPES.get(nbtList.getSubtagType()); + } else if (nbt instanceof ListBinaryTag nbtList) { + tagFunction = SUPPORTED_TYPES.get(nbtList.elementType()); if (tagFunction == null) { // Invalid list subtype, fallback to nbt consumer.accept(makeEntry(path, Tag.NBT(key), nbt)); } else { try { 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++) { - values[i] = nbtList.get(i).getValue(); + values[i] = NBTUtils.nbtValueFromTag(nbtList.get(i)); } consumer.accept(makeEntry(path, Tag.class.cast(tag), List.of(values))); } catch (Exception e) { diff --git a/src/main/java/net/minestom/server/tag/TagRecord.java b/src/main/java/net/minestom/server/tag/TagRecord.java index 3c15d198c..6cc3d33d7 100644 --- a/src/main/java/net/minestom/server/tag/TagRecord.java +++ b/src/main/java/net/minestom/server/tag/TagRecord.java @@ -1,11 +1,11 @@ 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.minestom.server.item.ItemStack; import org.jetbrains.annotations.NotNull; 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.InvocationTargetException; @@ -44,7 +44,7 @@ final class TagRecord { final Tag tag; if (componentType.isRecord()) { tag = Tag.Structure(componentName, serializers.get(componentType)); - } else if (NBT.class.isAssignableFrom(componentType)) { + } else if (BinaryTag.class.isAssignableFrom(componentType)) { tag = Tag.NBT(componentName); } else { final var fun = SUPPORTED_TYPES.get(componentType); @@ -73,7 +73,7 @@ final class TagRecord { static final class Serializer implements TagSerializer { final Constructor constructor; final Entry[] entries; - final Serializers.Entry serializerEntry; + final Serializers.Entry serializerEntry; Serializer(Constructor constructor, Entry[] entries) { this.constructor = constructor; diff --git a/src/main/java/net/minestom/server/tag/TagSerializer.java b/src/main/java/net/minestom/server/tag/TagSerializer.java index df3138d4e..314a49c2f 100644 --- a/src/main/java/net/minestom/server/tag/TagSerializer.java +++ b/src/main/java/net/minestom/server/tag/TagSerializer.java @@ -1,9 +1,9 @@ package net.minestom.server.tag; +import net.kyori.adventure.nbt.CompoundBinaryTag; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.function.Function; @@ -31,11 +31,11 @@ public interface TagSerializer { void write(@NotNull TagWritable writer, @NotNull T value); @ApiStatus.Experimental - TagSerializer COMPOUND = TagSerializerImpl.COMPOUND; + TagSerializer COMPOUND = TagSerializerImpl.COMPOUND; @ApiStatus.Experimental - static TagSerializer fromCompound(@NotNull Function reader, - @NotNull Function writer) { + static TagSerializer fromCompound(@NotNull Function reader, + @NotNull Function writer) { return TagSerializerImpl.fromCompound(reader, writer); } } diff --git a/src/main/java/net/minestom/server/tag/TagSerializerImpl.java b/src/main/java/net/minestom/server/tag/TagSerializerImpl.java index 57f8f84be..53bc4d451 100644 --- a/src/main/java/net/minestom/server/tag/TagSerializerImpl.java +++ b/src/main/java/net/minestom/server/tag/TagSerializerImpl.java @@ -1,35 +1,35 @@ package net.minestom.server.tag; +import net.kyori.adventure.nbt.CompoundBinaryTag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.function.Function; final class TagSerializerImpl { - public static final TagSerializer COMPOUND = new TagSerializer<>() { + public static final TagSerializer COMPOUND = new TagSerializer<>() { @Override - public @NotNull NBTCompound read(@NotNull TagReadable reader) { + public @NotNull CompoundBinaryTag read(@NotNull TagReadable reader) { return ((TagHandler) reader).asCompound(); } @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())); } }; - static TagSerializer fromCompound(Function readFunc, Function writeFunc) { + static TagSerializer fromCompound(Function readFunc, Function writeFunc) { return new TagSerializer<>() { @Override public @Nullable T read(@NotNull TagReadable reader) { - final NBTCompound compound = COMPOUND.read(reader); + final CompoundBinaryTag compound = COMPOUND.read(reader); return readFunc.apply(compound); } @Override 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); } }; diff --git a/src/main/java/net/minestom/server/utils/NBTUtils.java b/src/main/java/net/minestom/server/utils/NBTUtils.java new file mode 100644 index 000000000..fd07f7dc7 --- /dev/null +++ b/src/main/java/net/minestom/server/utils/NBTUtils.java @@ -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() { + } +} diff --git a/src/main/java/net/minestom/server/utils/binary/BinaryBuffer.java b/src/main/java/net/minestom/server/utils/binary/BinaryBuffer.java index c4f607628..ef3e98355 100644 --- a/src/main/java/net/minestom/server/utils/binary/BinaryBuffer.java +++ b/src/main/java/net/minestom/server/utils/binary/BinaryBuffer.java @@ -2,8 +2,6 @@ package net.minestom.server.utils.binary; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTReader; -import org.jglrxavpok.hephaistos.nbt.NBTWriter; import java.io.IOException; import java.nio.ByteBuffer; @@ -17,8 +15,6 @@ import java.nio.channels.WritableByteChannel; @ApiStatus.Internal public final class BinaryBuffer { private ByteBuffer nioBuffer; // To become a `MemorySegment` once released - private NBTReader nbtReader; - private NBTWriter nbtWriter; private final int capacity; private int readerOffset, writerOffset; diff --git a/src/main/java/net/minestom/server/utils/binary/BinaryReader.java b/src/main/java/net/minestom/server/utils/binary/BinaryReader.java index dbcaef4cb..5fbcb3b6d 100644 --- a/src/main/java/net/minestom/server/utils/binary/BinaryReader.java +++ b/src/main/java/net/minestom/server/utils/binary/BinaryReader.java @@ -1,5 +1,6 @@ package net.minestom.server.utils.binary; +import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; 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.validate.Check; import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBT; import java.io.InputStream; import java.nio.BufferUnderflowException; @@ -263,7 +263,7 @@ public class BinaryReader extends InputStream { return buffer.readableBytes(); } - public NBT readTag() { + public BinaryTag readTag() { return buffer.read(NBT); } diff --git a/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java b/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java index c6ab077ae..7a0eb0116 100644 --- a/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java +++ b/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java @@ -1,5 +1,6 @@ package net.minestom.server.utils.binary; +import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.text.Component; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; @@ -8,7 +9,6 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.Either; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBT; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -167,7 +167,7 @@ public class BinaryWriter extends OutputStream { 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); } diff --git a/src/main/java/net/minestom/server/utils/block/BlockUtils.java b/src/main/java/net/minestom/server/utils/block/BlockUtils.java index dd6684925..36034d1e3 100644 --- a/src/main/java/net/minestom/server/utils/block/BlockUtils.java +++ b/src/main/java/net/minestom/server/utils/block/BlockUtils.java @@ -1,16 +1,14 @@ package net.minestom.server.utils.block; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import net.kyori.adventure.nbt.CompoundBinaryTag; 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.BlockHandler; import net.minestom.server.tag.Tag; import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBT; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.Map; import java.util.Objects; @@ -90,22 +88,22 @@ public class BlockUtils { 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; // Append handler tags 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) { // Extract explicitly defined tags and keep the rest server-side - return NBT.Compound(nbt -> { - for (Tag tag : handler.getBlockEntityTags()) { - final var value = tag.read(blockNbt); - if (value != null) { - // Tag is present and valid - tag.writeUnsafe(nbt, value); - } + var builder = CompoundBinaryTag.builder(); + for (Tag tag : handler.getBlockEntityTags()) { + final var value = tag.read(blockNbt); + if (value != null) { + // Tag is present and valid + tag.writeUnsafe(builder, value); } - }); + } + return builder.build(); } // Complete nbt shall be sent if the block has no handler // Necessary to support all vanilla blocks diff --git a/src/main/java/net/minestom/server/world/DimensionType.java b/src/main/java/net/minestom/server/world/DimensionType.java index 46cf39507..c48aed029 100644 --- a/src/main/java/net/minestom/server/world/DimensionType.java +++ b/src/main/java/net/minestom/server/world/DimensionType.java @@ -1,13 +1,10 @@ package net.minestom.server.world; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.NotNull; 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.concurrent.atomic.AtomicInteger; @@ -18,6 +15,9 @@ public class DimensionType { 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")) .ultrawarm(false) .natural(true) @@ -91,55 +91,56 @@ public class DimensionType { return new DimensionTypeBuilder(); } - public static DimensionType fromNBT(NBTCompound nbt) { + public static DimensionType fromNBT(CompoundBinaryTag nbt) { return DimensionType.builder(NamespaceID.from(nbt.getString("name"))) .ambientLight(nbt.getFloat("ambient_light")) .infiniburn(NamespaceID.from(nbt.getString("infiniburn").replaceFirst("#", ""))) - .natural(nbt.getByte("natural") != 0) - .ceilingEnabled(nbt.getByte("has_ceiling") != 0) - .skylightEnabled(nbt.getByte("has_skylight") != 0) - .ultrawarm(nbt.getByte("ultrawarm") != 0) - .raidCapable(nbt.getByte("has_raids") != 0) - .respawnAnchorSafe(nbt.getByte("respawn_anchor_works") != 0) - .bedSafe(nbt.getByte("bed_works") != 0) + .natural(nbt.getBoolean("natural")) + .ceilingEnabled(nbt.getBoolean("has_ceiling")) + .skylightEnabled(nbt.getBoolean("has_skylight")) + .ultrawarm(nbt.getBoolean("ultrawarm")) + .raidCapable(nbt.getBoolean("has_raids")) + .respawnAnchorSafe(nbt.getBoolean("respawn_anchor_works")) + .bedSafe(nbt.getBoolean("bed_works")) .effects(nbt.getString("effects")) - .piglinSafe(nbt.getByte("piglin_safe") != 0) + .piglinSafe(nbt.getBoolean("piglin_safe")) .logicalHeight(nbt.getInt("logical_height")) .coordinateScale(nbt.getDouble("coordinate_scale")) .build(); } @NotNull - public NBTCompound toIndexedNBT() { - return NBT.Compound(Map.of( - "name", NBT.String(name.toString()), - "id", NBT.Int(id), - "element", toNBT())); + public CompoundBinaryTag toIndexedNBT() { + return CompoundBinaryTag.builder() + .putString("name", name.toString()) + .putInt("id", id) + .put("element", toNBT()) + .build(); } @NotNull - public NBTCompound toNBT() { - return NBT.Compound(nbt -> { - nbt.setFloat("ambient_light", ambientLight); - nbt.setString("infiniburn", "#" + infiniburn.toString()); - nbt.setByte("natural", (byte) (natural ? 0x01 : 0x00)); - nbt.setByte("has_ceiling", (byte) (ceilingEnabled ? 0x01 : 0x00)); - nbt.setByte("has_skylight", (byte) (skylightEnabled ? 0x01 : 0x00)); - nbt.setByte("ultrawarm", (byte) (ultrawarm ? 0x01 : 0x00)); - nbt.setByte("has_raids", (byte) (raidCapable ? 0x01 : 0x00)); - nbt.setByte("respawn_anchor_works", (byte) (respawnAnchorSafe ? 0x01 : 0x00)); - nbt.setByte("bed_works", (byte) (bedSafe ? 0x01 : 0x00)); - nbt.setString("effects", effects); - nbt.setByte("piglin_safe", (byte) (piglinSafe ? 0x01 : 0x00)); - nbt.setInt("min_y", minY); - nbt.setInt("height", height); - nbt.setInt("logical_height", logicalHeight); - nbt.setDouble("coordinate_scale", coordinateScale); - nbt.setString("name", name.toString()); - nbt.setInt("monster_spawn_block_light_limit", 0); - nbt.setInt("monster_spawn_light_level", 11); - if (fixedTime != null) nbt.setLong("fixed_time", fixedTime); - }); + public CompoundBinaryTag toNBT() { + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + builder.putFloat("ambient_light", ambientLight); + builder.putString("infiniburn", "#" + infiniburn.toString()); + builder.putByte("natural", (byte) (natural ? 0x01 : 0x00)); + builder.putByte("has_ceiling", (byte) (ceilingEnabled ? 0x01 : 0x00)); + builder.putByte("has_skylight", (byte) (skylightEnabled ? 0x01 : 0x00)); + builder.putByte("ultrawarm", (byte) (ultrawarm ? 0x01 : 0x00)); + builder.putByte("has_raids", (byte) (raidCapable ? 0x01 : 0x00)); + builder.putByte("respawn_anchor_works", (byte) (respawnAnchorSafe ? 0x01 : 0x00)); + builder.putByte("bed_works", (byte) (bedSafe ? 0x01 : 0x00)); + builder.putString("effects", effects); + builder.putByte("piglin_safe", (byte) (piglinSafe ? 0x01 : 0x00)); + builder.putInt("min_y", minY); + builder.putInt("height", height); + builder.putInt("logical_height", logicalHeight); + builder.putDouble("coordinate_scale", coordinateScale); + builder.putString("name", name.toString()); + builder.putInt("monster_spawn_block_light_limit", 0); + builder.putInt("monster_spawn_light_level", 11); + if (fixedTime != null) builder.putLong("fixed_time", fixedTime); + return builder.build(); } @Override @@ -261,9 +262,9 @@ public class DimensionType { private boolean bedSafe = true; private String effects = "minecraft:overworld"; private boolean piglinSafe = false; - private int minY = SizesKt.getVanillaMinY(); - private int logicalHeight = SizesKt.getVanillaMaxY() - SizesKt.getVanillaMinY() + 1; - private int height = SizesKt.getVanillaMaxY() - SizesKt.getVanillaMinY() + 1; + private int minY = VANILLA_MIN_Y; + private int logicalHeight = VANILLA_MAX_Y - VANILLA_MIN_Y + 1; + private int height = VANILLA_MAX_Y - VANILLA_MIN_Y + 1; private double coordinateScale = 1.0; private NamespaceID infiniburn = NamespaceID.from("minecraft:infiniburn_overworld"); diff --git a/src/main/java/net/minestom/server/world/DimensionTypeManager.java b/src/main/java/net/minestom/server/world/DimensionTypeManager.java index 0c38fac88..4627851f3 100644 --- a/src/main/java/net/minestom/server/world/DimensionTypeManager.java +++ b/src/main/java/net/minestom/server/world/DimensionTypeManager.java @@ -1,11 +1,11 @@ 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 org.jetbrains.annotations.NotNull; 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.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. *

* Used when a player connects. * * @return an nbt compound containing the registered dimensions */ - public @NotNull NBTCompound toNBT() { - return NBT.Compound(dimensions -> { - dimensions.setString("type", "minecraft:dimension_type"); - dimensions.set("value", NBT.List( - NBTType.TAG_Compound, - dimensionTypes.stream() - .map(DimensionType::toIndexedNBT) - .toList() - )); - }); + public @NotNull CompoundBinaryTag toNBT() { + ListBinaryTag.Builder entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND); + for (DimensionType dimensionType : dimensionTypes) + entries.add(dimensionType.toIndexedNBT()); + return CompoundBinaryTag.builder() + .putString("type", "minecraft:dimension_type") + .put("value", entries.build()) + .build(); } } diff --git a/src/main/java/net/minestom/server/world/biomes/Biome.java b/src/main/java/net/minestom/server/world/biomes/Biome.java index bc9719a4c..0372d6e03 100644 --- a/src/main/java/net/minestom/server/world/biomes/Biome.java +++ b/src/main/java/net/minestom/server/world/biomes/Biome.java @@ -1,5 +1,6 @@ package net.minestom.server.world.biomes; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.coordinate.Point; import net.minestom.server.registry.ProtocolObject; 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.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBT; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; 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(effects(), "The biome effects cannot be null"); - return NBT.Compound(element -> { - element.setFloat("temperature", temperature()); - element.setFloat("downfall", downfall()); - element.setByte("has_precipitation", (byte) (precipitation() == Precipitation.NONE ? 0 : 1)); - if (temperatureModifier() != TemperatureModifier.NONE) - element.setString("temperature_modifier", temperatureModifier().name().toLowerCase(Locale.ROOT)); - element.set("effects", effects().toNbt()); - }); + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder() + .putFloat("temperature", temperature()) + .putFloat("downfall", downfall()) + .putByte("has_precipitation", (byte) (precipitation() == Precipitation.NONE ? 0 : 1)) + .putString("precipitation", precipitation().name().toLowerCase(Locale.ROOT)); + if (temperatureModifier() != TemperatureModifier.NONE) + builder.putString("temperature_modifier", temperatureModifier().name().toLowerCase(Locale.ROOT)); + return builder + .put("effects", effects().toNbt()) + .build(); } static @NotNull Builder builder() { diff --git a/src/main/java/net/minestom/server/world/biomes/BiomeEffects.java b/src/main/java/net/minestom/server/world/biomes/BiomeEffects.java index 56fb36eae..cac043914 100644 --- a/src/main/java/net/minestom/server/world/biomes/BiomeEffects.java +++ b/src/main/java/net/minestom/server/world/biomes/BiomeEffects.java @@ -1,12 +1,10 @@ package net.minestom.server.world.biomes; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBT; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.Locale; -import java.util.Map; public record BiomeEffects(int fogColor, int skyColor, int waterColor, int waterFogColor, int foliageColor, int grassColor, @@ -18,29 +16,29 @@ public record BiomeEffects(int fogColor, int skyColor, int waterColor, int water return new Builder(); } - public NBTCompound toNbt() { - return NBT.Compound(nbt -> { - nbt.setInt("fog_color", fogColor); - if (foliageColor != -1) - nbt.setInt("foliage_color", foliageColor); - if (grassColor != -1) - nbt.setInt("grass_color", grassColor); - nbt.setInt("sky_color", skyColor); - nbt.setInt("water_color", waterColor); - nbt.setInt("water_fog_color", waterFogColor); - if (grassColorModifier != null) - nbt.setString("grass_color_modifier", grassColorModifier.name().toLowerCase(Locale.ROOT)); - if (biomeParticle != null) - nbt.set("particle", biomeParticle.toNbt()); - if (ambientSound != null) - nbt.setString("ambient_sound", ambientSound.toString()); - if (moodSound != null) - nbt.set("mood_sound", moodSound.toNbt()); - if (additionsSound != null) - nbt.set("additions_sound", additionsSound.toNbt()); - if (music != null) - nbt.set("music", music.toNbt()); - }); + public CompoundBinaryTag toNbt() { + var builder = CompoundBinaryTag.builder(); + builder.putInt("fog_color", fogColor); + if (foliageColor != -1) + builder.putInt("foliage_color", foliageColor); + if (grassColor != -1) + builder.putInt("grass_color", grassColor); + builder.putInt("sky_color", skyColor); + builder.putInt("water_color", waterColor); + builder.putInt("water_fog_color", waterFogColor); + if (grassColorModifier != null) + builder.putString("grass_color_modifier", grassColorModifier.name().toLowerCase(Locale.ROOT)); + if (biomeParticle != null) + builder.put("particle", biomeParticle.toNbt()); + if (ambientSound != null) + builder.putString("ambient_sound", ambientSound.toString()); + if (moodSound != null) + builder.put("mood_sound", moodSound.toNbt()); + if (additionsSound != null) + builder.put("additions_sound", additionsSound.toNbt()); + if (music != null) + builder.put("music", music.toNbt()); + return builder.build(); } 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 @NotNull NBTCompound toNbt() { - return NBT.Compound(Map.of( - "sound", NBT.String(sound.toString()), - "tick_delay", NBT.Int(tickDelay), - "block_search_extent", NBT.Int(blockSearchExtent), - "offset", NBT.Double(offset))); + public @NotNull CompoundBinaryTag toNbt() { + return CompoundBinaryTag.builder() + .putString("sound", sound.toString()) + .putInt("tick_delay", tickDelay) + .putInt("block_search_extent", blockSearchExtent) + .putDouble("offset", offset) + .build(); } } public record AdditionsSound(NamespaceID sound, double tickChance) { - public @NotNull NBTCompound toNbt() { - return NBT.Compound(Map.of( - "sound", NBT.String(sound.toString()), - "tick_chance", NBT.Double(tickChance))); + public @NotNull CompoundBinaryTag toNbt() { + return CompoundBinaryTag.builder() + .putString("sound", sound.toString()) + .putDouble("tick_chance", tickChance) + .build(); } } public record Music(NamespaceID sound, int minDelay, int maxDelay, boolean replaceCurrentMusic) { - public @NotNull NBTCompound toNbt() { - return NBT.Compound(Map.of( - "sound", NBT.String(sound.toString()), - "min_delay", NBT.Int(minDelay), - "max_delay", NBT.Int(maxDelay), - "replace_current_music", NBT.Boolean(replaceCurrentMusic))); + public @NotNull CompoundBinaryTag toNbt() { + return CompoundBinaryTag.builder() + .putString("sound", sound.toString()) + .putInt("min_delay", minDelay) + .putInt("max_delay", maxDelay) + .putBoolean("replace_current_music", replaceCurrentMusic) + .build(); } } diff --git a/src/main/java/net/minestom/server/world/biomes/BiomeManager.java b/src/main/java/net/minestom/server/world/biomes/BiomeManager.java index 18dfdbe28..9569ca9f6 100644 --- a/src/main/java/net/minestom/server/world/biomes/BiomeManager.java +++ b/src/main/java/net/minestom/server/world/biomes/BiomeManager.java @@ -1,12 +1,12 @@ 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.validate.Check; import org.jetbrains.annotations.NotNull; 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.Collections; @@ -25,7 +25,7 @@ public final class BiomeManager { private final Map idMappings = new ConcurrentHashMap<>(); private final AtomicInteger ID_COUNTER = new AtomicInteger(0); - private NBTCompound nbtCache = null; + private CompoundBinaryTag nbtCache = null; public BiomeManager() { // Need to register plains for the client to work properly @@ -101,18 +101,21 @@ public final class BiomeManager { return getByName(namespace); } - public @NotNull NBTCompound toNBT() { + public @NotNull CompoundBinaryTag toNBT() { 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 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; } diff --git a/src/main/java/net/minestom/server/world/biomes/BiomeParticle.java b/src/main/java/net/minestom/server/world/biomes/BiomeParticle.java index f2f3edeb3..42fdd44dc 100644 --- a/src/main/java/net/minestom/server/world/biomes/BiomeParticle.java +++ b/src/main/java/net/minestom/server/world/biomes/BiomeParticle.java @@ -1,22 +1,22 @@ package net.minestom.server.world.biomes; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.instance.block.Block; import net.minestom.server.item.ItemStack; import net.minestom.server.utils.NamespaceID; -import org.jglrxavpok.hephaistos.nbt.NBT; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.Map; public record BiomeParticle(float probability, Option option) { - public NBTCompound toNbt() { - return NBT.Compound(Map.of( - "probability", NBT.Float(probability), - "options", option.toNbt())); + public CompoundBinaryTag toNbt() { + return CompoundBinaryTag.builder() + .putFloat("probability", probability) + .put("options", option.toNbt()) + .build(); } public interface Option { - NBTCompound toNbt(); + CompoundBinaryTag toNbt(); } public record BlockOption(Block block) implements Option { @@ -24,15 +24,17 @@ public record BiomeParticle(float probability, Option option) { private static final String type = "block"; @Override - public NBTCompound toNbt() { - return NBT.Compound(nbtCompound -> { - nbtCompound.setString("type", type); - nbtCompound.setString("Name", block.name()); - Map propertiesMap = block.properties(); - if (propertiesMap.size() != 0) { - nbtCompound.set("Properties", NBT.Compound(p -> propertiesMap.forEach(p::setString))); - } - }); + public CompoundBinaryTag toNbt() { + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + builder.putString("type", type); + builder.putString("Name", block.name()); + Map propertiesMap = block.properties(); + if (!propertiesMap.isEmpty()) { + 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"; @Override - public NBTCompound toNbt() { - return NBT.Compound(Map.of( - "type", NBT.String(type), - "r", NBT.Float(red), - "g", NBT.Float(green), - "b", NBT.Float(blue), - "scale", NBT.Float(scale))); + public CompoundBinaryTag toNbt() { + return CompoundBinaryTag.builder() + .putString("type", type) + .putFloat("r", red) + .putFloat("g", green) + .putFloat("b", blue) + .putFloat("scale", scale) + .build(); } } @@ -54,17 +57,19 @@ public record BiomeParticle(float probability, Option option) { private static final String type = "item"; @Override - public NBTCompound toNbt() { + public CompoundBinaryTag toNbt() { //todo test count might be wrong type - NBTCompound nbtCompound = item.meta().toNBT(); - return nbtCompound.modify(n -> n.setString("type", type)); + return item.meta().toNBT() + .putString("type", type); } } public record NormalOption(NamespaceID type) implements Option { @Override - public NBTCompound toNbt() { - return NBT.Compound(Map.of("type", NBT.String(type.toString()))); + public CompoundBinaryTag toNbt() { + return CompoundBinaryTag.builder() + .putString("type", type.toString()) + .build(); } } }