From b0f0a4deb57bfb9d164bc125f96d7ce24b1fd702 Mon Sep 17 00:00:00 2001 From: mastermc05 Date: Tue, 29 Mar 2022 23:33:46 +0300 Subject: [PATCH 1/7] First idea implementation --- .../BukkitVersionHelperSpigot116_2.java | 14 ++- .../BukkitVersionHelperSpigot116_3.java | 14 ++- .../BukkitVersionHelperSpigot116_4.java | 14 ++- .../v116/BukkitVersionHelperSpigot116.java | 12 ++- .../v117/BukkitVersionHelperSpigot117.java | 16 +++- .../v118_2/AsyncChunkProvider118_2.java | 56 +++++++++++ .../BukkitVersionHelperSpigot118_2.java | 23 ++++- .../helper/v118_2/MapChunkCache118_2.java | 44 ++++++--- .../v118/BukkitVersionHelperSpigot118.java | 19 ++-- .../bukkit/helper/BukkitVersionHelper.java | 4 + .../bukkit/helper/BukkitVersionHelperCB.java | 6 ++ .../helper/BukkitVersionHelperGlowstone.java | 7 +- .../java/org/dynmap/bukkit/DynmapPlugin.java | 93 +++++++++++-------- 13 files changed, 243 insertions(+), 79 deletions(-) create mode 100644 bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java diff --git a/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java b/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java index e493ec2d..1b4fa1e9 100644 --- a/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java +++ b/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java @@ -37,12 +37,14 @@ import net.minecraft.server.v1_16_R2.MinecraftServer; * Helper for isolation of bukkit version specific issues */ public class BukkitVersionHelperSpigot116_2 extends BukkitVersionHelperGeneric { - private Field watercolorfield; + private final boolean unsafeAsync; + private Field watercolorfield; public BukkitVersionHelperSpigot116_2() { Class biomefog = getNMSClass("net.minecraft.server.BiomeFog"); watercolorfield = getPrivateField(biomefog, new String[] { "c" }, int.class); - } + this.unsafeAsync = true; + } /** * Get block short name list @@ -69,7 +71,13 @@ public class BukkitVersionHelperSpigot116_2 extends BukkitVersionHelperGeneric { } private Object[] biomelist; - /** + + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } + + /** * Get list of defined biomebase objects */ @Override diff --git a/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/BukkitVersionHelperSpigot116_3.java b/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/BukkitVersionHelperSpigot116_3.java index ae63946c..16cd5805 100644 --- a/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/BukkitVersionHelperSpigot116_3.java +++ b/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/BukkitVersionHelperSpigot116_3.java @@ -37,12 +37,14 @@ import net.minecraft.server.v1_16_R2.BlockPosition; * Helper for isolation of bukkit version specific issues */ public class BukkitVersionHelperSpigot116_3 extends BukkitVersionHelperGeneric { - private Field watercolorfield; + private final boolean unsafeAsync; + private Field watercolorfield; public BukkitVersionHelperSpigot116_3() { Class biomefog = getNMSClass("net.minecraft.server.BiomeFog"); watercolorfield = getPrivateField(biomefog, new String[] { "c" }, int.class); - } + this.unsafeAsync = true; + } /** * Get block short name list @@ -69,7 +71,13 @@ public class BukkitVersionHelperSpigot116_3 extends BukkitVersionHelperGeneric { } private Object[] biomelist; - /** + + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } + + /** * Get list of defined biomebase objects */ @Override diff --git a/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/BukkitVersionHelperSpigot116_4.java b/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/BukkitVersionHelperSpigot116_4.java index 32ae9698..b0243d8f 100644 --- a/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/BukkitVersionHelperSpigot116_4.java +++ b/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/BukkitVersionHelperSpigot116_4.java @@ -26,12 +26,14 @@ import java.util.List; * Helper for isolation of bukkit version specific issues */ public class BukkitVersionHelperSpigot116_4 extends BukkitVersionHelperGeneric { - private Field watercolorfield; + private final boolean unsafeAsync; + private Field watercolorfield; public BukkitVersionHelperSpigot116_4() { Class biomefog = getNMSClass("net.minecraft.server.BiomeFog"); watercolorfield = getPrivateField(biomefog, new String[] { "c" }, int.class); - } + this.unsafeAsync = true; + } /** * Get block short name list @@ -58,7 +60,13 @@ public class BukkitVersionHelperSpigot116_4 extends BukkitVersionHelperGeneric { } private Object[] biomelist; - /** + + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } + + /** * Get list of defined biomebase objects */ @Override diff --git a/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/BukkitVersionHelperSpigot116.java b/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/BukkitVersionHelperSpigot116.java index c522d77d..9646e6cd 100644 --- a/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/BukkitVersionHelperSpigot116.java +++ b/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/BukkitVersionHelperSpigot116.java @@ -36,12 +36,14 @@ import net.minecraft.server.v1_16_R1.BlockPosition; * Helper for isolation of bukkit version specific issues */ public class BukkitVersionHelperSpigot116 extends BukkitVersionHelperGeneric { + private final boolean unsafeAsync; private Field watercolorfield; public BukkitVersionHelperSpigot116() { Class biomefog = getNMSClass("net.minecraft.server.BiomeFog"); watercolorfield = getPrivateField(biomefog, new String[] { "c" }, int.class); - } + this.unsafeAsync = true; + } /** * Get block short name list @@ -59,7 +61,13 @@ public class BukkitVersionHelperSpigot116 extends BukkitVersionHelperGeneric { } private Object[] biomelist; - /** + + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } + + /** * Get list of defined biomebase objects */ @Override diff --git a/bukkit-helper-117/src/main/java/org/dynmap/bukkit/helper/v117/BukkitVersionHelperSpigot117.java b/bukkit-helper-117/src/main/java/org/dynmap/bukkit/helper/v117/BukkitVersionHelperSpigot117.java index 96116e88..e56fad95 100644 --- a/bukkit-helper-117/src/main/java/org/dynmap/bukkit/helper/v117/BukkitVersionHelperSpigot117.java +++ b/bukkit-helper-117/src/main/java/org/dynmap/bukkit/helper/v117/BukkitVersionHelperSpigot117.java @@ -58,11 +58,19 @@ import java.util.Map; /** * Helper for isolation of bukkit version specific issues */ -public class BukkitVersionHelperSpigot117 extends BukkitVersionHelper { - public BukkitVersionHelperSpigot117() { +public class BukkitVersionHelperSpigot117 extends BukkitVersionHelper { + private final boolean unsafeAsync; + + public BukkitVersionHelperSpigot117() { + this.unsafeAsync = true; } - - /** + + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } + + /** * Get block short name list */ @Override diff --git a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java new file mode 100644 index 00000000..9bbdd6b5 --- /dev/null +++ b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java @@ -0,0 +1,56 @@ +package org.dynmap.bukkit.helper.v118_2; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.server.level.WorldServer; +import net.minecraft.world.level.World; +import net.minecraft.world.level.chunk.Chunk; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * The provider used to work with paper libs + * Because paper libs need java 17 we can't interact with them directly + */ +public class AsyncChunkProvider118_2 { + private static final Thread ioThread; + private static final Method getChunk; + private static final Predicate ifFailed; + static { + try { + Predicate ifFailed1 = null; + Method getChunk1 = null; + Thread ioThread1 = null; + try { + Class threadClass = Class.forName("com.destroystokyo.paper.io.PaperFileIOThread"); + Class[] classes = threadClass.getClasses(); + Class holder = Arrays.stream(classes).filter(aClass -> aClass.getSimpleName().equals("Holder")).findAny().orElseThrow(RuntimeException::new); + ioThread1 = (Thread) holder.getField("INSTANCE").get(null); + getChunk1 = threadClass.getMethod("loadChunkDataAsync", WorldServer.class, int.class, int.class, int.class, Consumer.class, boolean.class, boolean.class, boolean.class); + NBTTagCompound failure = (NBTTagCompound) threadClass.getField("FAILURE_VALUE").get(null); + ifFailed1 = nbtTagCompound -> nbtTagCompound == failure; + } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) { + e.printStackTrace(); + } + ifFailed = Objects.requireNonNull(ifFailed1); + getChunk = Objects.requireNonNull(getChunk1); + ioThread = Objects.requireNonNull(ioThread1); + } catch (Throwable e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + public NBTTagCompound getChunk(WorldServer world, int x, int y) throws InvocationTargetException, IllegalAccessException, NoSuchFieldException { + CompletableFuture future = new CompletableFuture<>(); + getChunk.invoke(ioThread,world,x,y,5,(Consumer) future::complete, false, true, true); + Object resultFuture = future.join(); + if (resultFuture == null) return null; + NBTTagCompound result = (NBTTagCompound) resultFuture.getClass().getField("chunkData").get(resultFuture); + return ifFailed.test(result) ? null : result; + } +} diff --git a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/BukkitVersionHelperSpigot118_2.java b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/BukkitVersionHelperSpigot118_2.java index 83c80870..9d40746e 100644 --- a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/BukkitVersionHelperSpigot118_2.java +++ b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/BukkitVersionHelperSpigot118_2.java @@ -64,12 +64,25 @@ import java.util.Set; * Helper for isolation of bukkit version specific issues */ public class BukkitVersionHelperSpigot118_2 extends BukkitVersionHelper { - + private final boolean unsafeAsync; + public BukkitVersionHelperSpigot118_2() { - - } - - /** + boolean unsafeAsync1; + try { + Class.forName("com.destroystokyo.paper.io.PaperFileIOThread"); + unsafeAsync1 = false; + } catch (ClassNotFoundException e) { + unsafeAsync1 = true; + } + this.unsafeAsync = unsafeAsync1; + } + + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } + + /** * Get block short name list */ @Override diff --git a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java index 2e8b1972..ab135e87 100644 --- a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java +++ b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java @@ -1,8 +1,11 @@ package org.dynmap.bukkit.helper.v118_2; +import org.bukkit.Bukkit; import org.bukkit.World; +import org.bukkit.craftbukkit.v1_18_R2.CraftServer; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.dynmap.DynmapChunk; +import org.dynmap.bukkit.helper.BukkitVersionHelper; import org.dynmap.bukkit.helper.BukkitWorld; import org.dynmap.common.chunk.GenericChunk; import org.dynmap.common.chunk.GenericChunkCache; @@ -14,12 +17,15 @@ import net.minecraft.world.level.chunk.storage.ChunkRegionLoader; import net.minecraft.world.level.chunk.Chunk; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.util.List; +import java.util.concurrent.CompletableFuture; /** * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread */ public class MapChunkCache118_2 extends GenericMapChunkCache { + private final AsyncChunkProvider118_2 provider = BukkitVersionHelper.helper.isUnsafeAsync() ? null : new AsyncChunkProvider118_2(); private World w; /** * Construct empty cache @@ -30,20 +36,24 @@ public class MapChunkCache118_2 extends GenericMapChunkCache { // Load generic chunk from existing and already loaded chunk protected GenericChunk getLoadedChunk(DynmapChunk chunk) { - CraftWorld cw = (CraftWorld) w; - NBTTagCompound nbt = null; - GenericChunk gc = null; - if (cw.isChunkLoaded(chunk.x, chunk.z)) { - Chunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z); - if ((c != null) && c.o) { // c.loaded - nbt = ChunkRegionLoader.a(cw.getHandle(), c); - } - if (nbt != null) { - gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); - } + CraftWorld cw = (CraftWorld) w; + NBTTagCompound nbt = null; + GenericChunk gc = null; + if (cw.isChunkLoaded(chunk.x, chunk.z)) { + Chunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z); //already safe async on vanilla + if ((c != null) && c.o) { // c.loaded + if (provider == null) { //idk why, but paper uses this only sync, so I won't be smarter + nbt = ChunkRegionLoader.a(cw.getHandle(), c); + } else { + nbt = CompletableFuture.supplyAsync(() -> ChunkRegionLoader.a(cw.getHandle(), c), ((CraftServer) Bukkit.getServer()).getServer()).join(); } - return gc; - } + } + if (nbt != null) { + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); + } + } + return gc; + } // Load generic chunk from unloaded chunk protected GenericChunk loadChunk(DynmapChunk chunk) { CraftWorld cw = (CraftWorld) w; @@ -51,8 +61,12 @@ public class MapChunkCache118_2 extends GenericMapChunkCache { ChunkCoordIntPair cc = new ChunkCoordIntPair(chunk.x, chunk.z); GenericChunk gc = null; try { - nbt = cw.getHandle().k().a.f(cc); // playerChunkMap - } catch (IOException iox) { + if (provider == null){ + nbt = cw.getHandle().k().a.f(cc); // playerChunkMap + } else { + nbt = provider.getChunk(cw.getHandle(),chunk.x, chunk.z); + } + } catch (IOException | InvocationTargetException | IllegalAccessException | NoSuchFieldException ignored) { } if (nbt != null) { gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); diff --git a/bukkit-helper-118/src/main/java/org/dynmap/bukkit/helper/v118/BukkitVersionHelperSpigot118.java b/bukkit-helper-118/src/main/java/org/dynmap/bukkit/helper/v118/BukkitVersionHelperSpigot118.java index d5381c60..dd9aa5c3 100644 --- a/bukkit-helper-118/src/main/java/org/dynmap/bukkit/helper/v118/BukkitVersionHelperSpigot118.java +++ b/bukkit-helper-118/src/main/java/org/dynmap/bukkit/helper/v118/BukkitVersionHelperSpigot118.java @@ -63,13 +63,20 @@ import java.util.Set; /** * Helper for isolation of bukkit version specific issues */ -public class BukkitVersionHelperSpigot118 extends BukkitVersionHelper { - - public BukkitVersionHelperSpigot118() { - +public class BukkitVersionHelperSpigot118 extends BukkitVersionHelper { + + private final boolean unsafeAsync; + + public BukkitVersionHelperSpigot118() { + this.unsafeAsync = true; } - - /** + + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } + + /** * Get block short name list */ @Override diff --git a/bukkit-helper/src/main/java/org/dynmap/bukkit/helper/BukkitVersionHelper.java b/bukkit-helper/src/main/java/org/dynmap/bukkit/helper/BukkitVersionHelper.java index 8724eac8..58cdb90d 100644 --- a/bukkit-helper/src/main/java/org/dynmap/bukkit/helper/BukkitVersionHelper.java +++ b/bukkit-helper/src/main/java/org/dynmap/bukkit/helper/BukkitVersionHelper.java @@ -34,6 +34,10 @@ public abstract class BukkitVersionHelper { protected BukkitVersionHelper() { } + /** + * Get if it's unsafe to load chunks async + */ + public abstract boolean isUnsafeAsync(); /** * Get list of defined biomebase objects */ diff --git a/bukkit-helper/src/main/java/org/dynmap/bukkit/helper/BukkitVersionHelperCB.java b/bukkit-helper/src/main/java/org/dynmap/bukkit/helper/BukkitVersionHelperCB.java index 05da8fbe..d9ddd264 100644 --- a/bukkit-helper/src/main/java/org/dynmap/bukkit/helper/BukkitVersionHelperCB.java +++ b/bukkit-helper/src/main/java/org/dynmap/bukkit/helper/BukkitVersionHelperCB.java @@ -54,6 +54,12 @@ public class BukkitVersionHelperCB extends BukkitVersionHelperGeneric { isBadUnload = HDBlockModels.checkVersionRange(mcver, "1.9-"); Log.verboseinfo("MCVER=" + mcver + ", isBadUnload=" + isBadUnload); } + + @Override + public boolean isUnsafeAsync() { + return true; + } + @Override protected String getNMSPackage() { Server srv = Bukkit.getServer(); diff --git a/bukkit-helper/src/main/java/org/dynmap/bukkit/helper/BukkitVersionHelperGlowstone.java b/bukkit-helper/src/main/java/org/dynmap/bukkit/helper/BukkitVersionHelperGlowstone.java index 2629abc0..92629236 100644 --- a/bukkit-helper/src/main/java/org/dynmap/bukkit/helper/BukkitVersionHelperGlowstone.java +++ b/bukkit-helper/src/main/java/org/dynmap/bukkit/helper/BukkitVersionHelperGlowstone.java @@ -32,7 +32,12 @@ public class BukkitVersionHelperGlowstone extends BukkitVersionHelper { throw new IllegalArgumentException("Error initializing dynmap - Glowstone version incompatible!"); } } - + + @Override + public boolean isUnsafeAsync() { + return true; + } + @Override public Object[] getBiomeBaseList() { return new Object[0]; diff --git a/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java b/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java index fec426fd..75b203ca 100644 --- a/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java +++ b/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java @@ -481,6 +481,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { boolean rslt = permissions.hasOfflinePermission(player, perm); return rslt; } + private final Object[] lock = {}; /** * Render processor helper - used by code running on render threads to request chunk snapshot cache from server/sync thread */ @@ -514,46 +515,64 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { final MapChunkCache cc = c; while(!cc.isDoneLoading()) { - Future f = core.getServer().callSyncMethod(new Callable() { - public Boolean call() throws Exception { - boolean exhausted = true; - - if (prev_tick != cur_tick) { - prev_tick = cur_tick; - cur_tick_starttime = System.nanoTime(); - } - if(chunks_in_cur_tick > 0) { - boolean done = false; - while (!done) { - int cnt = chunks_in_cur_tick; - if (cnt > 5) cnt = 5; - chunks_in_cur_tick -= cc.loadChunks(cnt); - exhausted = (chunks_in_cur_tick == 0) || ((System.nanoTime() - cur_tick_starttime) > perTickLimit); - done = exhausted || cc.isDoneLoading(); + if (BukkitVersionHelper.helper.isUnsafeAsync()) { + Future f = core.getServer().callSyncMethod(new Callable() { + public Boolean call() throws Exception { + boolean exhausted = true; + + if (prev_tick != cur_tick) { + prev_tick = cur_tick; + cur_tick_starttime = System.nanoTime(); } + if (chunks_in_cur_tick > 0) { + boolean done = false; + while (!done) { + int cnt = chunks_in_cur_tick; + if (cnt > 5) cnt = 5; + chunks_in_cur_tick -= cc.loadChunks(cnt); + exhausted = (chunks_in_cur_tick == 0) || ((System.nanoTime() - cur_tick_starttime) > perTickLimit); + done = exhausted || cc.isDoneLoading(); + } + } + return exhausted; } - return exhausted; + }); + if (f == null) { + return null; + } + Boolean delay; + try { + delay = f.get(); + } catch (CancellationException cx) { + return null; + } catch (InterruptedException cx) { + return null; + } catch (ExecutionException ex) { + Log.severe("Exception while fetching chunks: ", ex.getCause()); + return null; + } catch (Exception ix) { + Log.severe(ix); + return null; + } + + if ((delay != null) && delay.booleanValue()) { + try { + Thread.sleep(25); + } catch (InterruptedException ix) { + } + } + } else { + try { + synchronized (lock) { + if (prev_tick != cur_tick) { + prev_tick = cur_tick; + cur_tick_starttime = System.nanoTime(); + } + cc.loadChunks(Integer.MAX_VALUE); + } + } catch (Exception e) { + e.printStackTrace(); } - }); - if (f == null) { - return null; - } - Boolean delay; - try { - delay = f.get(); - } catch (CancellationException cx) { - return null; - } catch (InterruptedException cx) { - return null; - } catch (ExecutionException ex) { - Log.severe("Exception while fetching chunks: ", ex.getCause()); - return null; - } catch (Exception ix) { - Log.severe(ix); - return null; - } - if((delay != null) && delay.booleanValue()) { - try { Thread.sleep(25); } catch (InterruptedException ix) {} } } /* If cancelled due to world unload return nothing */ From de510108a2193966013f0dafcb1598e726ab8326 Mon Sep 17 00:00:00 2001 From: mastermc05 <63639746+mastermc05@users.noreply.github.com> Date: Wed, 30 Mar 2022 15:39:58 +0300 Subject: [PATCH 2/7] Fix spaces * fix 1.16.2 spaces * fix 1.16.4 spaces * fix 1.16 * fix 1.16.0 x2 * fix 1.17 * fix 1.18.2 * fix 1.18.2 map cache * fix 1.18.2 map cache p2 * fix 1.18 * fix 1.16.3 --- .../BukkitVersionHelperSpigot116_2.java | 8 +- .../BukkitVersionHelperSpigot116_3.java | 22 ++--- .../BukkitVersionHelperSpigot116_4.java | 18 ++-- .../v116/BukkitVersionHelperSpigot116.java | 14 +-- .../v117/BukkitVersionHelperSpigot117.java | 16 ++-- .../BukkitVersionHelperSpigot118_2.java | 30 +++---- .../helper/v118_2/MapChunkCache118_2.java | 87 +++++++++---------- .../v118/BukkitVersionHelperSpigot118.java | 17 ++-- 8 files changed, 105 insertions(+), 107 deletions(-) diff --git a/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java b/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java index 1b4fa1e9..c0dcef62 100644 --- a/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java +++ b/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java @@ -37,14 +37,14 @@ import net.minecraft.server.v1_16_R2.MinecraftServer; * Helper for isolation of bukkit version specific issues */ public class BukkitVersionHelperSpigot116_2 extends BukkitVersionHelperGeneric { - private final boolean unsafeAsync; - private Field watercolorfield; + private final boolean unsafeAsync; + private Field watercolorfield; public BukkitVersionHelperSpigot116_2() { Class biomefog = getNMSClass("net.minecraft.server.BiomeFog"); watercolorfield = getPrivateField(biomefog, new String[] { "c" }, int.class); - this.unsafeAsync = true; - } + this.unsafeAsync = true; + } /** * Get block short name list diff --git a/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/BukkitVersionHelperSpigot116_3.java b/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/BukkitVersionHelperSpigot116_3.java index 16cd5805..531503e5 100644 --- a/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/BukkitVersionHelperSpigot116_3.java +++ b/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/BukkitVersionHelperSpigot116_3.java @@ -37,14 +37,14 @@ import net.minecraft.server.v1_16_R2.BlockPosition; * Helper for isolation of bukkit version specific issues */ public class BukkitVersionHelperSpigot116_3 extends BukkitVersionHelperGeneric { - private final boolean unsafeAsync; - private Field watercolorfield; + private final boolean unsafeAsync; + private Field watercolorfield; public BukkitVersionHelperSpigot116_3() { - Class biomefog = getNMSClass("net.minecraft.server.BiomeFog"); - watercolorfield = getPrivateField(biomefog, new String[] { "c" }, int.class); - this.unsafeAsync = true; - } + Class biomefog = getNMSClass("net.minecraft.server.BiomeFog"); + watercolorfield = getPrivateField(biomefog, new String[] { "c" }, int.class); + this.unsafeAsync = true; + } /** * Get block short name list @@ -72,12 +72,12 @@ public class BukkitVersionHelperSpigot116_3 extends BukkitVersionHelperGeneric { private Object[] biomelist; - @Override - public boolean isUnsafeAsync() { - return unsafeAsync; - } + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } - /** + /** * Get list of defined biomebase objects */ @Override diff --git a/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/BukkitVersionHelperSpigot116_4.java b/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/BukkitVersionHelperSpigot116_4.java index b0243d8f..26b87b2f 100644 --- a/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/BukkitVersionHelperSpigot116_4.java +++ b/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/BukkitVersionHelperSpigot116_4.java @@ -26,14 +26,14 @@ import java.util.List; * Helper for isolation of bukkit version specific issues */ public class BukkitVersionHelperSpigot116_4 extends BukkitVersionHelperGeneric { - private final boolean unsafeAsync; - private Field watercolorfield; + private final boolean unsafeAsync; + private Field watercolorfield; public BukkitVersionHelperSpigot116_4() { Class biomefog = getNMSClass("net.minecraft.server.BiomeFog"); watercolorfield = getPrivateField(biomefog, new String[] { "c" }, int.class); - this.unsafeAsync = true; - } + this.unsafeAsync = true; + } /** * Get block short name list @@ -61,12 +61,12 @@ public class BukkitVersionHelperSpigot116_4 extends BukkitVersionHelperGeneric { private Object[] biomelist; - @Override - public boolean isUnsafeAsync() { - return unsafeAsync; - } + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } - /** + /** * Get list of defined biomebase objects */ @Override diff --git a/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/BukkitVersionHelperSpigot116.java b/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/BukkitVersionHelperSpigot116.java index 9646e6cd..fb9f2a10 100644 --- a/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/BukkitVersionHelperSpigot116.java +++ b/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/BukkitVersionHelperSpigot116.java @@ -42,8 +42,8 @@ public class BukkitVersionHelperSpigot116 extends BukkitVersionHelperGeneric { public BukkitVersionHelperSpigot116() { Class biomefog = getNMSClass("net.minecraft.server.BiomeFog"); watercolorfield = getPrivateField(biomefog, new String[] { "c" }, int.class); - this.unsafeAsync = true; - } + this.unsafeAsync = true; + } /** * Get block short name list @@ -62,12 +62,12 @@ public class BukkitVersionHelperSpigot116 extends BukkitVersionHelperGeneric { private Object[] biomelist; - @Override - public boolean isUnsafeAsync() { - return unsafeAsync; - } + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } - /** + /** * Get list of defined biomebase objects */ @Override diff --git a/bukkit-helper-117/src/main/java/org/dynmap/bukkit/helper/v117/BukkitVersionHelperSpigot117.java b/bukkit-helper-117/src/main/java/org/dynmap/bukkit/helper/v117/BukkitVersionHelperSpigot117.java index e56fad95..f5a9b076 100644 --- a/bukkit-helper-117/src/main/java/org/dynmap/bukkit/helper/v117/BukkitVersionHelperSpigot117.java +++ b/bukkit-helper-117/src/main/java/org/dynmap/bukkit/helper/v117/BukkitVersionHelperSpigot117.java @@ -59,18 +59,18 @@ import java.util.Map; * Helper for isolation of bukkit version specific issues */ public class BukkitVersionHelperSpigot117 extends BukkitVersionHelper { - private final boolean unsafeAsync; + private final boolean unsafeAsync; - public BukkitVersionHelperSpigot117() { - this.unsafeAsync = true; + public BukkitVersionHelperSpigot117() { + this.unsafeAsync = true; } - @Override - public boolean isUnsafeAsync() { - return unsafeAsync; - } + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } - /** + /** * Get block short name list */ @Override diff --git a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/BukkitVersionHelperSpigot118_2.java b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/BukkitVersionHelperSpigot118_2.java index 9d40746e..fed30017 100644 --- a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/BukkitVersionHelperSpigot118_2.java +++ b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/BukkitVersionHelperSpigot118_2.java @@ -64,25 +64,25 @@ import java.util.Set; * Helper for isolation of bukkit version specific issues */ public class BukkitVersionHelperSpigot118_2 extends BukkitVersionHelper { - private final boolean unsafeAsync; + private final boolean unsafeAsync; public BukkitVersionHelperSpigot118_2() { - boolean unsafeAsync1; - try { - Class.forName("com.destroystokyo.paper.io.PaperFileIOThread"); - unsafeAsync1 = false; - } catch (ClassNotFoundException e) { - unsafeAsync1 = true; - } - this.unsafeAsync = unsafeAsync1; - } + boolean unsafeAsync1; + try { + Class.forName("com.destroystokyo.paper.io.PaperFileIOThread"); + unsafeAsync1 = false; + } catch (ClassNotFoundException e) { + unsafeAsync1 = true; + } + this.unsafeAsync = unsafeAsync1; + } - @Override - public boolean isUnsafeAsync() { - return unsafeAsync; - } + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } - /** + /** * Get block short name list */ @Override diff --git a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java index ab135e87..c3f0ac45 100644 --- a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java +++ b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java @@ -25,57 +25,56 @@ import java.util.concurrent.CompletableFuture; * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread */ public class MapChunkCache118_2 extends GenericMapChunkCache { - private final AsyncChunkProvider118_2 provider = BukkitVersionHelper.helper.isUnsafeAsync() ? null : new AsyncChunkProvider118_2(); - private World w; - /** - * Construct empty cache - */ - public MapChunkCache118_2(GenericChunkCache cc) { - super(cc); - } - - // Load generic chunk from existing and already loaded chunk - protected GenericChunk getLoadedChunk(DynmapChunk chunk) { - CraftWorld cw = (CraftWorld) w; - NBTTagCompound nbt = null; - GenericChunk gc = null; - if (cw.isChunkLoaded(chunk.x, chunk.z)) { - Chunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z); //already safe async on vanilla - if ((c != null) && c.o) { // c.loaded - if (provider == null) { //idk why, but paper uses this only sync, so I won't be smarter - nbt = ChunkRegionLoader.a(cw.getHandle(), c); - } else { - nbt = CompletableFuture.supplyAsync(() -> ChunkRegionLoader.a(cw.getHandle(), c), ((CraftServer) Bukkit.getServer()).getServer()).join(); - } - } - if (nbt != null) { - gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); - } + private final AsyncChunkProvider118_2 provider = BukkitVersionHelper.helper.isUnsafeAsync() ? null : new AsyncChunkProvider118_2(); + private World w; + /** + * Construct empty cache + */ + public MapChunkCache118_2(GenericChunkCache cc) { + super(cc); } - return gc; - } - // Load generic chunk from unloaded chunk - protected GenericChunk loadChunk(DynmapChunk chunk) { + + // Load generic chunk from existing and already loaded chunk + protected GenericChunk getLoadedChunk(DynmapChunk chunk) { + CraftWorld cw = (CraftWorld) w; + NBTTagCompound nbt = null; + GenericChunk gc = null; + if (cw.isChunkLoaded(chunk.x, chunk.z)) { + Chunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z); //already safe async on vanilla + if ((c != null) && c.o) { // c.loaded + if (provider == null) { //idk why, but paper uses this only sync, so I won't be smarter + nbt = ChunkRegionLoader.a(cw.getHandle(), c); + } else { + nbt = CompletableFuture.supplyAsync(() -> ChunkRegionLoader.a(cw.getHandle(), c), ((CraftServer) Bukkit.getServer()).getServer()).join(); + } + } + if (nbt != null) { + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); + } + } + return gc; + } + // Load generic chunk from unloaded chunk + protected GenericChunk loadChunk(DynmapChunk chunk) { CraftWorld cw = (CraftWorld) w; NBTTagCompound nbt = null; ChunkCoordIntPair cc = new ChunkCoordIntPair(chunk.x, chunk.z); GenericChunk gc = null; try { - if (provider == null){ - nbt = cw.getHandle().k().a.f(cc); // playerChunkMap - } else { - nbt = provider.getChunk(cw.getHandle(),chunk.x, chunk.z); - } - } catch (IOException | InvocationTargetException | IllegalAccessException | NoSuchFieldException ignored) { - } + if (provider == null){ + nbt = cw.getHandle().k().a.f(cc); // playerChunkMap + } else { + nbt = provider.getChunk(cw.getHandle(),chunk.x, chunk.z); + } + } catch (IOException | InvocationTargetException | IllegalAccessException | NoSuchFieldException ignored) {} if (nbt != null) { - gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); } - return gc; - } + return gc; + } - public void setChunks(BukkitWorld dw, List chunks) { - this.w = dw.getWorld(); - super.setChunks(dw, chunks); - } + public void setChunks(BukkitWorld dw, List chunks) { + this.w = dw.getWorld(); + super.setChunks(dw, chunks); + } } diff --git a/bukkit-helper-118/src/main/java/org/dynmap/bukkit/helper/v118/BukkitVersionHelperSpigot118.java b/bukkit-helper-118/src/main/java/org/dynmap/bukkit/helper/v118/BukkitVersionHelperSpigot118.java index dd9aa5c3..fbacfa6d 100644 --- a/bukkit-helper-118/src/main/java/org/dynmap/bukkit/helper/v118/BukkitVersionHelperSpigot118.java +++ b/bukkit-helper-118/src/main/java/org/dynmap/bukkit/helper/v118/BukkitVersionHelperSpigot118.java @@ -64,19 +64,18 @@ import java.util.Set; * Helper for isolation of bukkit version specific issues */ public class BukkitVersionHelperSpigot118 extends BukkitVersionHelper { + private final boolean unsafeAsync; - private final boolean unsafeAsync; - - public BukkitVersionHelperSpigot118() { - this.unsafeAsync = true; + public BukkitVersionHelperSpigot118() { + this.unsafeAsync = true; } - @Override - public boolean isUnsafeAsync() { - return unsafeAsync; - } + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } - /** + /** * Get block short name list */ @Override From c5d113b77a6ca654aa6ccc01eeda592808aaee44 Mon Sep 17 00:00:00 2001 From: mastermc05 <63639746+mastermc05@users.noreply.github.com> Date: Wed, 30 Mar 2022 15:43:55 +0300 Subject: [PATCH 3/7] fix missed 1.16.2 --- .../helper/v116_2/BukkitVersionHelperSpigot116_2.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java b/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java index c0dcef62..bd00dd00 100644 --- a/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java +++ b/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java @@ -72,12 +72,12 @@ public class BukkitVersionHelperSpigot116_2 extends BukkitVersionHelperGeneric { private Object[] biomelist; - @Override - public boolean isUnsafeAsync() { - return unsafeAsync; - } + @Override + public boolean isUnsafeAsync() { + return unsafeAsync; + } - /** + /** * Get list of defined biomebase objects */ @Override From 4a97550b63e4fa4b3f23c037ac98efa6e675078e Mon Sep 17 00:00:00 2001 From: mastermc05 Date: Wed, 30 Mar 2022 19:37:29 +0300 Subject: [PATCH 4/7] Parallel process and load plans --- .../common/chunk/GenericMapChunkCache.java | 154 +++++++++++++++++- .../v118_2/AsyncChunkProvider118_2.java | 15 +- .../helper/v118_2/MapChunkCache118_2.java | 62 ++++--- .../java/org/dynmap/bukkit/DynmapPlugin.java | 21 +-- 4 files changed, 212 insertions(+), 40 deletions(-) diff --git a/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java b/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java index 90fa625d..07c121de 100644 --- a/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java +++ b/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java @@ -1,8 +1,9 @@ package org.dynmap.common.chunk; -import java.util.ArrayList; -import java.util.List; -import java.util.ListIterator; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; import org.dynmap.DynmapChunk; import org.dynmap.DynmapCore; @@ -697,6 +698,14 @@ public abstract class GenericMapChunkCache extends MapChunkCache { protected abstract GenericChunk getLoadedChunk(DynmapChunk ch); // Load generic chunk from unloaded chunk protected abstract GenericChunk loadChunk(DynmapChunk ch); + // Load generic chunk from existing and already loaded chunk + protected Supplier getLoadedChunkAsync(DynmapChunk ch) { + throw new RuntimeException("Not implemeted"); + } + // Load generic chunks from unloaded chunk async + protected Supplier loadChunkAsync(DynmapChunk ch){ + throw new RuntimeException("Not implemeted"); + } /** * Read NBT data from loaded chunks - needs to be called from server/world @@ -753,11 +762,75 @@ public abstract class GenericMapChunkCache extends MapChunkCache { } return cnt; } + public void getLoadedChunksAsync() { + class SimplePair{ //simple pair of the supplier that finishes read async, and a consumer that also finish his work async + final Supplier supplier; + final BiConsumer consumer; + + SimplePair(Supplier supplier, BiConsumer consumer) { + this.supplier = supplier; + this.consumer = consumer; + } + } + if (!dw.isLoaded()) { + isempty = true; + unloadChunks(); + return; + } + List lastApply = new ArrayList<>(); + for (DynmapChunk dynmapChunk : chunks) { + long startTime = System.nanoTime(); + int chunkIndex = (dynmapChunk.x - x_min) + (dynmapChunk.z - z_min) * x_dim; + if (snaparray[chunkIndex] != null) + continue; // Skip if already processed + + boolean vis = isChunkVisible(dynmapChunk); + + /* Check if cached chunk snapshot found */ + if (tryChunkCache(dynmapChunk, vis)) { + endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); + } + // If chunk is loaded and not being unloaded, we're grabbing its NBT data + else { + // Get generic chunk from already loaded chunk, if we can + Supplier supplier = getLoadedChunkAsync(dynmapChunk); + long startPause = System.nanoTime(); + BiConsumer consumer = (ss, reloadTime) -> { + if (ss == null) return; + long pause = reloadTime - startPause; + if (vis) { // If visible + prepChunkSnapshot(dynmapChunk, ss); + } else { + if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) { + ss = getStone(); + } else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) { + ss = getOcean(); + } else { + ss = getEmpty(); + } + } + snaparray[chunkIndex] = ss; + endChunkLoad(startTime - pause, ChunkStats.LOADED_CHUNKS); + + }; + lastApply.add(new SimplePair(supplier, consumer)); + } + } + //impact on the main thread should be minimal, so we plan and finish the work after main thread finished it's part + lastApply.forEach(simplePair -> { + long reloadWork = System.nanoTime(); + simplePair.consumer.accept(simplePair.supplier.get(), reloadWork); + }); + } @Override public int loadChunks(int max_to_load) { return getLoadedChunks() + readChunks(max_to_load); + } + public void loadChunksAsync() { + getLoadedChunksAsync(); + readChunksAsync(); } public int readChunks(int max_to_load) { @@ -840,6 +913,81 @@ public abstract class GenericMapChunkCache extends MapChunkCache { return cnt; } + public void readChunksAsync() { + if (!dw.isLoaded()) { + isempty = true; + unloadChunks(); + return; + } + + List chunks; + if (iterator == null) { + iterator = Collections.emptyListIterator(); + chunks = new ArrayList<>(this.chunks); + } else { + chunks = new ArrayList<>(); + iterator.forEachRemaining(chunks::add); + } +// DynmapCore.setIgnoreChunkLoads(true); + + List cached = new ArrayList<>(); + List,DynmapChunk>> notCached = new ArrayList<>(); + + iterator.forEachRemaining(chunks::add); + chunks.stream() + .filter(chunk -> snaparray[(chunk.x - x_min) + (chunk.z - z_min) * x_dim] == null) + .forEach(chunk -> { + if (cache.getSnapshot(dw.getName(),chunk.x, chunk.z) == null) { + notCached.add(new AbstractMap.SimpleEntry<>(loadChunkAsync(chunk),chunk)); + } else { + cached.add(chunk); + } + }); + + cached.forEach(chunk -> { + long startTime = System.nanoTime(); + tryChunkCache(chunk, isChunkVisible(chunk)); + endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); + }); + notCached.forEach(chunkSupplier -> { + long startTime = System.nanoTime(); + GenericChunk chunk = chunkSupplier.getKey().get(); + DynmapChunk dynmapChunk = chunkSupplier.getValue(); + if (chunk != null) { + // If hidden + if (isChunkVisible(dynmapChunk)) { + // Prep snapshot + prepChunkSnapshot(dynmapChunk, chunk); + } else { + if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) { + chunk = getStone(); + } else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) { + chunk = getOcean(); + } else { + chunk = getEmpty(); + } + } + snaparray[(dynmapChunk.x - x_min) + (dynmapChunk.z - z_min) * x_dim] = chunk; + endChunkLoad(startTime, ChunkStats.UNLOADED_CHUNKS); + } else { + endChunkLoad(startTime, ChunkStats.UNGENERATED_CHUNKS); + } + }); + +// DynmapCore.setIgnoreChunkLoads(false); + + isempty = true; + /* Fill missing chunks with empty dummy chunk */ + for (int i = 0; i < snaparray.length; i++) { + if (snaparray[i] == null) { + snaparray[i] = getEmpty(); + } else if (!snaparray[i].isEmpty) { + isempty = false; + } + } + + } + /** * Test if done loading */ diff --git a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java index 9bbdd6b5..59d48842 100644 --- a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java +++ b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java @@ -45,12 +45,17 @@ public class AsyncChunkProvider118_2 { throw new RuntimeException(e); } } - public NBTTagCompound getChunk(WorldServer world, int x, int y) throws InvocationTargetException, IllegalAccessException, NoSuchFieldException { + public CompletableFuture getChunk(WorldServer world, int x, int y) throws InvocationTargetException, IllegalAccessException { CompletableFuture future = new CompletableFuture<>(); getChunk.invoke(ioThread,world,x,y,5,(Consumer) future::complete, false, true, true); - Object resultFuture = future.join(); - if (resultFuture == null) return null; - NBTTagCompound result = (NBTTagCompound) resultFuture.getClass().getField("chunkData").get(resultFuture); - return ifFailed.test(result) ? null : result; + return future.thenApply((resultFuture) -> { + if (resultFuture == null) return null; + try { + return (NBTTagCompound) resultFuture.getClass().getField("chunkData").get(resultFuture); + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + return null; + }); } } diff --git a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java index c3f0ac45..5d0f1b0b 100644 --- a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java +++ b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; /** * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread @@ -36,23 +37,43 @@ public class MapChunkCache118_2 extends GenericMapChunkCache { // Load generic chunk from existing and already loaded chunk protected GenericChunk getLoadedChunk(DynmapChunk chunk) { - CraftWorld cw = (CraftWorld) w; - NBTTagCompound nbt = null; - GenericChunk gc = null; - if (cw.isChunkLoaded(chunk.x, chunk.z)) { - Chunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z); //already safe async on vanilla - if ((c != null) && c.o) { // c.loaded - if (provider == null) { //idk why, but paper uses this only sync, so I won't be smarter - nbt = ChunkRegionLoader.a(cw.getHandle(), c); - } else { - nbt = CompletableFuture.supplyAsync(() -> ChunkRegionLoader.a(cw.getHandle(), c), ((CraftServer) Bukkit.getServer()).getServer()).join(); - } - } - if (nbt != null) { - gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); - } + return getLoadedChunk(chunk, false).get(); + } + @Override + protected Supplier getLoadedChunkAsync(DynmapChunk ch) { + return getLoadedChunk(ch, true); + } + + @Override + protected Supplier loadChunkAsync(DynmapChunk chunk){ + try { + CompletableFuture nbt = provider.getChunk(((CraftWorld) w).getHandle(), chunk.x, chunk.z); + return () -> { + NBTTagCompound compound = nbt.join(); + return compound == null ? null : parseChunkFromNBT(new NBT.NBTCompound(compound)); + }; + } catch (InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); } - return gc; + return () -> null; + } + + private Supplier getLoadedChunk(DynmapChunk chunk, boolean async) { + CraftWorld cw = (CraftWorld) w; + if (!cw.isChunkLoaded(chunk.x, chunk.z)) return () -> null; + Chunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z); //already safe async on vanilla + if ((c == null) || c.o) return () -> null; // c.loaded + if (async) { //idk why, but paper uses this only sync, so I won't be smarter + CompletableFuture nbt = CompletableFuture.supplyAsync(() -> ChunkRegionLoader.a(cw.getHandle(), c), ((CraftServer) Bukkit.getServer()).getServer()); + return () -> parseChunkFromNBT(new NBT.NBTCompound(nbt.join())); + } else { + NBTTagCompound nbt = ChunkRegionLoader.a(cw.getHandle(), c); + GenericChunk genericChunk; + if (nbt != null) genericChunk = parseChunkFromNBT(new NBT.NBTCompound(nbt)); + else genericChunk = null; + return () -> genericChunk; + } + } // Load generic chunk from unloaded chunk protected GenericChunk loadChunk(DynmapChunk chunk) { @@ -61,12 +82,9 @@ public class MapChunkCache118_2 extends GenericMapChunkCache { ChunkCoordIntPair cc = new ChunkCoordIntPair(chunk.x, chunk.z); GenericChunk gc = null; try { - if (provider == null){ - nbt = cw.getHandle().k().a.f(cc); // playerChunkMap - } else { - nbt = provider.getChunk(cw.getHandle(),chunk.x, chunk.z); - } - } catch (IOException | InvocationTargetException | IllegalAccessException | NoSuchFieldException ignored) {} + nbt = cw.getHandle().k().a.f(cc); // playerChunkMap + } catch (IOException iox) { + } if (nbt != null) { gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); } diff --git a/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java b/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java index 75b203ca..1b16ffaa 100644 --- a/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java +++ b/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java @@ -104,6 +104,7 @@ import org.dynmap.common.DynmapPlayer; import org.dynmap.common.DynmapServerInterface; import org.dynmap.common.chunk.GenericChunkCache; import org.dynmap.common.DynmapListenerManager.EventType; +import org.dynmap.common.chunk.GenericMapChunkCache; import org.dynmap.hdmap.HDMap; import org.dynmap.markers.MarkerAPI; import org.dynmap.modsupport.ModSupportImpl; @@ -562,17 +563,17 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { } } } else { - try { - synchronized (lock) { - if (prev_tick != cur_tick) { - prev_tick = cur_tick; - cur_tick_starttime = System.nanoTime(); - } - cc.loadChunks(Integer.MAX_VALUE); - } - } catch (Exception e) { - e.printStackTrace(); +// synchronized (lock) { + if (prev_tick != cur_tick) { + prev_tick = cur_tick; + cur_tick_starttime = System.nanoTime(); } + if (cc instanceof GenericMapChunkCache) { + ((GenericMapChunkCache) cc).loadChunksAsync(); + } else { + cc.loadChunks(Integer.MAX_VALUE); + } +// } } } /* If cancelled due to world unload return nothing */ From 790f1f4966e6772bfcc3bf1e03997029e81c3ded Mon Sep 17 00:00:00 2001 From: mastermc05 Date: Thu, 31 Mar 2022 15:04:36 +0300 Subject: [PATCH 5/7] Readd ignore chunk loads --- .../common/chunk/GenericMapChunkCache.java | 120 ++++++++++-------- .../v118_2/AsyncChunkProvider118_2.java | 5 +- .../helper/v118_2/MapChunkCache118_2.java | 2 +- 3 files changed, 67 insertions(+), 60 deletions(-) diff --git a/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java b/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java index 07c121de..553a57bf 100644 --- a/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java +++ b/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java @@ -1,6 +1,7 @@ package org.dynmap.common.chunk; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; @@ -38,6 +39,7 @@ public abstract class GenericMapChunkCache extends MapChunkCache { private int snapcnt; private GenericChunk[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */ private boolean[][] isSectionNotEmpty; /* Indexed by snapshot index, then by section index */ + private AtomicInteger loadingChunks = new AtomicInteger(0); //the amount of threads loading threads at this moment, used by async loading private static final BlockStep unstep[] = { BlockStep.X_MINUS, BlockStep.Y_MINUS, BlockStep.Z_MINUS, BlockStep.X_PLUS, BlockStep.Y_PLUS, BlockStep.Z_PLUS }; @@ -928,64 +930,70 @@ public abstract class GenericMapChunkCache extends MapChunkCache { chunks = new ArrayList<>(); iterator.forEachRemaining(chunks::add); } -// DynmapCore.setIgnoreChunkLoads(true); - - List cached = new ArrayList<>(); - List,DynmapChunk>> notCached = new ArrayList<>(); - - iterator.forEachRemaining(chunks::add); - chunks.stream() - .filter(chunk -> snaparray[(chunk.x - x_min) + (chunk.z - z_min) * x_dim] == null) - .forEach(chunk -> { - if (cache.getSnapshot(dw.getName(),chunk.x, chunk.z) == null) { - notCached.add(new AbstractMap.SimpleEntry<>(loadChunkAsync(chunk),chunk)); - } else { - cached.add(chunk); - } - }); - - cached.forEach(chunk -> { - long startTime = System.nanoTime(); - tryChunkCache(chunk, isChunkVisible(chunk)); - endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); - }); - notCached.forEach(chunkSupplier -> { - long startTime = System.nanoTime(); - GenericChunk chunk = chunkSupplier.getKey().get(); - DynmapChunk dynmapChunk = chunkSupplier.getValue(); - if (chunk != null) { - // If hidden - if (isChunkVisible(dynmapChunk)) { - // Prep snapshot - prepChunkSnapshot(dynmapChunk, chunk); - } else { - if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) { - chunk = getStone(); - } else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) { - chunk = getOcean(); - } else { - chunk = getEmpty(); - } - } - snaparray[(dynmapChunk.x - x_min) + (dynmapChunk.z - z_min) * x_dim] = chunk; - endChunkLoad(startTime, ChunkStats.UNLOADED_CHUNKS); - } else { - endChunkLoad(startTime, ChunkStats.UNGENERATED_CHUNKS); - } - }); - -// DynmapCore.setIgnoreChunkLoads(false); - - isempty = true; - /* Fill missing chunks with empty dummy chunk */ - for (int i = 0; i < snaparray.length; i++) { - if (snaparray[i] == null) { - snaparray[i] = getEmpty(); - } else if (!snaparray[i].isEmpty) { - isempty = false; - } + //if before increent was 0, means that we are the first, so we need to set this + if (loadingChunks.getAndIncrement() == 0) { + DynmapCore.setIgnoreChunkLoads(true); } + try { + List cached = new ArrayList<>(); + List, DynmapChunk>> notCached = new ArrayList<>(); + + iterator.forEachRemaining(chunks::add); + chunks.stream() + .filter(chunk -> snaparray[(chunk.x - x_min) + (chunk.z - z_min) * x_dim] == null) + .forEach(chunk -> { + if (cache.getSnapshot(dw.getName(), chunk.x, chunk.z) == null) { + notCached.add(new AbstractMap.SimpleEntry<>(loadChunkAsync(chunk), chunk)); + } else { + cached.add(chunk); + } + }); + + cached.forEach(chunk -> { + long startTime = System.nanoTime(); + tryChunkCache(chunk, isChunkVisible(chunk)); + endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); + }); + notCached.forEach(chunkSupplier -> { + long startTime = System.nanoTime(); + GenericChunk chunk = chunkSupplier.getKey().get(); + DynmapChunk dynmapChunk = chunkSupplier.getValue(); + if (chunk != null) { + // If hidden + if (isChunkVisible(dynmapChunk)) { + // Prep snapshot + prepChunkSnapshot(dynmapChunk, chunk); + } else { + if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) { + chunk = getStone(); + } else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) { + chunk = getOcean(); + } else { + chunk = getEmpty(); + } + } + snaparray[(dynmapChunk.x - x_min) + (dynmapChunk.z - z_min) * x_dim] = chunk; + endChunkLoad(startTime, ChunkStats.UNLOADED_CHUNKS); + } else { + endChunkLoad(startTime, ChunkStats.UNGENERATED_CHUNKS); + } + }); + + isempty = true; + /* Fill missing chunks with empty dummy chunk */ + for (int i = 0; i < snaparray.length; i++) { + if (snaparray[i] == null) { + snaparray[i] = getEmpty(); + } else if (!snaparray[i].isEmpty) { + isempty = false; + } + } + } finally { + if (loadingChunks.decrementAndGet() == 0) { + DynmapCore.setIgnoreChunkLoads(false); + } + } } /** diff --git a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java index 59d48842..ef1df618 100644 --- a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java +++ b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java @@ -2,8 +2,6 @@ package org.dynmap.bukkit.helper.v118_2; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.server.level.WorldServer; -import net.minecraft.world.level.World; -import net.minecraft.world.level.chunk.Chunk; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -51,7 +49,8 @@ public class AsyncChunkProvider118_2 { return future.thenApply((resultFuture) -> { if (resultFuture == null) return null; try { - return (NBTTagCompound) resultFuture.getClass().getField("chunkData").get(resultFuture); + NBTTagCompound compound = (NBTTagCompound) resultFuture.getClass().getField("chunkData").get(resultFuture); + return ifFailed.test(compound) ? null : compound; } catch (IllegalAccessException | NoSuchFieldException e) { e.printStackTrace(); } diff --git a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java index 5d0f1b0b..236fe894 100644 --- a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java +++ b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java @@ -54,8 +54,8 @@ public class MapChunkCache118_2 extends GenericMapChunkCache { }; } catch (InvocationTargetException | IllegalAccessException e) { e.printStackTrace(); + return () -> loadChunk(chunk); } - return () -> null; } private Supplier getLoadedChunk(DynmapChunk chunk, boolean async) { From da05fc467571b36ea733196278df1717edd871be Mon Sep 17 00:00:00 2001 From: mastermc05 Date: Thu, 31 Mar 2022 16:18:02 +0300 Subject: [PATCH 6/7] Clean and finish --- .../common/chunk/GenericMapChunkCache.java | 33 ++++++++++++++----- .../java/org/dynmap/bukkit/DynmapPlugin.java | 2 -- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java b/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java index 553a57bf..e44f7f14 100644 --- a/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java +++ b/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java @@ -700,13 +700,13 @@ public abstract class GenericMapChunkCache extends MapChunkCache { protected abstract GenericChunk getLoadedChunk(DynmapChunk ch); // Load generic chunk from unloaded chunk protected abstract GenericChunk loadChunk(DynmapChunk ch); - // Load generic chunk from existing and already loaded chunk + // Load generic chunk from existing and already loaded chunk async protected Supplier getLoadedChunkAsync(DynmapChunk ch) { - throw new RuntimeException("Not implemeted"); + throw new IllegalStateException("Not implemeted"); } // Load generic chunks from unloaded chunk async protected Supplier loadChunkAsync(DynmapChunk ch){ - throw new RuntimeException("Not implemeted"); + throw new IllegalStateException("Not implemeted"); } /** @@ -764,8 +764,13 @@ public abstract class GenericMapChunkCache extends MapChunkCache { } return cnt; } + + /** + * Read NBT data from loaded chunks - do not needs to be called from server/world + * Will throw {@link IllegalStateException} if not supporting + */ public void getLoadedChunksAsync() { - class SimplePair{ //simple pair of the supplier that finishes read async, and a consumer that also finish his work async + class SimplePair { //simple pair of the supplier that finishes read async, and a consumer that also finish his work async final Supplier supplier; final BiConsumer consumer; @@ -830,6 +835,9 @@ public abstract class GenericMapChunkCache extends MapChunkCache { return getLoadedChunks() + readChunks(max_to_load); } + /** + * Prepare the chunks async + */ public void loadChunksAsync() { getLoadedChunksAsync(); readChunksAsync(); @@ -916,6 +924,15 @@ public abstract class GenericMapChunkCache extends MapChunkCache { } public void readChunksAsync() { + class SimplePair { + private final Supplier supplier; + private final DynmapChunk chunk; + + SimplePair(DynmapChunk chunk) { + this.chunk = chunk; + this.supplier = loadChunkAsync(chunk); + } + } if (!dw.isLoaded()) { isempty = true; unloadChunks(); @@ -937,14 +954,14 @@ public abstract class GenericMapChunkCache extends MapChunkCache { try { List cached = new ArrayList<>(); - List, DynmapChunk>> notCached = new ArrayList<>(); + List notCached = new ArrayList<>(); iterator.forEachRemaining(chunks::add); chunks.stream() .filter(chunk -> snaparray[(chunk.x - x_min) + (chunk.z - z_min) * x_dim] == null) .forEach(chunk -> { if (cache.getSnapshot(dw.getName(), chunk.x, chunk.z) == null) { - notCached.add(new AbstractMap.SimpleEntry<>(loadChunkAsync(chunk), chunk)); + notCached.add(new SimplePair(chunk)); } else { cached.add(chunk); } @@ -957,8 +974,8 @@ public abstract class GenericMapChunkCache extends MapChunkCache { }); notCached.forEach(chunkSupplier -> { long startTime = System.nanoTime(); - GenericChunk chunk = chunkSupplier.getKey().get(); - DynmapChunk dynmapChunk = chunkSupplier.getValue(); + GenericChunk chunk = chunkSupplier.supplier.get(); + DynmapChunk dynmapChunk = chunkSupplier.chunk; if (chunk != null) { // If hidden if (isChunkVisible(dynmapChunk)) { diff --git a/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java b/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java index 1b16ffaa..9ac97138 100644 --- a/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java +++ b/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java @@ -563,7 +563,6 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { } } } else { -// synchronized (lock) { if (prev_tick != cur_tick) { prev_tick = cur_tick; cur_tick_starttime = System.nanoTime(); @@ -573,7 +572,6 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { } else { cc.loadChunks(Integer.MAX_VALUE); } -// } } } /* If cancelled due to world unload return nothing */ From d0a791b634d1e9993d793d3f2120e7b76ffb1601 Mon Sep 17 00:00:00 2001 From: mastermc05 Date: Fri, 1 Apr 2022 15:16:57 +0300 Subject: [PATCH 7/7] Clean and finish x2 --- .../dynmap/common/chunk/GenericMapChunkCache.java | 4 ++-- .../helper/v118_2/AsyncChunkProvider118_2.java | 8 ++++---- .../bukkit/helper/v118_2/MapChunkCache118_2.java | 14 ++++++++------ .../main/java/org/dynmap/bukkit/DynmapPlugin.java | 1 - 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java b/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java index e44f7f14..2cfc7ce4 100644 --- a/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java +++ b/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java @@ -39,7 +39,7 @@ public abstract class GenericMapChunkCache extends MapChunkCache { private int snapcnt; private GenericChunk[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */ private boolean[][] isSectionNotEmpty; /* Indexed by snapshot index, then by section index */ - private AtomicInteger loadingChunks = new AtomicInteger(0); //the amount of threads loading threads at this moment, used by async loading + private AtomicInteger loadingChunks = new AtomicInteger(0); //the amount of threads loading chunks at this moment, used by async loading private static final BlockStep unstep[] = { BlockStep.X_MINUS, BlockStep.Y_MINUS, BlockStep.Z_MINUS, BlockStep.X_PLUS, BlockStep.Y_PLUS, BlockStep.Z_PLUS }; @@ -924,7 +924,7 @@ public abstract class GenericMapChunkCache extends MapChunkCache { } public void readChunksAsync() { - class SimplePair { + class SimplePair { //pair of the chunk and the data which is readed async private final Supplier supplier; private final DynmapChunk chunk; diff --git a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java index ef1df618..9c21562d 100644 --- a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java +++ b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/AsyncChunkProvider118_2.java @@ -16,10 +16,10 @@ import java.util.function.Predicate; * Because paper libs need java 17 we can't interact with them directly */ public class AsyncChunkProvider118_2 { - private static final Thread ioThread; - private static final Method getChunk; - private static final Predicate ifFailed; - static { + private final Thread ioThread; + private final Method getChunk; + private final Predicate ifFailed; + AsyncChunkProvider118_2 () { try { Predicate ifFailed1 = null; Method getChunk1 = null; diff --git a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java index 236fe894..3971de10 100644 --- a/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java +++ b/bukkit-helper-118-2/src/main/java/org/dynmap/bukkit/helper/v118_2/MapChunkCache118_2.java @@ -26,7 +26,7 @@ import java.util.function.Supplier; * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread */ public class MapChunkCache118_2 extends GenericMapChunkCache { - private final AsyncChunkProvider118_2 provider = BukkitVersionHelper.helper.isUnsafeAsync() ? null : new AsyncChunkProvider118_2(); + private static final AsyncChunkProvider118_2 provider = BukkitVersionHelper.helper.isUnsafeAsync() ? null : new AsyncChunkProvider118_2(); private World w; /** * Construct empty cache @@ -52,9 +52,8 @@ public class MapChunkCache118_2 extends GenericMapChunkCache { NBTTagCompound compound = nbt.join(); return compound == null ? null : parseChunkFromNBT(new NBT.NBTCompound(compound)); }; - } catch (InvocationTargetException | IllegalAccessException e) { - e.printStackTrace(); - return () -> loadChunk(chunk); + } catch (InvocationTargetException | IllegalAccessException ignored) { + return () -> null; } } @@ -63,9 +62,12 @@ public class MapChunkCache118_2 extends GenericMapChunkCache { if (!cw.isChunkLoaded(chunk.x, chunk.z)) return () -> null; Chunk c = cw.getHandle().getChunkIfLoaded(chunk.x, chunk.z); //already safe async on vanilla if ((c == null) || c.o) return () -> null; // c.loaded - if (async) { //idk why, but paper uses this only sync, so I won't be smarter + if (async) { //the data of the chunk may change while we write, better to write it sync CompletableFuture nbt = CompletableFuture.supplyAsync(() -> ChunkRegionLoader.a(cw.getHandle(), c), ((CraftServer) Bukkit.getServer()).getServer()); - return () -> parseChunkFromNBT(new NBT.NBTCompound(nbt.join())); + return () -> { + NBTTagCompound compound = nbt.join(); + return compound == null ? null : parseChunkFromNBT(new NBT.NBTCompound(compound)); + }; } else { NBTTagCompound nbt = ChunkRegionLoader.a(cw.getHandle(), c); GenericChunk genericChunk; diff --git a/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java b/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java index 9ac97138..a426a840 100644 --- a/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java +++ b/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java @@ -482,7 +482,6 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { boolean rslt = permissions.hasOfflinePermission(player, perm); return rslt; } - private final Object[] lock = {}; /** * Render processor helper - used by code running on render threads to request chunk snapshot cache from server/sync thread */