mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2025-03-03 16:49:43 +01:00
fix: allow queues to not generate chunks (#4599)
- initially apply to regenallroads - additionally add a 10s timeout for requesting a chunk before resubmitting it to the queue - addresses #4310
This commit is contained in:
parent
d4f10422e3
commit
eb0d854870
@ -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<ProgressSubscriber> progressSubscribers = new LinkedList<>();
|
||||
|
||||
private final Queue<BlockVector2> 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<Throwable> throwableConsumer,
|
||||
@Assisted("unloadAfter") final boolean unloadAfter,
|
||||
@Assisted final @NonNull Collection<ProgressSubscriber> 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 {
|
||||
|
@ -238,6 +238,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator {
|
||||
.unloadAfter(isUnloadAfter())
|
||||
.withProgressSubscribers(getProgressSubscribers())
|
||||
.forceSync(isForceSync())
|
||||
.shouldGen(isShouldGen())
|
||||
.build();
|
||||
return super.enqueue();
|
||||
}
|
||||
|
@ -432,6 +432,7 @@ public class HybridUtils {
|
||||
if (!UPDATE) {
|
||||
Iterator<BlockVector2> 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<BlockVector2> 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<BlockVector2> 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);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -40,7 +40,8 @@ public interface ChunkCoordinatorFactory {
|
||||
final @NonNull Consumer<Throwable> throwableConsumer,
|
||||
@Assisted("unloadAfter") final boolean unloadAfter,
|
||||
final @NonNull Collection<ProgressSubscriber> progressSubscribers,
|
||||
@Assisted("forceSync") final boolean forceSync
|
||||
@Assisted("forceSync") final boolean forceSync,
|
||||
@Assisted("shouldGen") final boolean shouldGen
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ public class DelegateQueueCoordinator extends QueueCoordinator {
|
||||
|
||||
if (parent != null) {
|
||||
this.setForceSync(parent.isForceSync());
|
||||
this.setShouldGen(parent.isShouldGen());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user