Temporary tag fix

Signed-off-by: TheMode <themode@outlook.fr>
This commit is contained in:
TheMode 2022-04-25 07:26:26 +02:00
parent acd3345fc9
commit a74b6ce220
3 changed files with 151 additions and 27 deletions

View File

@ -21,12 +21,6 @@ final class TagHandlerImpl implements TagHandler {
private volatile SPMCMap entries;
private Cache cache;
TagHandlerImpl(TagHandlerImpl parent, SPMCMap entries, Cache cache) {
this.parent = parent;
this.entries = entries;
this.cache = cache;
}
TagHandlerImpl(TagHandlerImpl parent) {
this.parent = parent;
this.entries = new SPMCMap(this);
@ -60,7 +54,7 @@ final class TagHandlerImpl implements TagHandler {
tag.write(viewCompound, value);
updateContent(viewCompound);
} else {
final Entry<?> entry = valueToEntry(tag, value);
Entry<?> entry = valueToEntry(tag, value);
final int tagIndex = tag.index;
final Tag.PathEntry[] paths = tag.path;
final boolean present = entry != null;
@ -71,6 +65,11 @@ final class TagHandlerImpl implements TagHandler {
return;
}
SPMCMap entries = local.entries;
if (entry instanceof PathEntry pathEntry) {
var childHandler = new TagHandlerImpl(local);
childHandler.updateContent(pathEntry.updatedNbt());
entry = new PathEntry(tag.getKey(), childHandler);
}
if (present) entries.put(tagIndex, entry);
else entries.remove(tagIndex);
entries.invalidate();
@ -102,9 +101,8 @@ final class TagHandlerImpl implements TagHandler {
}
@Override
public synchronized @NotNull TagHandler copy() {
assert parent == null;
return new TagHandlerImpl(null, entries.clone(), cache);
public @NotNull TagHandler copy() {
return fromCompound(asCompound());
}
@Override
@ -132,6 +130,12 @@ final class TagHandlerImpl implements TagHandler {
final Entry<?> entry = local.entries.get(pathIndex);
if (entry instanceof PathEntry pathEntry) {
// Existing path, continue navigating
{
// FIXME
//assert pathEntry.value.parent == local : "Path parent is invalid: " + pathEntry.value.parent + " != " + local;
pathEntry.value.cache = null;
pathEntry.value.parent.cache = null;
}
local = pathEntry.value;
} else {
if (!present) return null;
@ -170,21 +174,18 @@ final class TagHandlerImpl implements TagHandler {
return local;
}
private Cache updatedCache() {
VarHandle.fullFence();
private synchronized Cache updatedCache() {
Cache cache;
if (!CACHE_ENABLE || (cache = this.cache) == null) {
synchronized (this) {
final SPMCMap entries = this.entries;
if (!entries.isEmpty()) {
MutableNBTCompound tmp = new MutableNBTCompound();
for (Entry<?> entry : entries.values()) {
if (entry != null) tmp.put(entry.tag().getKey(), entry.updatedNbt());
}
cache = new Cache(entries.clone(), tmp.toCompound());
} else cache = Cache.EMPTY;
this.cache = cache;
}
final SPMCMap entries = this.entries;
if (!entries.isEmpty()) {
MutableNBTCompound tmp = new MutableNBTCompound();
for (Entry<?> entry : entries.values()) {
if (entry != null) tmp.put(entry.tag().getKey(), entry.updatedNbt());
}
cache = new Cache(entries.clone(), tmp.toCompound());
} else cache = Cache.EMPTY;
this.cache = cache;
}
return cache;
}

View File

@ -2,6 +2,7 @@ package net.minestom.server.tag;
import org.junit.jupiter.api.Test;
import static net.minestom.server.api.TestUtils.assertEqualsSNBT;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
@ -9,11 +10,64 @@ public class TagHandlerCopyTest {
@Test
public void copy() {
var handler1 = TagHandler.newHandler();
handler1.setTag(Tag.String("key"), "test");
var handler = TagHandler.newHandler();
handler.setTag(Tag.String("key"), "test");
var handler2 = handler1.copy();
assertEquals(handler1.getTag(Tag.String("key")), handler2.getTag(Tag.String("key")));
var copy = handler.copy();
assertEquals(handler.getTag(Tag.String("key")), copy.getTag(Tag.String("key")));
}
@Test
public void copyCachePath() {
var tag = Tag.String("key").path("path");
var handler = TagHandler.newHandler();
handler.setTag(tag, "test");
assertEqualsSNBT("""
{"path":{"key":"test"}}
""", handler.asCompound());
var copy = handler.copy();
handler.setTag(tag, "test2");
assertEqualsSNBT("""
{"path":{"key":"test2"}}
""", handler.asCompound());
assertEqualsSNBT("""
{"path":{"key":"test"}}
""", copy.asCompound());
copy.setTag(tag, "test3");
assertEquals("test3", copy.getTag(tag));
assertEqualsSNBT("""
{"path":{"key":"test3"}}
""", copy.asCompound());
}
@Test
public void copyCache() {
var tag = Tag.String("key");
var handler = TagHandler.newHandler();
handler.setTag(tag, "test");
assertEqualsSNBT("""
{"key":"test"}
""", handler.asCompound());
var copy = handler.copy();
handler.setTag(tag, "test2");
assertEqualsSNBT("""
{"key":"test2"}
""", handler.asCompound());
assertEqualsSNBT("""
{"key":"test"}
""", copy.asCompound());
copy.setTag(tag, "test3");
assertEquals("test3", copy.getTag(tag));
assertEqualsSNBT("""
{"key":"test2"}
""", handler.asCompound());
assertEqualsSNBT("""
{"key":"test3"}
""", copy.asCompound());
}
@Test

View File

@ -50,6 +50,75 @@ public class TagNbtTest {
assertEqualsSNBT("{}", handler.asCompound());
}
@Test
public void fromCompoundModify() {
var compound = NBT.Compound(Map.of("key", NBT.Int(5)));
var handler = TagHandler.fromCompound(compound);
assertEquals(compound, handler.asCompound());
assertEqualsSNBT("""
{"key":5}
""", handler.asCompound());
handler.setTag(Tag.Integer("key"), 10);
assertEquals(10, handler.getTag(Tag.Integer("key")));
assertEqualsSNBT("""
{"key":10}
""", handler.asCompound());
handler.setTag(Tag.Integer("key"), 15);
assertEqualsSNBT("""
{"key":15}
""", handler.asCompound());
}
@Test
public void fromCompoundModifyPath() {
var compound = NBT.Compound(Map.of("path", NBT.Compound(Map.of("key", NBT.Int(5)))));
var handler = TagHandler.fromCompound(compound);
var tag = Tag.Integer("key").path("path");
handler.setTag(tag, 10);
assertEquals(10, handler.getTag(tag));
assertEqualsSNBT("""
{"path":{"key":10}}
""", handler.asCompound());
handler.setTag(tag, 15);
assertEqualsSNBT("""
{"path":{"key":15}}
""", handler.asCompound());
}
@Test
public void fromCompoundModifyDoublePath() {
var compound = NBT.Compound(Map.of("path", NBT.Compound(Map.of("path2",
NBT.Compound(Map.of("key", NBT.Int(5)))))));
var handler = TagHandler.fromCompound(compound);
var tag = Tag.Integer("key").path("path", "path2");
handler.setTag(tag, 10);
assertEquals(10, handler.getTag(tag));
assertEqualsSNBT("""
{"path":{"path2":{"key":10}}}
""", handler.asCompound());
handler.setTag(tag, 15);
assertEqualsSNBT("""
{"path":{"path2":{"key":15}}}
""", handler.asCompound());
}
@Test
public void compoundOverride() {
var handler = TagHandler.newHandler();
var nbtTag = Tag.NBT("path1");
var nbt1 = NBT.Compound(Map.of("key", NBT.Int(5)));
var nbt2 = NBT.Compound(Map.of("other-key", NBT.Int(5)));
handler.setTag(nbtTag, nbt1);
assertEquals(nbt1, handler.getTag(nbtTag));
handler.setTag(nbtTag, nbt2);
assertEquals(nbt2, handler.getTag(nbtTag));
}
@Test
public void compoundRead() {
var handler = TagHandler.newHandler();