diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitAugmentedGenerator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitAugmentedGenerator.java index 0f3733c11..b63b4f9fb 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitAugmentedGenerator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitAugmentedGenerator.java @@ -25,7 +25,11 @@ */ package com.plotsquared.bukkit.generator; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.generator.AugmentedUtils; +import com.plotsquared.core.queue.QueueCoordinator; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.util.SideEffectSet; import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.generator.BlockPopulator; @@ -52,7 +56,14 @@ public class BukkitAugmentedGenerator extends BlockPopulator { @Override public void populate(@NonNull World world, @NonNull Random random, @NonNull Chunk source) { - AugmentedUtils.generate(source, world.getName(), source.getX(), source.getZ(), null); + QueueCoordinator queue = PlotSquared.platform().globalBlockQueue().getNewQueue(BukkitAdapter.adapt(world)); + // The chunk is already loaded and we do not want to load the chunk in "fully" by using any PaperLib methods. + queue.setForceSync(true); + queue.setSideEffectSet(SideEffectSet.none()); + queue.setBiomesEnabled(false); + queue.setChunkObject(source); + AugmentedUtils.generateChunk(world.getName(), source.getX(), source.getZ(), queue); + queue.enqueue(); } } 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 3f78bf39e..2ed483ee1 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java @@ -76,10 +76,11 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { private final int totalSize; private final AtomicInteger expectedSize; private final AtomicInteger loadingChunks = new AtomicInteger(); + private final boolean forceSync; private int batchSize; private PlotSquaredTask task; - private boolean shouldCancel; + private volatile boolean shouldCancel; private boolean finished; @Inject @@ -92,7 +93,8 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { @Assisted final @NonNull Runnable whenDone, @Assisted final @NonNull Consumer throwableConsumer, @Assisted final boolean unloadAfter, - @Assisted final @NonNull Collection progressSubscribers + @Assisted final @NonNull Collection progressSubscribers, + @Assisted final boolean forceSync ) { this.requestedChunks = new LinkedBlockingQueue<>(requestedChunks); this.availableChunks = new LinkedBlockingQueue<>(); @@ -107,14 +109,27 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { this.plugin = JavaPlugin.getPlugin(BukkitPlatform.class); this.bukkitWorld = Bukkit.getWorld(world.getName()); this.progressSubscribers.addAll(progressSubscribers); + this.forceSync = forceSync; } @Override public void start() { - // Request initial batch - this.requestBatch(); - // Wait until next tick to give the chunks a chance to be loaded - TaskManager.runTaskLater(() -> task = TaskManager.runTaskRepeat(this, TaskTime.ticks(1)), TaskTime.ticks(1)); + if (!forceSync) { + // Request initial batch + this.requestBatch(); + // Wait until next tick to give the chunks a chance to be loaded + TaskManager.runTaskLater(() -> task = TaskManager.runTaskRepeat(this, TaskTime.ticks(1)), TaskTime.ticks(1)); + } else { + try { + while (!shouldCancel && !requestedChunks.isEmpty()) { + chunkConsumer.accept(requestedChunks.poll()); + } + } catch (Throwable t) { + throwableConsumer.accept(t); + } finally { + finish(); + } + } } @Override @@ -131,7 +146,9 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { for (final ProgressSubscriber subscriber : this.progressSubscribers) { subscriber.notifyEnd(); } - task.cancel(); + if (task != null) { + task.cancel(); + } finished = true; } } 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 f7e6f16a3..f100733fa 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java @@ -62,10 +62,27 @@ import java.util.function.Consumer; public class BukkitQueueCoordinator extends BasicQueueCoordinator { - private final SideEffectSet noSideEffectSet; - private final SideEffectSet lightingSideEffectSet; - private final SideEffectSet edgeSideEffectSet; - private final SideEffectSet edgeLightingSideEffectSet; + private static final SideEffectSet NO_SIDE_EFFECT_SET; + private static final SideEffectSet EDGE_SIDE_EFFECT_SET; + private static final SideEffectSet LIGHTING_SIDE_EFFECT_SET; + private static final SideEffectSet EDGE_LIGHTING_SIDE_EFFECT_SET; + + static { + NO_SIDE_EFFECT_SET = SideEffectSet.none().with(SideEffect.LIGHTING, SideEffect.State.OFF).with( + SideEffect.NEIGHBORS, + SideEffect.State.OFF + ); + EDGE_SIDE_EFFECT_SET = SideEffectSet.none().with(SideEffect.UPDATE, SideEffect.State.ON).with( + SideEffect.NEIGHBORS, + SideEffect.State.ON + ); + LIGHTING_SIDE_EFFECT_SET = SideEffectSet.none().with(SideEffect.NEIGHBORS, SideEffect.State.OFF); + EDGE_LIGHTING_SIDE_EFFECT_SET = SideEffectSet.none().with(SideEffect.UPDATE, SideEffect.State.ON).with( + SideEffect.NEIGHBORS, + SideEffect.State.ON + ); + } + private org.bukkit.World bukkitWorld; @Inject private ChunkCoordinatorBuilderFactory chunkCoordinatorBuilderFactory; @@ -76,19 +93,6 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { @Inject public BukkitQueueCoordinator(@NonNull World world) { super(world); - noSideEffectSet = SideEffectSet.none().with(SideEffect.LIGHTING, SideEffect.State.OFF).with( - SideEffect.NEIGHBORS, - SideEffect.State.OFF - ); - lightingSideEffectSet = SideEffectSet.none().with(SideEffect.NEIGHBORS, SideEffect.State.OFF); - edgeSideEffectSet = noSideEffectSet.with(SideEffect.UPDATE, SideEffect.State.ON).with( - SideEffect.NEIGHBORS, - SideEffect.State.ON - ); - edgeLightingSideEffectSet = noSideEffectSet.with(SideEffect.UPDATE, SideEffect.State.ON).with( - SideEffect.NEIGHBORS, - SideEffect.State.ON - ); } @Override @@ -201,7 +205,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { localChunk.getTiles().forEach((blockVector3, tag) -> { try { BaseBlock block = getWorld().getBlock(blockVector3).toBaseBlock(tag); - getWorld().setBlock(blockVector3, block, noSideEffectSet); + getWorld().setBlock(blockVector3, block, getSideEffectSet(SideEffectState.NONE)); } catch (WorldEditException ignored) { StateWrapper sw = new StateWrapper(tag); sw.restoreTag(getWorld().getName(), blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()); @@ -258,9 +262,9 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { } SideEffectSet sideEffectSet; if (lighting) { - sideEffectSet = edge ? edgeLightingSideEffectSet : lightingSideEffectSet; + sideEffectSet = getSideEffectSet(edge ? SideEffectState.EDGE_LIGHTING : SideEffectState.LIGHTING); } else { - sideEffectSet = edge ? edgeSideEffectSet : noSideEffectSet; + sideEffectSet = getSideEffectSet(edge ? SideEffectState.EDGE : SideEffectState.NONE); } getWorld().setBlock(loc, block, sideEffectSet); } catch (WorldEditException ignored) { @@ -375,4 +379,23 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { return false; } + private SideEffectSet getSideEffectSet(SideEffectState state) { + if (getSideEffectSet() != null) { + return getSideEffectSet(); + } + return switch (state) { + case NONE -> NO_SIDE_EFFECT_SET; + case EDGE -> EDGE_SIDE_EFFECT_SET; + case LIGHTING -> LIGHTING_SIDE_EFFECT_SET; + case EDGE_LIGHTING -> EDGE_LIGHTING_SIDE_EFFECT_SET; + }; + } + + private enum SideEffectState { + NONE, + EDGE, + LIGHTING, + EDGE_LIGHTING + } + } diff --git a/Core/src/main/java/com/plotsquared/core/generator/AugmentedUtils.java b/Core/src/main/java/com/plotsquared/core/generator/AugmentedUtils.java index 349d06b89..6c79c9252 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/AugmentedUtils.java +++ b/Core/src/main/java/com/plotsquared/core/generator/AugmentedUtils.java @@ -54,12 +54,22 @@ public class AugmentedUtils { enabled = true; } - public static boolean generate( - @Nullable Object chunkObject, + /** + * Generate an augmented world chunk at the given location. If a queue is given, the data will be written to it, else a new + * queue will be created and written to world. Returns true if generation occurred. + * + * @param world World name to generate data for. Must be a PlotSquared world containing one or more areas else nothing will + * happen. + * @param chunkX Chunk X position + * @param chunkZ Chunk Z position + * @param queue Queue to write to, if desired. + * @return true if generation occurred. + */ + public static boolean generateChunk( final @NonNull String world, final int chunkX, final int chunkZ, - QueueCoordinator queue + @Nullable QueueCoordinator queue ) { if (!enabled) { return false; @@ -97,9 +107,6 @@ public class AugmentedUtils { .platform() .worldUtil() .getWeWorld(world)); - if (chunkObject != null) { - queue.setChunkObject(chunkObject); - } } QueueCoordinator primaryMask; // coordinates @@ -157,13 +164,9 @@ public class AugmentedUtils { } generationResult = true; } - if (chunkObject != null) { - primaryMask.setChunkObject(chunkObject); - } - if (chunkObject != null) { - secondaryMask.setChunkObject(chunkObject); - } + // This queue should not be enqueued as it is simply used to restrict block setting, and then delegate to the + // actual queue ScopedQueueCoordinator scoped = new ScopedQueueCoordinator( secondaryMask, @@ -172,8 +175,6 @@ public class AugmentedUtils { ); generator.generateChunk(scoped, area); generator.populateChunk(scoped, area); - scoped.setForceSync(true); - scoped.enqueue(); } if (enqueue) { queue.enqueue(); @@ -181,4 +182,19 @@ public class AugmentedUtils { return generationResult; } + /** + * @deprecated Use {@link AugmentedUtils#generateChunk(String, int, int, QueueCoordinator)} as chunkObject is not required + * in the above method + */ + @Deprecated(forRemoval = true) + public static boolean generate( + @Nullable Object chunkObject, + final @NonNull String world, + final int chunkX, + final int chunkZ, + QueueCoordinator queue + ) { + return generateChunk(world, chunkX, chunkZ, queue); + } + } diff --git a/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java index 1f6d6371c..957ca441d 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java @@ -34,6 +34,7 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; @@ -61,6 +62,7 @@ public abstract class BasicQueueCoordinator extends QueueCoordinator { private int lastX = Integer.MIN_VALUE; private int lastZ = Integer.MIN_VALUE; private boolean settingBiomes = false; + private boolean disableBiomes = false; private boolean settingTiles = false; private boolean regen = false; private int[] regenStart; @@ -68,7 +70,8 @@ public abstract class BasicQueueCoordinator extends QueueCoordinator { private CuboidRegion regenRegion = null; private Consumer consumer = null; private boolean unloadAfter = true; - private Runnable whenDone; + private Runnable whenDone = null; + private SideEffectSet sideEffectSet = null; @Nullable private LightingMode lightingMode = LightingMode.valueOf(Settings.QUEUE.LIGHTING_MODE); @@ -120,6 +123,9 @@ public abstract class BasicQueueCoordinator extends QueueCoordinator { @SuppressWarnings("removal") @Override public boolean setBiome(int x, int z, @NonNull BiomeType biomeType) { + if (disableBiomes) { + return false; + } LocalChunk chunk = getChunk(x >> 4, z >> 4); for (int y = world.getMinY(); y <= world.getMaxY(); y++) { chunk.setBiome(x & 15, y, z & 15, biomeType); @@ -130,6 +136,9 @@ public abstract class BasicQueueCoordinator extends QueueCoordinator { @Override public final boolean setBiome(int x, int y, int z, @NonNull BiomeType biomeType) { + if (disableBiomes) { + return false; + } LocalChunk chunk = getChunk(x >> 4, z >> 4); chunk.setBiome(x & 15, y, z & 15, biomeType); settingBiomes = true; @@ -141,6 +150,12 @@ public abstract class BasicQueueCoordinator extends QueueCoordinator { return this.settingBiomes; } + @Override + public void setBiomesEnabled(boolean settingBiomes) { + this.settingBiomes = settingBiomes; + this.disableBiomes = true; + } + @Override public boolean setTile(int x, int y, int z, @NonNull CompoundTag tag) { LocalChunk chunk = getChunk(x >> 4, z >> 4); @@ -315,6 +330,29 @@ public abstract class BasicQueueCoordinator extends QueueCoordinator { this.whenDone = whenDone; } + @Override + public SideEffectSet getSideEffectSet() { + return sideEffectSet; + } + + @Override + public void setSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + // Don't ask about the @NonNull placement. That's how it needs to be else it errors. + @Override + public void setBiomeCuboid( + final com.plotsquared.core.location.@NonNull Location pos1, + final com.plotsquared.core.location.@NonNull Location pos2, + @NonNull final BiomeType biome + ) { + if (disableBiomes) { + return; + } + super.setBiomeCuboid(pos1, pos2, biome); + } + /** * Get the {@link LocalChunk} from the queue at the given chunk coordinates. Returns a new instance if one doesn't exist */ 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 0dd83c39e..b0c827ff1 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/DelegateQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/DelegateQueueCoordinator.java @@ -32,6 +32,7 @@ import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; @@ -135,6 +136,13 @@ public class DelegateQueueCoordinator extends QueueCoordinator { return false; } + @Override + public void setBiomesEnabled(final boolean enabled) { + if (parent != null) { + parent.setBiomesEnabled(enabled); + } + } + @Override public boolean setEntity(@NonNull Entity entity) { if (parent != null) { @@ -248,6 +256,21 @@ public class DelegateQueueCoordinator extends QueueCoordinator { } } + @Override + public SideEffectSet getSideEffectSet() { + if (parent != null) { + return parent.getSideEffectSet(); + } + return null; + } + + @Override + public void setSideEffectSet(final SideEffectSet sideEffectSet) { + if (parent != null) { + parent.setSideEffectSet(sideEffectSet); + } + } + @Override public @NonNull List getReadChunks() { if (parent != null) { 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 7853f89eb..98fd88e9e 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java @@ -35,6 +35,7 @@ import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; @@ -247,6 +248,13 @@ public abstract class QueueCoordinator { */ public abstract boolean isSettingBiomes(); + /** + * If the queue should accept biome placement + * + * @param enabled If biomes should be enabled + */ + public abstract void setBiomesEnabled(boolean enabled); + /** * Add entities to be created * @@ -412,6 +420,10 @@ public abstract class QueueCoordinator { */ public abstract void setLightingMode(@Nullable LightingMode mode); + public abstract SideEffectSet getSideEffectSet(); + + public abstract void setSideEffectSet(SideEffectSet sideEffectSet); + /** * Fill a cuboid between two positions with a BlockState * diff --git a/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java index cba1f8a2a..2debf5829 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java @@ -35,22 +35,20 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** - * Queue that only sets blocks with a designated area + * Queue that only sets blocks with a designated X-Z area, will accept any Y values. Requires all blocks be set normalized in + * the x and z directions, i.e. starting from 0,0. An offset of the minimum point of the region will then be applied to x and z. */ public class ScopedQueueCoordinator extends DelegateQueueCoordinator { private final Location min; private final Location max; private final int minX; - private final int minY; private final int minZ; private final int maxX; - private final int maxY; private final int maxZ; private final int dx; - private final int dy; private final int dz; /** @@ -61,15 +59,12 @@ public class ScopedQueueCoordinator extends DelegateQueueCoordinator { this.min = min; this.max = max; this.minX = min.getX(); - this.minY = min.getY(); this.minZ = min.getZ(); this.maxX = max.getX(); - this.maxY = max.getY(); this.maxZ = max.getZ(); this.dx = maxX - minX; - this.dy = maxY - minY; this.dz = maxZ - minZ; } @@ -80,11 +75,11 @@ public class ScopedQueueCoordinator extends DelegateQueueCoordinator { @Override public boolean setBiome(int x, int y, int z, @NonNull BiomeType biome) { - return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super.setBiome(x + minX, y + minY, z + minZ, biome); + return x >= 0 && x <= dx && z >= 0 && z <= dz && super.setBiome(x + minX, y, z + minZ, biome); } public void fillBiome(BiomeType biome) { - for (int y = 0; y <= dy; y++) { + for (int y = min.getY(); y <= max.getY(); y++) { for (int x = 0; x <= dx; x++) { for (int z = 0; z < dz; z++) { setBiome(x, y, z, biome); @@ -95,27 +90,22 @@ public class ScopedQueueCoordinator extends DelegateQueueCoordinator { @Override public boolean setBlock(int x, int y, int z, @NonNull BaseBlock id) { - return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super.setBlock(x + minX, y + minY, z + minZ, id); + return x >= 0 && x <= dx && z >= 0 && z <= dz && super.setBlock(x + minX, y, z + minZ, id); } @Override public boolean setBlock(int x, int y, int z, @NonNull BlockState id) { - return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super.setBlock(x + minX, y + minY, z + minZ, id); + return x >= 0 && x <= dx && z >= 0 && z <= dz && super.setBlock(x + minX, y, z + minZ, id); } @Override public boolean setBlock(int x, int y, int z, @NonNull Pattern pattern) { - return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super.setBlock( - x + minX, - y + minY, - z + minZ, - pattern - ); + return x >= 0 && x <= dx && z >= 0 && z <= dz && super.setBlock(x + minX, y, z + minZ, pattern); } @Override public boolean setTile(int x, int y, int z, @NonNull CompoundTag tag) { - return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super.setTile(x + minX, y + minY, z + minZ, tag); + return x >= 0 && x <= dx && z >= 0 && z <= dz && super.setTile(x + minX, y, z + minZ, tag); } public @NonNull Location getMin() {