mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-04 07:28:19 +01:00
Allow path on view tags
Signed-off-by: TheMode <themode@outlook.fr>
This commit is contained in:
parent
68fc705cd3
commit
d8a1003368
@ -13,6 +13,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTType;
|
||||
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
|
||||
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
final class TagHandlerImpl implements TagHandler {
|
||||
@ -41,45 +42,48 @@ final class TagHandlerImpl implements TagHandler {
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
if (tag.isView()) return tag.read(asCompound());
|
||||
return read(entries, tag);
|
||||
return read(entries, tag, this::asCompound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||
if (tag.isView()) {
|
||||
MutableNBTCompound viewCompound = new MutableNBTCompound();
|
||||
tag.write(viewCompound, value);
|
||||
updateContent(viewCompound);
|
||||
} else {
|
||||
final int tagIndex = tag.index;
|
||||
final Tag.PathEntry[] paths = tag.path;
|
||||
final boolean present = value != null;
|
||||
TagHandlerImpl local = this;
|
||||
synchronized (this) {
|
||||
if (paths != null) {
|
||||
if ((local = traversePathWrite(this, paths, present)) == null)
|
||||
return; // Tried to remove an absent tag. Do nothing
|
||||
}
|
||||
SPMCMap entries = local.entries;
|
||||
if (present) {
|
||||
TagHandlerImpl local = this;
|
||||
final Tag.PathEntry[] paths = tag.path;
|
||||
final boolean present = value != null;
|
||||
final int tagIndex = tag.index;
|
||||
final boolean isView = tag.isView();
|
||||
synchronized (this) {
|
||||
if (paths != null) {
|
||||
if ((local = traversePathWrite(this, paths, present)) == null)
|
||||
return; // Tried to remove an absent tag. Do nothing
|
||||
}
|
||||
SPMCMap entries = local.entries;
|
||||
if (present) {
|
||||
if (!isView) {
|
||||
entries.put(tagIndex, valueToEntry(local, tag, value));
|
||||
} else {
|
||||
// Remove recursively
|
||||
if (entries.remove(tagIndex) == null) return;
|
||||
if (paths != null) {
|
||||
TagHandlerImpl tmp = local;
|
||||
int i = paths.length;
|
||||
do {
|
||||
if (!tmp.entries.isEmpty()) break;
|
||||
tmp = tmp.parent;
|
||||
tmp.entries.remove(paths[--i].index());
|
||||
} while (i > 0);
|
||||
}
|
||||
local.updateContent((NBTCompound) tag.entry.write(value));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Remove recursively
|
||||
if (!isView) {
|
||||
if (entries.remove(tagIndex) == null) return;
|
||||
} else {
|
||||
entries.clear();
|
||||
}
|
||||
if (paths != null) {
|
||||
TagHandlerImpl tmp = local;
|
||||
int i = paths.length;
|
||||
do {
|
||||
if (!tmp.entries.isEmpty()) break;
|
||||
tmp = tmp.parent;
|
||||
tmp.entries.remove(paths[--i].index());
|
||||
} while (i > 0);
|
||||
}
|
||||
entries.invalidate();
|
||||
assert !local.entries.rehashed;
|
||||
}
|
||||
entries.invalidate();
|
||||
assert !local.entries.rehashed;
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,13 +169,21 @@ final class TagHandlerImpl implements TagHandler {
|
||||
return cache;
|
||||
}
|
||||
|
||||
private static <T> T read(Int2ObjectOpenHashMap<Entry<?>> entries, Tag<T> tag) {
|
||||
private static <T> T read(Int2ObjectOpenHashMap<Entry<?>> entries, Tag<T> tag,
|
||||
Supplier<NBTCompound> rootCompoundSupplier) {
|
||||
final Tag.PathEntry[] paths = tag.path;
|
||||
TagHandlerImpl pathHandler = null;
|
||||
if (paths != null) {
|
||||
// Must be a path-able entry
|
||||
if ((entries = traversePathRead(paths, entries)) == null)
|
||||
return tag.createDefault();
|
||||
if ((pathHandler = traversePathRead(paths, entries)) == null)
|
||||
return tag.createDefault(); // Must be a path-able entry, but not present
|
||||
entries = pathHandler.entries;
|
||||
}
|
||||
|
||||
if (tag.isView()) {
|
||||
return tag.read(pathHandler != null ?
|
||||
pathHandler.asCompound() : rootCompoundSupplier.get());
|
||||
}
|
||||
|
||||
final Entry<?> entry;
|
||||
if ((entry = entries.get(tag.index)) == null) {
|
||||
return tag.createDefault();
|
||||
@ -189,25 +201,29 @@ final class TagHandlerImpl implements TagHandler {
|
||||
return type == null || type == nbt.getID() ? serializerEntry.read(nbt) : tag.createDefault();
|
||||
}
|
||||
|
||||
private static Int2ObjectOpenHashMap<Entry<?>> traversePathRead(Tag.PathEntry[] paths,
|
||||
Int2ObjectOpenHashMap<Entry<?>> entries) {
|
||||
private static TagHandlerImpl traversePathRead(Tag.PathEntry[] paths,
|
||||
Int2ObjectOpenHashMap<Entry<?>> entries) {
|
||||
assert paths != null && paths.length > 0;
|
||||
TagHandlerImpl result = null;
|
||||
for (var path : paths) {
|
||||
final Entry<?> entry;
|
||||
if ((entry = entries.get(path.index())) == null)
|
||||
return null;
|
||||
if (entry instanceof PathEntry pathEntry) {
|
||||
entries = pathEntry.value.entries;
|
||||
result = pathEntry.value;
|
||||
} else if (entry.updatedNbt() instanceof NBTCompound compound) {
|
||||
// Slow path forcing a conversion of the structure to NBTCompound
|
||||
// TODO should the handler be cached inside the entry?
|
||||
TagHandlerImpl tmp = fromCompound(compound);
|
||||
entries = tmp.entries;
|
||||
result = fromCompound(compound);
|
||||
} else {
|
||||
// Entry is not path-able
|
||||
return null;
|
||||
}
|
||||
assert result != null;
|
||||
entries = result.entries;
|
||||
}
|
||||
return entries;
|
||||
assert result != null;
|
||||
return result;
|
||||
}
|
||||
|
||||
private record Cache(Int2ObjectOpenHashMap<Entry<?>> entries, NBTCompound compound) implements TagReadable {
|
||||
@ -215,8 +231,7 @@ final class TagHandlerImpl implements TagHandler {
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
if (tag.isView()) return tag.read(compound);
|
||||
return read(entries, tag);
|
||||
return read(entries, tag, () -> compound);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,6 +81,71 @@ public class TagViewTest {
|
||||
""", handler.asCompound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void empty() {
|
||||
var handler = TagHandler.newHandler();
|
||||
var tag = Tag.View(new TagSerializer<Entry>() {
|
||||
@Override
|
||||
public @Nullable Entry read(@NotNull TagReadable reader) {
|
||||
// Empty
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull TagWritable writer, @NotNull Entry value) {
|
||||
// Empty
|
||||
}
|
||||
});
|
||||
assertNull(handler.getTag(tag));
|
||||
assertFalse(handler.hasTag(tag));
|
||||
|
||||
var entry = new Entry("hello");
|
||||
handler.setTag(tag, entry);
|
||||
assertNull(handler.getTag(tag));
|
||||
assertFalse(handler.hasTag(tag));
|
||||
assertEqualsSNBT("{}", handler.asCompound());
|
||||
|
||||
handler.removeTag(tag);
|
||||
assertFalse(handler.hasTag(tag));
|
||||
assertNull(handler.getTag(VIEW_TAG));
|
||||
assertEqualsSNBT("{}", handler.asCompound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void path() {
|
||||
var handler = TagHandler.newHandler();
|
||||
var tag = VIEW_TAG.path("path");
|
||||
assertNull(handler.getTag(tag));
|
||||
assertFalse(handler.hasTag(tag));
|
||||
|
||||
var entry = new Entry("hello");
|
||||
handler.setTag(tag, entry);
|
||||
assertTrue(handler.hasTag(tag));
|
||||
assertEquals(entry, handler.getTag(tag));
|
||||
|
||||
handler.removeTag(tag);
|
||||
assertFalse(handler.hasTag(tag));
|
||||
assertNull(handler.getTag(tag));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pathSnbt() {
|
||||
var handler = TagHandler.newHandler();
|
||||
var tag = VIEW_TAG.path("path");
|
||||
var entry = new Entry("hello");
|
||||
handler.setTag(tag, entry);
|
||||
assertEqualsSNBT("""
|
||||
{
|
||||
"path":{
|
||||
"value":"hello"
|
||||
}
|
||||
}
|
||||
""", handler.asCompound());
|
||||
|
||||
handler.removeTag(tag);
|
||||
assertEqualsSNBT("{}", handler.asCompound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compoundSerializer() {
|
||||
var tag = Tag.View(TagSerializer.COMPOUND);
|
||||
|
Loading…
Reference in New Issue
Block a user