diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java index fc3ce7370..39c2c59cd 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java @@ -30,6 +30,8 @@ import com.plotsquared.core.util.task.TaskTime; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.world.World; import io.papermc.lib.PaperLib; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.plugin.Plugin; @@ -41,6 +43,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -55,6 +58,8 @@ import java.util.function.Consumer; **/ public final class BukkitChunkCoordinator extends ChunkCoordinator { + private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + BukkitChunkCoordinator.class.getSimpleName()); + private final List progressSubscribers = new LinkedList<>(); private final Queue requestedChunks; @@ -70,6 +75,7 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { private final AtomicInteger expectedSize; private final AtomicInteger loadingChunks = new AtomicInteger(); private final boolean forceSync; + private final boolean shouldGen; private int batchSize; private PlotSquaredTask task; @@ -87,7 +93,8 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { @Assisted final @NonNull Consumer throwableConsumer, @Assisted("unloadAfter") final boolean unloadAfter, @Assisted final @NonNull Collection progressSubscribers, - @Assisted("forceSync") final boolean forceSync + @Assisted("forceSync") final boolean forceSync, + @Assisted("shouldGen") final boolean shouldGen ) { this.requestedChunks = new LinkedBlockingQueue<>(requestedChunks); this.availableChunks = new LinkedBlockingQueue<>(); @@ -103,6 +110,7 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { this.bukkitWorld = Bukkit.getWorld(world.getName()); this.progressSubscribers.addAll(progressSubscribers); this.forceSync = forceSync; + this.shouldGen = shouldGen; } @Override @@ -212,18 +220,22 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { * Requests a batch of chunks to be loaded */ private void requestBatch() { - BlockVector2 chunk; - for (int i = 0; i < this.batchSize && (chunk = this.requestedChunks.poll()) != null; i++) { + for (int i = 0; i < this.batchSize && this.requestedChunks.peek() != null; i++) { // This required PaperLib to be bumped to version 1.0.4 to mark the request as urgent + final BlockVector2 chunk = this.requestedChunks.poll(); loadingChunks.incrementAndGet(); PaperLib - .getChunkAtAsync(this.bukkitWorld, chunk.getX(), chunk.getZ(), true, true) + .getChunkAtAsync(this.bukkitWorld, chunk.getX(), chunk.getZ(), shouldGen, true) + .completeOnTimeout(null, 10L, TimeUnit.SECONDS) .whenComplete((chunkObject, throwable) -> { loadingChunks.decrementAndGet(); if (throwable != null) { - throwable.printStackTrace(); + LOGGER.error("Failed to load chunk {}", chunk, throwable); // We want one less because this couldn't be processed this.expectedSize.decrementAndGet(); + } else if (chunkObject == null) { + LOGGER.warn("Timed out awaiting chunk load {}", chunk); + this.requestedChunks.offer(chunk); } else if (PlotSquared.get().isMainThread(Thread.currentThread())) { this.processChunk(chunkObject); } else { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java index d923fe679..8c2bfa50f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java @@ -238,6 +238,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { .unloadAfter(isUnloadAfter()) .withProgressSubscribers(getProgressSubscribers()) .forceSync(isForceSync()) + .shouldGen(isShouldGen()) .build(); return super.enqueue(); } diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java b/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java index a2ea486d8..7b35f6f97 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java @@ -432,6 +432,7 @@ public class HybridUtils { if (!UPDATE) { Iterator iter = chunks.iterator(); QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(area.getWorldName())); + queue.setShouldGen(false); while (iter.hasNext()) { BlockVector2 chunk = iter.next(); iter.remove(); @@ -474,6 +475,7 @@ public class HybridUtils { Iterator iterator = chunks.iterator(); if (chunks.size() >= 32) { QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(area.getWorldName())); + queue.setShouldGen(false); for (int i = 0; i < 32; i++) { final BlockVector2 chunk = iterator.next(); iterator.remove(); @@ -487,6 +489,7 @@ public class HybridUtils { return null; } QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(area.getWorldName())); + queue.setShouldGen(false); while (!chunks.isEmpty()) { final BlockVector2 chunk = iterator.next(); iterator.remove(); @@ -502,7 +505,6 @@ public class HybridUtils { return; } } catch (Exception e) { - e.printStackTrace(); Iterator iterator = HybridUtils.regions.iterator(); BlockVector2 loc = iterator.next(); iterator.remove(); @@ -510,7 +512,8 @@ public class HybridUtils { "Error! Could not update '{}/region/r.{}.{}.mca' (Corrupt chunk?)", area.getWorldHash(), loc.getX(), - loc.getZ() + loc.getZ(), + e ); } TaskManager.runTaskLater(task, TaskTime.seconds(1L)); @@ -558,7 +561,7 @@ public class HybridUtils { try { plotworld.setupSchematics(); } catch (SchematicHandler.UnsupportedFormatException e) { - e.printStackTrace(); + LOGGER.error(e); } }); }); diff --git a/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorFactory.java b/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorFactory.java index ac4c7d8e1..64acd6543 100644 --- a/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorFactory.java +++ b/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorFactory.java @@ -40,7 +40,8 @@ public interface ChunkCoordinatorFactory { final @NonNull Consumer throwableConsumer, @Assisted("unloadAfter") final boolean unloadAfter, final @NonNull Collection progressSubscribers, - @Assisted("forceSync") final boolean forceSync + @Assisted("forceSync") final boolean forceSync, + @Assisted("shouldGen") final boolean shouldGen ); } diff --git a/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java b/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java index 408cba8d0..cd930087d 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java +++ b/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java @@ -52,6 +52,7 @@ public class ChunkCoordinatorBuilder { private int initialBatchSize = Settings.QUEUE.INITIAL_BATCH_SIZE; private boolean unloadAfter = true; private boolean forceSync = false; + private boolean shouldGen = true; @Inject public ChunkCoordinatorBuilder(@NonNull ChunkCoordinatorFactory chunkCoordinatorFactory) { @@ -203,6 +204,19 @@ public class ChunkCoordinatorBuilder { return this; } + /** + * Set whether chunks should be generated as part of this operation. Default is true. Disabling this may not be supported + * depending on server implementation. (i.e. setting to false may not actually disable generation as part of this operation + * - this is just a catch-all in case of future differing server implementations; the option will work on Spigot/Paper). + * + * @param shouldGen should generate new chunks or not + * @since TODO + */ + public @NonNull ChunkCoordinatorBuilder shouldGen(final boolean shouldGen) { + this.shouldGen = shouldGen; + return this; + } + public @NonNull ChunkCoordinatorBuilder withProgressSubscriber(ProgressSubscriber progressSubscriber) { this.progressSubscribers.add(progressSubscriber); return this; @@ -234,7 +248,8 @@ public class ChunkCoordinatorBuilder { this.throwableConsumer, this.unloadAfter, this.progressSubscribers, - this.forceSync + this.forceSync, + this.shouldGen ); } diff --git a/Core/src/main/java/com/plotsquared/core/queue/DelegateQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/DelegateQueueCoordinator.java index dbd73057a..d78621c1b 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/DelegateQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/DelegateQueueCoordinator.java @@ -51,6 +51,7 @@ public class DelegateQueueCoordinator extends QueueCoordinator { if (parent != null) { this.setForceSync(parent.isForceSync()); + this.setShouldGen(parent.isShouldGen()); } } diff --git a/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java index ff2b45b17..9ff243dca 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java @@ -45,6 +45,7 @@ public abstract class QueueCoordinator { private final AtomicBoolean enqueued = new AtomicBoolean(); private boolean forceSync = false; + private boolean shouldGen = true; @Nullable private Object chunkObject; @SuppressWarnings({"unused", "FieldCanBeLocal"}) @@ -110,6 +111,30 @@ public abstract class QueueCoordinator { this.forceSync = forceSync; } + + /** + * Get whether chunks should be generated as part of this operation. Default is true. Disabling this may not be supported + * depending on server implementation. (i.e. setting to false may not actually disable generation as part of this operation + * - this is just a catch-all in case of future differing server implementations; the option will work on Spigot/Paper). + * + * @since TODO + */ + public boolean isShouldGen() { + return shouldGen; + } + + /** + * Set whether chunks should be generated as part of this operation. Default is true. Disabling this may not be supported + * depending on server implementation. (i.e. setting to false may not actually disable generation as part of this operation + * - this is just a catch-all in case of future differing server implementations; the option will work on Spigot/Paper). + * + * @param shouldGen should generate new chunks or not + * @since TODO + */ + public void setShouldGen(boolean shouldGen) { + this.shouldGen = shouldGen; + } + /** * Get the Chunk Object set to the queue *