From 23e1c8a0bcd6356e89833d75ee8b976c0fb2465a Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 9 Apr 2022 16:17:24 +0200 Subject: [PATCH] Prepare better nbt conversion Signed-off-by: TheMode --- .../java/net/minestom/server/tag/Tag.java | 22 +++-- .../net/minestom/server/tag/TagHandler.java | 4 +- .../minestom/server/tag/TagHandlerImpl.java | 89 ++++++++++--------- .../net/minestom/server/tag/TagNbtTest.java | 5 +- 4 files changed, 66 insertions(+), 54 deletions(-) diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index de0a1474a..e8e0a52ed 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -247,16 +247,23 @@ public class Tag { return tag(key, Serializers.STRING); } - public static @NotNull Tag NBT(@NotNull String key) { - return tag(key, (Serializers.Entry) Serializers.NBT_ENTRY); - } - public static @NotNull Tag ItemStack(@NotNull String key) { return tag(key, Serializers.ITEM); } /** - * Create a wrapper around a compound. + * Creates a flexible tag able to read and write any {@link NBT} 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) { + return tag(key, Serializers.NBT_ENTRY); + } + + /** + * Creates a tag containing multiple fields. + *

+ * Those fields cannot be modified from an outside tag. (This is to prevent the backed object from becoming out of sync) * * @param key the tag key * @param serializer the tag serializer @@ -267,6 +274,11 @@ public class Tag { return fromSerializer(key, serializer); } + /** + * Specialized Structure tag affecting the src of the handler (i.e. overwrite all its data). + *

+ * Must be used with care. + */ public static @NotNull Tag View(@NotNull TagSerializer serializer) { return Structure("", serializer); } diff --git a/src/main/java/net/minestom/server/tag/TagHandler.java b/src/main/java/net/minestom/server/tag/TagHandler.java index d7c420d93..a1b7f491d 100644 --- a/src/main/java/net/minestom/server/tag/TagHandler.java +++ b/src/main/java/net/minestom/server/tag/TagHandler.java @@ -28,8 +28,6 @@ public interface TagHandler extends TagReadable, TagWritable { * @return a new tag handler with the content of the given compound */ static @NotNull TagHandler fromCompound(@NotNull NBTCompoundLike compound) { - TagHandler handler = newHandler(); - handler.updateContent(compound); - return handler; + 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 5e929fdf5..2196e30f4 100644 --- a/src/main/java/net/minestom/server/tag/TagHandlerImpl.java +++ b/src/main/java/net/minestom/server/tag/TagHandlerImpl.java @@ -23,19 +23,40 @@ final class TagHandlerImpl implements TagHandler { } @Override - public synchronized void setTag(@NotNull Tag tag, @Nullable T value) { - // Convert value to fit the tag (e.g. list copies) - if (value != null) { - final UnaryOperator copy = tag.copy; - if (copy != null) value = copy.apply(value); - } - // View tag access + public void setTag(@NotNull Tag tag, @Nullable T value) { if (tag.isView()) { - MutableNBTCompound tmp = new MutableNBTCompound(); - tag.writeUnsafe(tmp, value); - updateContent(tmp); - return; + MutableNBTCompound viewCompound = new MutableNBTCompound(); + tag.writeUnsafe(viewCompound, value); + updateContent(viewCompound); + } else { + if (value != null) { + final UnaryOperator copy = tag.copy; + if (copy != null) value = copy.apply(value); + } + write(tag, value); } + } + + @Override + public @NotNull TagReadable readableCopy() { + return updatedCache(); + } + + @Override + public void updateContent(@NotNull NBTCompoundLike compound) { + final TagHandlerImpl converted = fromCompound(compound); + synchronized (this) { + this.cache = converted.cache; + this.entries = converted.entries; + } + } + + @Override + public @NotNull NBTCompound asCompound() { + return updatedCache().compound; + } + + public synchronized void write(@NotNull Tag tag, @Nullable T value) { // Normal write int tagIndex = tag.index; TagHandlerImpl local = this; @@ -63,7 +84,9 @@ final class TagHandlerImpl implements TagHandler { } else if (entry.value instanceof TagHandlerImpl handler) { // Existing path, continue navigating local = handler; - } else throw new IllegalStateException("Cannot set a path-able tag on a non-path-able entry"); + } else { + throw new IllegalStateException("Cannot set a path-able tag on a non-path-able entry: " + entry.value.getClass()); + } entries = local.entries; pathHandlers[i] = local; } @@ -101,35 +124,6 @@ final class TagHandlerImpl implements TagHandler { } } - @Override - public @NotNull TagReadable readableCopy() { - return updatedCache(); - } - - @Override - public void updateContent(@NotNull NBTCompoundLike compound) { - Entry[] entries = new Entry[0]; - for (var entry : compound) { - final String key = entry.getKey(); - final NBT nbt = entry.getValue(); - final Tag tag = Tag.NBT(key); - final int index = tag.index; - if (index >= entries.length) { - entries = Arrays.copyOf(entries, index + 1); - } - entries[index] = new Entry<>(tag, nbt); - } - synchronized (this) { - this.cache = null; - this.entries = entries; - } - } - - @Override - public @NotNull NBTCompound asCompound() { - return updatedCache().compound; - } - private synchronized Cache updatedCache() { Cache cache = this.cache; if (cache == null) { @@ -198,8 +192,7 @@ final class TagHandlerImpl implements TagHandler { if (entry.value instanceof TagHandlerImpl handler) { entries = handler.entries; } else if (entry.updatedNbt() instanceof NBTCompound compound) { - var tmp = new TagHandlerImpl(); - tmp.updateContent(compound); + TagHandlerImpl tmp = fromCompound(compound); entries = tmp.entries; } } @@ -224,4 +217,14 @@ final class TagHandlerImpl implements TagHandler { return tag.createDefault(); } } + + static TagHandlerImpl fromCompound(NBTCompoundLike compound) { + TagHandlerImpl handler = new TagHandlerImpl(); + for (var entry : compound) { + final Tag tag = Tag.NBT(entry.getKey()); + final NBT nbt = entry.getValue(); + handler.setTag(tag, nbt); + } + return handler; + } } diff --git a/src/test/java/net/minestom/server/tag/TagNbtTest.java b/src/test/java/net/minestom/server/tag/TagNbtTest.java index 3f9f592c5..872c302ba 100644 --- a/src/test/java/net/minestom/server/tag/TagNbtTest.java +++ b/src/test/java/net/minestom/server/tag/TagNbtTest.java @@ -1,7 +1,6 @@ package net.minestom.server.tag; import org.jglrxavpok.hephaistos.nbt.NBT; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import org.junit.jupiter.api.Test; import java.util.Map; @@ -16,7 +15,7 @@ public class TagNbtTest { @Test public void compoundRead() { var handler = TagHandler.newHandler(); - Tag nbtTag = Tag.NBT("path1"); + var nbtTag = Tag.NBT("path1"); var nbt = NBT.Compound(Map.of("key", NBT.Int(5))); handler.setTag(nbtTag, nbt); @@ -29,7 +28,7 @@ public class TagNbtTest { @Test public void doubleCompoundRead() { var handler = TagHandler.newHandler(); - Tag nbtTag = Tag.NBT("path1"); + var nbtTag = Tag.NBT("path1"); var nbt = NBT.Compound(Map.of("path2", NBT.Compound(Map.of("key", NBT.Int(5))))); handler.setTag(nbtTag, nbt);