mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-06 08:27:43 +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 org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
|
||||||
|
|
||||||
import java.lang.invoke.VarHandle;
|
import java.lang.invoke.VarHandle;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.function.UnaryOperator;
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
final class TagHandlerImpl implements TagHandler {
|
final class TagHandlerImpl implements TagHandler {
|
||||||
@ -41,45 +42,48 @@ final class TagHandlerImpl implements TagHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||||
if (tag.isView()) return tag.read(asCompound());
|
return read(entries, tag, this::asCompound);
|
||||||
return read(entries, tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||||
if (tag.isView()) {
|
TagHandlerImpl local = this;
|
||||||
MutableNBTCompound viewCompound = new MutableNBTCompound();
|
final Tag.PathEntry[] paths = tag.path;
|
||||||
tag.write(viewCompound, value);
|
final boolean present = value != null;
|
||||||
updateContent(viewCompound);
|
final int tagIndex = tag.index;
|
||||||
} else {
|
final boolean isView = tag.isView();
|
||||||
final int tagIndex = tag.index;
|
synchronized (this) {
|
||||||
final Tag.PathEntry[] paths = tag.path;
|
if (paths != null) {
|
||||||
final boolean present = value != null;
|
if ((local = traversePathWrite(this, paths, present)) == null)
|
||||||
TagHandlerImpl local = this;
|
return; // Tried to remove an absent tag. Do nothing
|
||||||
synchronized (this) {
|
}
|
||||||
if (paths != null) {
|
SPMCMap entries = local.entries;
|
||||||
if ((local = traversePathWrite(this, paths, present)) == null)
|
if (present) {
|
||||||
return; // Tried to remove an absent tag. Do nothing
|
if (!isView) {
|
||||||
}
|
|
||||||
SPMCMap entries = local.entries;
|
|
||||||
if (present) {
|
|
||||||
entries.put(tagIndex, valueToEntry(local, tag, value));
|
entries.put(tagIndex, valueToEntry(local, tag, value));
|
||||||
} else {
|
} else {
|
||||||
// Remove recursively
|
local.updateContent((NBTCompound) tag.entry.write(value));
|
||||||
if (entries.remove(tagIndex) == null) return;
|
return;
|
||||||
if (paths != null) {
|
}
|
||||||
TagHandlerImpl tmp = local;
|
} else {
|
||||||
int i = paths.length;
|
// Remove recursively
|
||||||
do {
|
if (!isView) {
|
||||||
if (!tmp.entries.isEmpty()) break;
|
if (entries.remove(tagIndex) == null) return;
|
||||||
tmp = tmp.parent;
|
} else {
|
||||||
tmp.entries.remove(paths[--i].index());
|
entries.clear();
|
||||||
} while (i > 0);
|
}
|
||||||
}
|
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;
|
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;
|
final Tag.PathEntry[] paths = tag.path;
|
||||||
|
TagHandlerImpl pathHandler = null;
|
||||||
if (paths != null) {
|
if (paths != null) {
|
||||||
// Must be a path-able entry
|
if ((pathHandler = traversePathRead(paths, entries)) == null)
|
||||||
if ((entries = traversePathRead(paths, entries)) == null)
|
return tag.createDefault(); // Must be a path-able entry, but not present
|
||||||
return tag.createDefault();
|
entries = pathHandler.entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tag.isView()) {
|
||||||
|
return tag.read(pathHandler != null ?
|
||||||
|
pathHandler.asCompound() : rootCompoundSupplier.get());
|
||||||
|
}
|
||||||
|
|
||||||
final Entry<?> entry;
|
final Entry<?> entry;
|
||||||
if ((entry = entries.get(tag.index)) == null) {
|
if ((entry = entries.get(tag.index)) == null) {
|
||||||
return tag.createDefault();
|
return tag.createDefault();
|
||||||
@ -189,25 +201,29 @@ final class TagHandlerImpl implements TagHandler {
|
|||||||
return type == null || type == nbt.getID() ? serializerEntry.read(nbt) : tag.createDefault();
|
return type == null || type == nbt.getID() ? serializerEntry.read(nbt) : tag.createDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Int2ObjectOpenHashMap<Entry<?>> traversePathRead(Tag.PathEntry[] paths,
|
private static TagHandlerImpl traversePathRead(Tag.PathEntry[] paths,
|
||||||
Int2ObjectOpenHashMap<Entry<?>> entries) {
|
Int2ObjectOpenHashMap<Entry<?>> entries) {
|
||||||
|
assert paths != null && paths.length > 0;
|
||||||
|
TagHandlerImpl result = null;
|
||||||
for (var path : paths) {
|
for (var path : paths) {
|
||||||
final Entry<?> entry;
|
final Entry<?> entry;
|
||||||
if ((entry = entries.get(path.index())) == null)
|
if ((entry = entries.get(path.index())) == null)
|
||||||
return null;
|
return null;
|
||||||
if (entry instanceof PathEntry pathEntry) {
|
if (entry instanceof PathEntry pathEntry) {
|
||||||
entries = pathEntry.value.entries;
|
result = pathEntry.value;
|
||||||
} else if (entry.updatedNbt() instanceof NBTCompound compound) {
|
} else if (entry.updatedNbt() instanceof NBTCompound compound) {
|
||||||
// Slow path forcing a conversion of the structure to NBTCompound
|
// Slow path forcing a conversion of the structure to NBTCompound
|
||||||
// TODO should the handler be cached inside the entry?
|
// TODO should the handler be cached inside the entry?
|
||||||
TagHandlerImpl tmp = fromCompound(compound);
|
result = fromCompound(compound);
|
||||||
entries = tmp.entries;
|
|
||||||
} else {
|
} else {
|
||||||
// Entry is not path-able
|
// Entry is not path-able
|
||||||
return null;
|
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 {
|
private record Cache(Int2ObjectOpenHashMap<Entry<?>> entries, NBTCompound compound) implements TagReadable {
|
||||||
@ -215,8 +231,7 @@ final class TagHandlerImpl implements TagHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||||
if (tag.isView()) return tag.read(compound);
|
return read(entries, tag, () -> compound);
|
||||||
return read(entries, tag);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +81,71 @@ public class TagViewTest {
|
|||||||
""", handler.asCompound());
|
""", 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
|
@Test
|
||||||
public void compoundSerializer() {
|
public void compoundSerializer() {
|
||||||
var tag = Tag.View(TagSerializer.COMPOUND);
|
var tag = Tag.View(TagSerializer.COMPOUND);
|
||||||
|
Loading…
Reference in New Issue
Block a user