diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index 76c999fa7..340e15b49 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -35,29 +35,34 @@ public class Tag { final Function writeFunction; private final Supplier defaultValue; + final Function originalRead; + // Optional properties final List path; final UnaryOperator copy; + final int listScope; Tag(int index, String key, - Function readFunction, - Function writeFunction, - @Nullable Supplier defaultValue, @Nullable List path, - @Nullable UnaryOperator copy) { + Function originalRead, + Function readFunction, Function writeFunction, + Supplier defaultValue, List path, UnaryOperator copy, int listScope) { assert index == INDEX_MAP.get(key); this.index = index; this.key = key; + this.originalRead = originalRead; this.readFunction = readFunction; this.writeFunction = writeFunction; this.defaultValue = defaultValue; this.path = path; this.copy = copy; + this.listScope = listScope; } static Tag tag(@NotNull String key, @NotNull Function readFunction, @NotNull Function writeFunction) { - return new Tag<>(INDEX_MAP.get(key), key, (Function) readFunction, (Function) writeFunction, - null, null, null); + return new Tag<>(INDEX_MAP.get(key), key, readFunction, + (Function) readFunction, (Function) writeFunction, + null, null, null, 0); } /** @@ -71,7 +76,7 @@ public class Tag { @Contract(value = "_ -> new", pure = true) public Tag defaultValue(@NotNull Supplier defaultValue) { - return new Tag<>(index, key, readFunction, writeFunction, defaultValue, path, copy); + return new Tag<>(index, key, originalRead, readFunction, writeFunction, defaultValue, path, copy, listScope); } @Contract(value = "_ -> new", pure = true) @@ -83,6 +88,7 @@ public class Tag { public Tag map(@NotNull Function readMap, @NotNull Function writeMap) { return new Tag<>(index, key, + readMap, // Read readFunction.andThen(t -> { if (t == null) return null; @@ -92,13 +98,13 @@ public class Tag { writeMap.andThen(writeFunction), // Default value () -> readMap.apply(createDefault()), - path, null); + path, null, listScope); } @ApiStatus.Experimental @Contract(value = "-> new", pure = true) public Tag> list() { - return new Tag<>(index, key, + return new Tag<>(index, key, originalRead, read -> { var list = (NBTList) read; final int size = list.getSize(); @@ -138,14 +144,15 @@ public class Tag { array[i] = copy; } return shallowCopy ? List.copyOf(ts) : List.of(array); - } : List::copyOf); + } : List::copyOf, listScope + 1); } @ApiStatus.Experimental @Contract(value = "_ -> new", pure = true) public Tag path(@NotNull String @Nullable ... path) { final List entries = path != null ? Arrays.stream(path).map(s -> new PathEntry(s, INDEX_MAP.get(s))).toList() : null; - return new Tag<>(index, key, readFunction, writeFunction, defaultValue, entries, copy); + return new Tag<>(index, key, originalRead, + readFunction, writeFunction, defaultValue, entries, copy, listScope); } public @Nullable T read(@NotNull NBTCompoundLike nbt) { @@ -186,7 +193,7 @@ public class Tag { final boolean shareValue(@NotNull Tag other) { // Verify if these 2 tags can share the same cached value // Key/Default value/Path are ignored - return this == other || this.readFunction == other.readFunction; + return this == other || (this.originalRead == other.originalRead && this.listScope == other.listScope); } public static @NotNull Tag Byte(@NotNull String key) { diff --git a/src/test/java/net/minestom/server/tag/TagEqualityTest.java b/src/test/java/net/minestom/server/tag/TagEqualityTest.java index e8807e63d..e755414c1 100644 --- a/src/test/java/net/minestom/server/tag/TagEqualityTest.java +++ b/src/test/java/net/minestom/server/tag/TagEqualityTest.java @@ -2,6 +2,8 @@ package net.minestom.server.tag; import org.junit.jupiter.api.Test; +import java.util.function.Function; + import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -10,6 +12,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue; */ public class TagEqualityTest { + record Entry(int value) { + } + @Test public void same() { var tag = Tag.String("test"); @@ -37,17 +42,58 @@ public class TagEqualityTest { assertFalse(tag.shareValue(tag2)); } + @Test + public void mapSame() { + // Force identical functions + Function t1 = Entry::new; + Function t2 = Entry::value; + + var tag = Tag.Integer("key"); + var map1 = tag.map(t1, t2); + var map2 = tag.map(t1, t2); + assertTrue(map1.shareValue(map2)); + } + + @Test + public void mapChild() { + var intTag = Tag.Integer("key"); + var tag = intTag.map(Entry::new, Entry::value); + assertFalse(intTag.shareValue(tag)); + } + @Test public void list() { var tag = Tag.String("test").list(); assertTrue(tag.shareValue(tag)); } - //@Test + @Test + public void listScope() { + var tag = Tag.String("test"); + assertFalse(tag.shareValue(tag.list())); + } + + @Test public void similarList() { - // TODO make work var tag = Tag.String("test").list(); var tag2 = Tag.String("test").list(); assertTrue(tag.shareValue(tag2)); + assertTrue(tag.list().shareValue(tag2.list())); + } + + @Test + public void differentList() { + var tag = Tag.String("test").list(); + var tag2 = Tag.String("test").list(); + assertFalse(tag.shareValue(tag2.list())); + assertFalse(tag.list().shareValue(tag2.list().list())); + } + + @Test + public void differentListType() { + var tag = Tag.String("test").list(); + var tag2 = Tag.Integer("test").list(); + assertFalse(tag.shareValue(tag2)); + assertFalse(tag.list().shareValue(tag2.list())); } }