diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BlockStatePopulator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BlockStatePopulator.java index e8cb8d533..935ef3fde 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BlockStatePopulator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BlockStatePopulator.java @@ -32,11 +32,12 @@ import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.queue.ScopedQueueCoordinator; +import com.sk89q.worldedit.bukkit.BukkitWorld; import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.generator.BlockPopulator; -import javax.annotation.Nonnull; +import javax.annotation.Nonnull; import java.util.Random; final class BlockStatePopulator extends BlockPopulator { @@ -52,12 +53,11 @@ final class BlockStatePopulator extends BlockPopulator { this.plotAreaManager = plotAreaManager; } - @Override - public void populate(@Nonnull final World world, @Nonnull final Random random, + @Override public void populate(@Nonnull final World world, @Nonnull final Random random, @Nonnull final Chunk source) { if (this.queue == null) { - this.queue = PlotSquared.platform().getGlobalBlockQueue() - .getNewQueue(world.getName()); + this.queue = + PlotSquared.platform().getGlobalBlockQueue().getNewQueue(new BukkitWorld(world)); } final PlotArea area = this.plotAreaManager.getPlotArea(world.getName(), null); if (area == null) { 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 ff4d73f8f..41ebeef24 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java @@ -25,6 +25,8 @@ */ package com.plotsquared.bukkit.queue; +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; import com.plotsquared.bukkit.BukkitPlatform; import com.plotsquared.core.queue.ChunkCoordinator; import com.plotsquared.core.util.task.TaskManager; @@ -72,10 +74,13 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { private final AtomicInteger expectedSize; private int batchSize; - private BukkitChunkCoordinator(final long maxIterationTime, final int initialBatchSize, - @Nonnull final Consumer chunkConsumer, @Nonnull final World world, - @Nonnull final Collection requestedChunks, @Nonnull final Runnable whenDone, - @Nonnull final Consumer throwableConsumer) { + @Inject private BukkitChunkCoordinator(@Assisted final long maxIterationTime, + @Assisted final int initialBatchSize, + @Assisted @Nonnull final Consumer chunkConsumer, + @Assisted @Nonnull final World world, + @Assisted @Nonnull final Collection requestedChunks, + @Assisted @Nonnull final Runnable whenDone, + @Assisted @Nonnull final Consumer throwableConsumer) { this.requestedChunks = new LinkedBlockingQueue<>(requestedChunks); this.availableChunks = new LinkedBlockingQueue<>(); this.totalSize = requestedChunks.size(); 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 075359e26..3b8e6ce27 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java @@ -31,14 +31,18 @@ import com.plotsquared.bukkit.util.BukkitBlockUtil; import com.plotsquared.core.inject.factory.ChunkCoordinatorBuilderFactory; import com.plotsquared.core.inject.factory.ChunkCoordinatorFactory; import com.plotsquared.core.queue.BasicQueueCoordinator; +import com.plotsquared.core.queue.ChunkCoordinator; import com.plotsquared.core.queue.LocalChunk; import com.plotsquared.core.util.BlockUtil; import com.plotsquared.core.util.MainUtil; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.world.World; @@ -59,9 +63,11 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { private final World world; private final SideEffectSet sideEffectSet; + private org.bukkit.World bukkitWorld; @Inject private ChunkCoordinatorBuilderFactory chunkCoordinatorBuilderFactory; @Inject private ChunkCoordinatorFactory chunkCoordinatorFactory; private Runnable whenDone; + private ChunkCoordinator chunkCoordinator; @Inject public BukkitQueueCoordinator(World world) { super(world); @@ -80,17 +86,52 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { } } + @Override public void start() { + chunkCoordinator.start(); + } + + //TODO: implement cancellation + @Override public void cancel() { + chunkCoordinator.cancel(); + } + @Override public boolean enqueue() { + final EditSession editSession; + if (isRegen()) { + editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1); + world.regenerate(new CuboidRegion( + BlockVector3.at(getRegenStart()[0] << 4, 0, getRegenStart()[1] << 4), + BlockVector3.at((getRegenEnd()[0] << 4) + 15, 255, (getRegenEnd()[1] << 4) + 15)), + editSession); + } else { + editSession = null; + } Consumer consumer = getChunkConsumer(); if (consumer == null) { consumer = blockVector2 -> { LocalChunk localChunk = getBlockChunks().get(blockVector2); - if (localChunk == null) { + boolean isRegenChunk = + editSession != null && blockVector2.getBlockX() > getRegenStart()[0] + && blockVector2.getBlockZ() > getRegenStart()[1] + && blockVector2.getBlockX() < getRegenEnd()[0] + && blockVector2.getBlockZ() < getRegenEnd()[1]; + if (isRegenChunk) { + for (int layer = 0; layer < 16; layer++) { + for (int y = layer << 4; y < 16; y++) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + BaseBlock block = + editSession.getFullBlock(BlockVector3.at(x, y, z)); + setWorldBlock(x, y, z, block, blockVector2); + } + } + } + } + return; + } else if (localChunk == null) { throw new NullPointerException( "LocalChunk cannot be null when accessed from ChunkCoordinator"); } - org.bukkit.World bukkitWorld = null; - Chunk chunk = null; int sx = blockVector2.getX() << 4; int sz = blockVector2.getZ() << 4; for (int layer = 0; layer < localChunk.getBaseblocks().length; layer++) { @@ -106,42 +147,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { int x = sx + MainUtil.x_loc[layer][j]; int y = MainUtil.y_loc[layer][j]; int z = sz + MainUtil.z_loc[layer][j]; - try { - world.setBlock(BlockVector3.at(x, y, z), block, sideEffectSet); - } catch (WorldEditException ignored) { - // Fallback to not so nice method - BlockData blockData = BukkitAdapter.adapt(block); - - if (bukkitWorld == null) { - bukkitWorld = Bukkit.getWorld(world.getName()); - } - if (chunk == null) { - chunk = bukkitWorld - .getChunkAt(blockVector2.getX(), blockVector2.getZ()); - } - - Block existing = chunk.getBlock(x, y, z); - final BlockState existingBaseBlock = - BukkitAdapter.adapt(existing.getBlockData()); - if (BukkitBlockUtil.get(existing).equals(existingBaseBlock) && existing - .getBlockData().matches(blockData)) { - continue; - } - - if (existing.getState() instanceof Container) { - ((Container) existing.getState()).getInventory().clear(); - } - - existing.setType(BukkitAdapter.adapt(block.getBlockType()), false); - existing.setBlockData(blockData, false); - if (block.hasNbtData()) { - CompoundTag tag = block.getNbtData(); - StateWrapper sw = new StateWrapper(tag); - - sw.restoreTag(world.getName(), existing.getX(), existing.getY(), - existing.getZ()); - } - } + setWorldBlock(x, y, z, block, blockVector2); } } for (int layer = 0; layer < localChunk.getBaseblocks().length; layer++) { @@ -174,13 +180,48 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { } }; } - chunkCoordinatorBuilderFactory.create(chunkCoordinatorFactory).inWorld(world) - .withChunks(getBlockChunks().keySet()).withInitialBatchSize(3).withMaxIterationTime(40) - .withThrowableConsumer(Throwable::printStackTrace).withFinalAction(whenDone) - .withConsumer(consumer); + chunkCoordinator = + chunkCoordinatorBuilderFactory.create(chunkCoordinatorFactory).inWorld(world) + .withChunks(getBlockChunks().keySet()).withInitialBatchSize(3) + .withMaxIterationTime(40).withThrowableConsumer(Throwable::printStackTrace) + .withFinalAction(whenDone).withConsumer(consumer).build(); return super.enqueue(); } + private void setWorldBlock(int x, int y, int z, BaseBlock block, BlockVector2 blockVector2) { + try { + world.setBlock(BlockVector3.at(x, y, z), block, sideEffectSet); + } catch (WorldEditException ignored) { + // Fallback to not so nice method + BlockData blockData = BukkitAdapter.adapt(block); + + if (bukkitWorld == null) { + bukkitWorld = Bukkit.getWorld(world.getName()); + } + Chunk chunk = bukkitWorld.getChunkAt(blockVector2.getX(), blockVector2.getZ()); + + Block existing = chunk.getBlock(x, y, z); + final BlockState existingBaseBlock = BukkitAdapter.adapt(existing.getBlockData()); + if (BukkitBlockUtil.get(existing).equals(existingBaseBlock) && existing.getBlockData() + .matches(blockData)) { + return; + } + + if (existing.getState() instanceof Container) { + ((Container) existing.getState()).getInventory().clear(); + } + + existing.setType(BukkitAdapter.adapt(block.getBlockType()), false); + existing.setBlockData(blockData, false); + if (block.hasNbtData()) { + CompoundTag tag = block.getNbtData(); + StateWrapper sw = new StateWrapper(tag); + + sw.restoreTag(world.getName(), existing.getX(), existing.getY(), existing.getZ()); + } + } + } + @Override public void setCompleteTask(Runnable whenDone) { this.whenDone = whenDone; } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java index a3e9b4611..a01106c55 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java @@ -293,7 +293,7 @@ public class BukkitRegionManager extends RegionManager { int zzt = zzb + 15; if (xxb >= p1x && xxt <= p2x && zzb >= p1z && zzt <= p2z) { AugmentedUtils.bypass(ignoreAugment, - () -> queue.regenChunkSafe(chunk.getX(), chunk.getZ())); + () -> queue.regenChunk(chunk.getX(), chunk.getZ())); return; } boolean checkX1 = false; 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 463f58bb1..26b30b0c4 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 @@ -25,7 +25,6 @@ */ package com.plotsquared.core.inject.factory; -import com.google.inject.assistedinject.Assisted; import com.plotsquared.core.queue.ChunkCoordinator; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.world.World; @@ -37,12 +36,9 @@ import java.util.function.Consumer; public interface ChunkCoordinatorFactory { - @Nonnull ChunkCoordinator create(@Assisted final long maxIterationTime, - @Assisted final int initialBatchSize, - @NotNull @Assisted final Consumer chunkConsumer, - @NotNull @Assisted final World world, - @NotNull @Assisted final Collection requestedChunks, - @NotNull @Assisted final Runnable whenDone, - @NotNull @Assisted final Consumer throwableConsumer); + @Nonnull ChunkCoordinator create(final long maxIterationTime, final int initialBatchSize, + @NotNull final Consumer chunkConsumer, @NotNull final World world, + @NotNull final Collection requestedChunks, @NotNull final Runnable whenDone, + @NotNull final Consumer throwableConsumer); } diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java index 620ea670e..7e4ed4a31 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java @@ -27,6 +27,7 @@ package com.plotsquared.core.plot; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.collection.QuadMap; import com.plotsquared.core.configuration.CaptionUtility; import com.plotsquared.core.configuration.Captions; 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 7abc64bc4..f60f43efa 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java @@ -49,6 +49,9 @@ public abstract class BasicQueueCoordinator extends QueueCoordinator { private int lastZ = Integer.MIN_VALUE; private boolean settingBiomes = false; private boolean settingTiles = false; + private boolean regen = false; + private int[] regenStart; + private int[] regenEnd; private Consumer consumer = null; private GlobalBlockQueue globalBlockQueue; @@ -129,6 +132,40 @@ public abstract class BasicQueueCoordinator extends QueueCoordinator { return this.settingTiles; } + @Override public void regenChunk(int x, int z) { + regen = true; + // There will never only be one nullified coordinate pair + if (regenStart == null) { + regenStart = new int[]{x, z}; + regenEnd = new int[]{x, z}; + return; + } + if (x < regenStart[0]) { + regenStart[0] = x; + } + if (z < regenStart[1]) { + regenStart[1] = z; + } + if (x > regenEnd[0]) { + regenEnd[0] = x; + } + if (z > regenEnd[1]) { + regenEnd[1] = z; + } + } + + public int[] getRegenStart() { + return regenStart; + } + + public int[] getRegenEnd() { + return regenEnd; + } + + public boolean isRegen() { + return regen; + } + public ConcurrentHashMap getBlockChunks() { return this.blockChunks; } 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 a968e1992..7bb9178d0 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java +++ b/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java @@ -4,6 +4,7 @@ import com.google.common.base.Preconditions; import com.google.inject.Inject; import com.plotsquared.core.inject.factory.ChunkCoordinatorFactory; import com.plotsquared.core.location.Location; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.world.World; import org.jetbrains.annotations.NotNull; @@ -18,6 +19,7 @@ import java.util.function.Consumer; public class ChunkCoordinatorBuilder { private final List requestedChunks = new LinkedList<>(); + private final ChunkCoordinatorFactory chunkCoordinatorFactory; private Consumer throwableConsumer = Throwable::printStackTrace; private World world; private Consumer chunkConsumer; @@ -25,9 +27,9 @@ public class ChunkCoordinatorBuilder { }; private long maxIterationTime = 60; // A little over 1 tick; private int initialBatchSize = 4; - private final ChunkCoordinatorFactory chunkCoordinatorFactory; - @Inject public ChunkCoordinatorBuilder(@Nonnull ChunkCoordinatorFactory chunkCoordinatorFactory) { + @Inject + public ChunkCoordinatorBuilder(@Nonnull ChunkCoordinatorFactory chunkCoordinatorFactory) { this.chunkCoordinatorFactory = chunkCoordinatorFactory; } @@ -105,9 +107,9 @@ public class ChunkCoordinatorBuilder { Preconditions.checkNotNull(this.chunkConsumer, "No chunk consumer was supplied"); Preconditions.checkNotNull(this.whenDone, "No final action was supplied"); Preconditions.checkNotNull(this.throwableConsumer, "No throwable consumer was supplied"); - return chunkCoordinatorFactory.create(this.maxIterationTime, this.initialBatchSize, - this.chunkConsumer, this.world, this.requestedChunks, this.whenDone, - this.throwableConsumer); + return chunkCoordinatorFactory + .create(this.maxIterationTime, this.initialBatchSize, this.chunkConsumer, this.world, + this.requestedChunks, this.whenDone, this.throwableConsumer); } } 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 76cffc3be..d63773ddd 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/DelegateQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/DelegateQueueCoordinator.java @@ -65,43 +65,79 @@ public class DelegateQueueCoordinator extends QueueCoordinator { } @Override public boolean setBlock(int x, int y, int z, Pattern pattern) { - return parent.setBlock(x, y, z, pattern); + if (parent != null) { + return parent.setBlock(x, y, z, pattern); + } + return false; } @Override public boolean setBlock(int x, int y, int z, BaseBlock id) { - return parent.setBlock(x, y, z, id); + if (parent != null) { + return parent.setBlock(x, y, z, id); + } + return false; } @Override public boolean setBlock(int x, int y, int z, BlockState id) { - return parent.setBlock(x, y, z, id); + if (parent != null) { + return parent.setBlock(x, y, z, id); + } + return false; } @Override public BlockState getBlock(int x, int y, int z) { - return parent.getBlock(x, y, z); + if (parent != null) { + return parent.getBlock(x, y, z); + } + return null; } @Override public boolean setBiome(int x, int z, BiomeType biome) { - return parent.setBiome(x, z, biome); + if (parent != null) { + return parent.setBiome(x, z, biome); + } + return false; } @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { - return parent.setBiome(x, y, z, biome); + if (parent != null) { + return parent.setBiome(x, y, z, biome); + } + return false; } @Override public boolean isSettingBiomes() { - return parent.isSettingBiomes(); + if (parent != null) { + return parent.isSettingBiomes(); + } + return false; + } + + @Override public void regenChunk(int x, int z) { + if (parent != null) { + parent.regenChunk(x, z); + } } @Override public World getWorld() { - return parent.getWorld(); + if (parent != null) { + return parent.getWorld(); + } + return null; } @Override public boolean setTile(int x, int y, int z, CompoundTag tag) { - return parent.setTile(x, y, z, tag); + if (parent != null) { + return parent.setTile(x, y, z, tag); + } + return false; } @Override public boolean isSettingTiles() { - return parent.isSettingTiles(); + if (parent != null) { + return parent.isSettingTiles(); + } + return false; } @Override public boolean enqueue() { @@ -111,11 +147,27 @@ public class DelegateQueueCoordinator extends QueueCoordinator { return false; } + @Override public void start() { + if (parent != null) { + parent.start(); + } + } + + @Override public void cancel() { + if (parent != null) { + parent.cancel(); + } + } + @Override public void setCompleteTask(Runnable whenDone) { - parent.setCompleteTask(whenDone); + if (parent != null) { + parent.setCompleteTask(whenDone); + } } @Override public void setChunkConsumer(Consumer consumer) { - parent.setChunkConsumer(consumer); + if (parent != null) { + parent.setChunkConsumer(consumer); + } } } diff --git a/Core/src/main/java/com/plotsquared/core/queue/GlobalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/GlobalBlockQueue.java index cd18fd0f0..e5d69406e 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/GlobalBlockQueue.java +++ b/Core/src/main/java/com/plotsquared/core/queue/GlobalBlockQueue.java @@ -58,20 +58,23 @@ public class GlobalBlockQueue { } /** - * TODO Documentation needed. + * Place an instance of {@link QueueCoordinator} into a list incase access is needed + * and then start it. * - * @param queue todo + * @param queue {@link QueueCoordinator} instance to start. * @return true if added to queue, false otherwise */ public boolean enqueue(QueueCoordinator queue) { boolean success = false; if (queue.size() > 0 && !activeQueues.contains(queue)) { success = activeQueues.add(queue); + queue.start(); } return success; } public void dequeue(QueueCoordinator queue) { + queue.cancel(); activeQueues.remove(queue); } 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 91194e25f..e1161ab20 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java @@ -108,6 +108,8 @@ public abstract class QueueCoordinator { public abstract boolean isSettingBiomes(); + public abstract void regenChunk(int x, int z); + public abstract World getWorld(); public final void setModified() { @@ -118,6 +120,10 @@ public abstract class QueueCoordinator { return blockQueue.enqueue(this); } + public abstract void start(); + + public abstract void cancel(); + public abstract void setCompleteTask(Runnable whenDone); public abstract void setChunkConsumer(Consumer consumer);