From f84958957cbf28793662c675f4ccc17769b5c10c Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Tue, 30 Jun 2020 13:44:26 +0100 Subject: [PATCH 1/2] Fix various lighting issues fixes #496 possibly fixes #497 --- .../adapter/mc1_14/BukkitGetBlocks_1_14.java | 43 ++++++++++++++++--- .../adapter/mc1_15/BukkitGetBlocks_1_15.java | 43 ++++++++++++++++--- .../mc1_15_2/BukkitGetBlocks_1_15_2.java | 37 +++++++++++++--- .../implementation/blocks/CharSetBlocks.java | 12 ++++++ 4 files changed, 115 insertions(+), 20 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitGetBlocks_1_14.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitGetBlocks_1_14.java index eace17737..7196fb21b 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitGetBlocks_1_14.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitGetBlocks_1_14.java @@ -56,7 +56,7 @@ import net.minecraft.server.v1_14_R1.Entity; import net.minecraft.server.v1_14_R1.EntityTypes; import net.minecraft.server.v1_14_R1.EnumSkyBlock; import net.minecraft.server.v1_14_R1.IBlockData; -import net.minecraft.server.v1_14_R1.LightEngineThreaded; +import net.minecraft.server.v1_14_R1.LightEngine; import net.minecraft.server.v1_14_R1.NBTTagCompound; import net.minecraft.server.v1_14_R1.NBTTagInt; import net.minecraft.server.v1_14_R1.NibbleArray; @@ -69,8 +69,13 @@ import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class BukkitGetBlocks_1_14 extends CharGetBlocks { + + private static final Logger log = LoggerFactory.getLogger(BukkitGetBlocks_1_14.class); + public ChunkSection[] sections; public Chunk nmsChunk; public WorldServer world; @@ -129,7 +134,17 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks { int layer = y >> 4; if (skyLight[layer] == null) { //getDataLayerData - skyLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(SectionPosition.a(nmsChunk.getPos(), layer)); + SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), layer); + NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition); + // If the server hasn't generated the section's NibbleArray yet, it will be null + if (nibbleArray == null) { + byte[] a = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(a, (byte) 15); + nibbleArray = new NibbleArray(a); + ((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray); + } + skyLight[layer] = nibbleArray; } long l = BlockPosition.a(x, y, z); return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l))); @@ -140,7 +155,17 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks { int layer = y >> 4; if (blockLight[layer] == null) { //getDataLayerData - blockLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(SectionPosition.a(nmsChunk.getPos(), layer)); + SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), layer); + NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition); + // If the server hasn't generated the section's NibbleArray yet, it will be null + if (nibbleArray == null) { + byte[] a = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(a, (byte) 15); + nibbleArray = new NibbleArray(a); + ((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray); + } + blockLight[layer] = nibbleArray; } long l = BlockPosition.a(x, y, z); return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l))); @@ -299,7 +324,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks { } else { existingSection = sections[layer]; if (existingSection == null) { - System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); + log.error("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); continue; } } @@ -326,7 +351,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks { } newSection = BukkitAdapter_1_14.newChunkSection(layer, this::load, setArr, fastmode); if (!BukkitAdapter_1_14.setSectionAtomic(sections, existingSection, newSection, layer)) { - System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); + log.error("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); continue; } else { updateGet(this, nmsChunk, sections, newSection, setArr, layer); @@ -667,9 +692,13 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks { if (light[Y] == null) { continue; } - NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(SectionPosition.a(nmsChunk.getPos(), Y)); + SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y); + NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition); if (nibble == null) { - continue; + byte[] a = new byte[2048]; + Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0); + nibble = new NibbleArray(a); + ((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibble); } synchronized (nibble) { for (int i = 0; i < 4096; i++) { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitGetBlocks_1_15.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitGetBlocks_1_15.java index c9fbca585..57cc44026 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitGetBlocks_1_15.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitGetBlocks_1_15.java @@ -57,7 +57,7 @@ import net.minecraft.server.v1_15_R1.Entity; import net.minecraft.server.v1_15_R1.EntityTypes; import net.minecraft.server.v1_15_R1.EnumSkyBlock; import net.minecraft.server.v1_15_R1.IBlockData; -import net.minecraft.server.v1_15_R1.LightEngineThreaded; +import net.minecraft.server.v1_15_R1.LightEngine; import net.minecraft.server.v1_15_R1.NBTTagCompound; import net.minecraft.server.v1_15_R1.NBTTagInt; import net.minecraft.server.v1_15_R1.NibbleArray; @@ -70,8 +70,13 @@ import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class BukkitGetBlocks_1_15 extends CharGetBlocks { + + private static final Logger log = LoggerFactory.getLogger(BukkitGetBlocks_1_15.class); + private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); private final static Function nmsTile2We = tileEntity -> new LazyCompoundTag_1_15(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound()))); public ChunkSection[] sections; @@ -136,7 +141,17 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks { public int getSkyLight(int x, int y, int z) { int layer = y >> 4; if (skyLight[layer] == null) { - skyLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(SectionPosition.a(nmsChunk.getPos(), layer)); + SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), layer); + NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition); + // If the server hasn't generated the section's NibbleArray yet, it will be null + if (nibbleArray == null) { + byte[] a = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(a, (byte) 15); + nibbleArray = new NibbleArray(a); + ((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray); + } + skyLight[layer] = nibbleArray; } long l = BlockPosition.a(x, y, z); return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l))); @@ -146,7 +161,17 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks { public int getEmmittedLight(int x, int y, int z) { int layer = y >> 4; if (blockLight[layer] == null) { - blockLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(SectionPosition.a(nmsChunk.getPos(), layer)); + SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), layer); + NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition); + // If the server hasn't generated the section's NibbleArray yet, it will be null + if (nibbleArray == null) { + byte[] a = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(a, (byte) 15); + nibbleArray = new NibbleArray(a); + ((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray); + } + blockLight[layer] = nibbleArray; } long l = BlockPosition.a(x, y, z); return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l))); @@ -305,7 +330,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks { } else { existingSection = sections[layer]; if (existingSection == null) { - System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); + log.error("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); continue; } } @@ -332,7 +357,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks { } newSection = BukkitAdapter_1_15.newChunkSection(layer, this::load, setArr, fastmode); if (!BukkitAdapter_1_15.setSectionAtomic(sections, existingSection, newSection, layer)) { - System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); + log.error("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); continue; } else { updateGet(this, nmsChunk, sections, newSection, setArr, layer); @@ -684,9 +709,13 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks { if (light[Y] == null) { continue; } - NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(SectionPosition.a(nmsChunk.getPos(), Y)); + SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y); + NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition); if (nibble == null) { - continue; + byte[] a = new byte[2048]; + Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0); + nibble = new NibbleArray(a); + ((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibble); } synchronized (nibble) { for (int i = 0; i < 4096; i++) { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java index 3292cc556..90dc417b4 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java @@ -40,6 +40,7 @@ import net.minecraft.server.v1_15_R1.Entity; import net.minecraft.server.v1_15_R1.EntityTypes; import net.minecraft.server.v1_15_R1.EnumSkyBlock; import net.minecraft.server.v1_15_R1.IBlockData; +import net.minecraft.server.v1_15_R1.LightEngine; import net.minecraft.server.v1_15_R1.NBTTagCompound; import net.minecraft.server.v1_15_R1.NBTTagInt; import net.minecraft.server.v1_15_R1.NibbleArray; @@ -140,7 +141,17 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { public int getSkyLight(int x, int y, int z) { int layer = y >> 4; if (skyLight[layer] == null) { - skyLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(SectionPosition.a(nmsChunk.getPos(), layer)); + SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), layer); + NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition); + // If the server hasn't generated the section's NibbleArray yet, it will be null + if (nibbleArray == null) { + byte[] a = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(a, (byte) 15); + nibbleArray = new NibbleArray(a); + ((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray); + } + skyLight[layer] = nibbleArray; } long l = BlockPosition.a(x, y, z); return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l))); @@ -150,7 +161,17 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { public int getEmmittedLight(int x, int y, int z) { int layer = y >> 4; if (blockLight[layer] == null) { - blockLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(SectionPosition.a(nmsChunk.getPos(), layer)); + SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), layer); + NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition); + // If the server hasn't generated the section's NibbleArray yet, it will be null + if (nibbleArray == null) { + byte[] a = new byte[2048]; + // Safe enough to assume if it's not created, it's not got any emitted light. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(a, (byte) 0); + nibbleArray = new NibbleArray(a); + ((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray); + } + blockLight[layer] = nibbleArray; } long l = BlockPosition.a(x, y, z); return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l))); @@ -316,7 +337,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { } else { existingSection = sections[layer]; if (existingSection == null) { - System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); + log.error("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); continue; } } @@ -343,7 +364,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { } newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::load, setArr, fastmode); if (!BukkitAdapter_1_15_2.setSectionAtomic(sections, existingSection, newSection, layer)) { - System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); + log.error("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); continue; } else { updateGet(this, nmsChunk, sections, newSection, setArr, layer); @@ -689,9 +710,13 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { if (light[Y] == null) { continue; } - NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(SectionPosition.a(nmsChunk.getPos(), Y)); + SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y); + NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition); if (nibble == null) { - continue; + byte[] a = new byte[2048]; + Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0); + nibble = new NibbleArray(a); + ((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibble); } synchronized (nibble) { for (int i = 0; i < 4096; i++) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java index 1dda73c3a..744e92f06 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java @@ -181,6 +181,18 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { } @Override public void setFullBright(int layer) { + if (light == null) { + light = new char[16][]; + } + if (light[layer] == null) { + light[layer] = new char[4096]; + } + if (skyLight == null) { + skyLight = new char[16][]; + } + if (skyLight[layer] == null) { + skyLight[layer] = new char[4096]; + } Arrays.fill(light[layer], (char) 15); Arrays.fill(skyLight[layer], (char) 15); } From 4ca19acb489b219518e964c2ff7ce3f16ad137bb Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Tue, 30 Jun 2020 13:51:27 +0100 Subject: [PATCH 2/2] implement 1.16 methods --- .../fawe/bukkit/wrapper/AsyncWorld.java | 32 ++++++++++++++----- .../wrapper/state/AsyncDataContainer.java | 11 +++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java index 4252d3f32..c6b72076b 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java @@ -884,6 +884,14 @@ public class AsyncWorld extends PassthroughExtent implements World { parent.setWaterAnimalSpawnLimit(limit); } + @Override public int getWaterAmbientSpawnLimit() { + return 0; + } + + @Override public void setWaterAmbientSpawnLimit(int limit) { + + } + @Override public int getAmbientSpawnLimit() { return parent.getAmbientSpawnLimit(); @@ -1284,19 +1292,27 @@ public class AsyncWorld extends PassthroughExtent implements World { return parent.getHighestBlockAt(location, heightmap); } - public long getTicksPerWaterSpawns() { - throw new UnsupportedOperationException(); + public long getTicksPerWaterSpawns() throws UnsupportedOperationException { + return parent.getTicksPerWaterSpawns(); } - public void setTicksPerWaterSpawns(int ticksPerWaterSpawns) { - throw new UnsupportedOperationException(); + public void setTicksPerWaterSpawns(int ticksPerWaterSpawns) throws UnsupportedOperationException { + parent.setTicksPerWaterSpawns(ticksPerWaterSpawns); } - public long getTicksPerAmbientSpawns() { - throw new UnsupportedOperationException(); + @Override public long getTicksPerWaterAmbientSpawns() { + return parent.getTicksPerWaterAmbientSpawns(); } - public void setTicksPerAmbientSpawns(int ticksPerAmbientSpawns) { - throw new UnsupportedOperationException(); + @Override public void setTicksPerWaterAmbientSpawns(int ticksPerAmbientSpawns) { + parent.setTicksPerWaterAmbientSpawns(ticksPerAmbientSpawns); + } + + public long getTicksPerAmbientSpawns() throws UnsupportedOperationException { + return parent.getTicksPerAmbientSpawns(); + } + + public void setTicksPerAmbientSpawns(int ticksPerAmbientSpawns) throws UnsupportedOperationException { + parent.setTicksPerAmbientSpawns(ticksPerAmbientSpawns); } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java index f1fbbcbb2..51da9f50c 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java @@ -5,16 +5,21 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.Set; + import org.apache.commons.lang.Validate; import org.bukkit.NamespacedKey; import org.bukkit.persistence.PersistentDataAdapterContext; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; public final class AsyncDataContainer implements PersistentDataContainer { private final CompoundTag root; + private final Set keys = new HashSet<>(); public AsyncDataContainer(CompoundTag root) { this.root = root; @@ -47,6 +52,7 @@ public final class AsyncDataContainer implements PersistentDataContainer { Validate.notNull(type, "The provided type for the custom value was null"); Validate.notNull(value, "The provided value for the custom value was null"); get().put(key.toString(), FaweCache.IMP.asTag(type.toPrimitive(value, null))); + keys.add(key); } public boolean has(NamespacedKey key, PersistentDataType type) { @@ -69,9 +75,14 @@ public final class AsyncDataContainer implements PersistentDataContainer { return z != null ? z : defaultValue; } + @Override public @NotNull Set getKeys() { + return keys; + } + public void remove(NamespacedKey key) { Validate.notNull(key, "The provided key for the custom value was null"); get(false).remove(key.toString()); + keys.remove(key); } public boolean isEmpty() {