Prepare better nbt conversion

Signed-off-by: TheMode <themode@outlook.fr>
This commit is contained in:
TheMode 2022-04-09 16:17:24 +02:00
parent c22c4e914a
commit 23e1c8a0bc
4 changed files with 66 additions and 54 deletions

View File

@ -247,16 +247,23 @@ public class Tag<T> {
return tag(key, Serializers.STRING);
}
public static <T extends NBT> @NotNull Tag<T> NBT(@NotNull String key) {
return tag(key, (Serializers.Entry<T, ? extends NBT>) Serializers.NBT_ENTRY);
}
public static @NotNull Tag<ItemStack> 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.
* <p>
* Specialized tags are recommended if the type is known as conversion will be required both way (read and write).
*/
public static @NotNull Tag<NBT> NBT(@NotNull String key) {
return tag(key, Serializers.NBT_ENTRY);
}
/**
* Creates a tag containing multiple fields.
* <p>
* 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<T> {
return fromSerializer(key, serializer);
}
/**
* Specialized Structure tag affecting the src of the handler (i.e. overwrite all its data).
* <p>
* Must be used with care.
*/
public static <T> @NotNull Tag<T> View(@NotNull TagSerializer<T> serializer) {
return Structure("", serializer);
}

View File

@ -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);
}
}

View File

@ -23,19 +23,40 @@ final class TagHandlerImpl implements TagHandler {
}
@Override
public synchronized <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
// Convert value to fit the tag (e.g. list copies)
if (value != null) {
final UnaryOperator<T> copy = tag.copy;
if (copy != null) value = copy.apply(value);
}
// View tag access
public <T> void setTag(@NotNull Tag<T> 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<T> 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 <T> void write(@NotNull Tag<T> 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<NBT> 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<NBT> tag = Tag.NBT(entry.getKey());
final NBT nbt = entry.getValue();
handler.setTag(tag, nbt);
}
return handler;
}
}

View File

@ -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<NBTCompound> 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<NBTCompound> 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);