Continue implementation of new queue system

- Move ChunkCoordinatorBuild to Core
- Add core ChunkCoordinator
- Add Factories for ChunkCoordinator and its Builder
- Reimplement refreshChunk but in WorldUtil
- Allow custom Consumers to be used by the Queue when sent to the ChunkCoordinator
- Start switching ChunkTasks to use the new ChunkCoordinator system
- Replace GlobalBlockQueue's "empty task" system with normal sync TaskManager
- Remove lombok from the queue system
- Add back forceSync and chunkObject from LocalBlockQueue
This commit is contained in:
dordsor21
2020-07-18 12:07:56 +01:00
parent 66b94ab9f1
commit 57af50ed49
23 changed files with 625 additions and 441 deletions

View File

@ -26,12 +26,11 @@
package com.plotsquared.bukkit.inject;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.util.Providers;
import com.plotsquared.bukkit.BukkitPlatform;
import com.plotsquared.bukkit.player.BukkitPlayerManager;
import com.plotsquared.bukkit.queue.BukkitChunkCoordinator;
import com.plotsquared.bukkit.queue.BukkitQueueCoordinator;
import com.plotsquared.bukkit.schematic.BukkitSchematicHandler;
import com.plotsquared.bukkit.util.BukkitChunkManager;
@ -41,18 +40,20 @@ import com.plotsquared.bukkit.util.BukkitPermHandler;
import com.plotsquared.bukkit.util.BukkitRegionManager;
import com.plotsquared.bukkit.util.BukkitSetupUtils;
import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.bukkit.util.task.PaperTimeConverter;
import com.plotsquared.bukkit.util.task.SpigotTimeConverter;
import com.plotsquared.core.PlotPlatform;
import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.generator.HybridGen;
import com.plotsquared.core.generator.IndependentPlotGenerator;
import com.plotsquared.core.inject.annotations.ConsoleActor;
import com.plotsquared.core.inject.annotations.DefaultGenerator;
import com.plotsquared.core.inject.factory.ChunkCoordinatorBuilderFactory;
import com.plotsquared.core.inject.factory.ChunkCoordinatorFactory;
import com.plotsquared.core.inject.factory.HybridPlotWorldFactory;
import com.plotsquared.core.plot.world.DefaultPlotAreaManager;
import com.plotsquared.core.plot.world.PlotAreaManager;
import com.plotsquared.core.plot.world.SinglePlotAreaManager;
import com.plotsquared.core.queue.ChunkCoordinator;
import com.plotsquared.core.queue.ChunkCoordinatorBuilder;
import com.plotsquared.core.queue.GlobalBlockQueue;
import com.plotsquared.core.queue.QueueProvider;
import com.plotsquared.core.util.ChunkManager;
@ -105,6 +106,10 @@ public class BukkitModule extends AbstractModule {
bind(PlotAreaManager.class).to(DefaultPlotAreaManager.class);
}
install(new FactoryModuleBuilder().build(HybridPlotWorldFactory.class));
install(new FactoryModuleBuilder()
.implement(ChunkCoordinator.class, BukkitChunkCoordinator.class)
.build(ChunkCoordinatorFactory.class));
install(new FactoryModuleBuilder().build(ChunkCoordinatorBuilderFactory.class));
}
private void setupVault() {

View File

@ -25,17 +25,19 @@
*/
package com.plotsquared.bukkit.queue;
import com.google.common.base.Preconditions;
import com.plotsquared.bukkit.BukkitPlatform;
import com.plotsquared.core.queue.ChunkCoordinator;
import com.plotsquared.core.util.task.TaskManager;
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.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
@ -44,32 +46,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
/**
* Utility that allows for the loading and coordination of chunk actions
* <p>
* The coordinator takes in collection of chunk coordinates, loads them
* and allows the caller to specify a sink for the loaded chunks. The
* coordinator will prevent the chunks from being unloaded until the sink
* has fully consumed the chunk
* <p>
* Usage:
* <pre>{@code
* final ChunkCoordinator chunkCoordinator = ChunkCoordinator.builder()
* .inWorld(Objects.requireNonNull(Bukkit.getWorld("world"))).withChunk(BlockVector2.at(0, 0))
* .withConsumer(chunk -> System.out.printf("Got chunk %d;%d", chunk.getX(), chunk.getZ()))
* .withFinalAction(() -> System.out.println("All chunks have been loaded"))
* .withThrowableConsumer(throwable -> System.err.println("Something went wrong... =("))
* .withMaxIterationTime(25L)
* .build();
* chunkCoordinator.subscribeToProgress((coordinator, progress) ->
* System.out.printf("Progress: %.1f", progress * 100.0f));
* chunkCoordinator.start();
* }</pre>
*
* @author Alexander Söderberg
* @see #builder() To create a new coordinator instance
*/
public final class BukkitChunkCoordinator extends BukkitRunnable {
public final class BukkitChunkCoordinator extends ChunkCoordinator {
private final List<ProgressSubscriber> progressSubscribers = new LinkedList<>();
@ -77,52 +54,44 @@ public final class BukkitChunkCoordinator extends BukkitRunnable {
private final Queue<Chunk> availableChunks;
private final long maxIterationTime;
private final Plugin plugin;
private final Consumer<Chunk> chunkConsumer;
private final World world;
private final Consumer<BlockVector2> chunkConsumer;
private final org.bukkit.World bukkitWorld;
private final Runnable whenDone;
private final Consumer<Throwable> throwableConsumer;
private final int totalSize;
private AtomicInteger expectedSize;
private final AtomicInteger expectedSize;
private int batchSize;
private BukkitChunkCoordinator(final long maxIterationTime, final int initialBatchSize,
@NotNull final Consumer<Chunk> chunkConsumer, @NotNull final World world,
@NotNull final Collection<BlockVector2> requestedChunks, @NotNull final Runnable whenDone,
@NotNull final Consumer<Throwable> throwableConsumer) {
@Nonnull final Consumer<BlockVector2> chunkConsumer, @Nonnull final World world,
@Nonnull final Collection<BlockVector2> requestedChunks, @Nonnull final Runnable whenDone,
@Nonnull final Consumer<Throwable> throwableConsumer) {
this.requestedChunks = new LinkedBlockingQueue<>(requestedChunks);
this.availableChunks = new LinkedBlockingQueue<>();
this.totalSize = requestedChunks.size();
this.expectedSize = new AtomicInteger(this.totalSize);
this.world = world;
this.batchSize = initialBatchSize;
this.chunkConsumer = chunkConsumer;
this.maxIterationTime = maxIterationTime;
this.whenDone = whenDone;
this.throwableConsumer = throwableConsumer;
this.plugin = JavaPlugin.getPlugin(BukkitPlatform.class);
}
/**
* Create a new {@link BukkitChunkCoordinator} instance
*
* @return Coordinator builder instance
*/
@NotNull public static ChunkCoordinatorBuilder builder() {
return new ChunkCoordinatorBuilder();
this.bukkitWorld = Bukkit.getWorld(world.getName());
}
/**
* Start the coordinator instance
*/
public void start() {
@Override public void start() {
// Request initial batch
this.requestBatch();
// Wait until next tick to give the chunks a chance to be loaded
this.runTaskTimer(this.plugin, 1L, 1L);
TaskManager.runTaskLater(() -> TaskManager.runTaskRepeat(this, TaskTime.ticks(1)),
TaskTime.ticks(1));
}
@Override public void run() {
@Override public void runTask() {
Chunk chunk = this.availableChunks.poll();
if (chunk == null) {
return;
@ -132,7 +101,7 @@ public final class BukkitChunkCoordinator extends BukkitRunnable {
do {
final long start = System.currentTimeMillis();
try {
this.chunkConsumer.accept(chunk);
this.chunkConsumer.accept(BlockVector2.at(chunk.getX(), chunk.getZ()));
} catch (final Throwable throwable) {
this.throwableConsumer.accept(throwable);
}
@ -173,7 +142,7 @@ public final class BukkitChunkCoordinator extends BukkitRunnable {
BlockVector2 chunk;
for (int i = 0; i < this.batchSize && (chunk = this.requestedChunks.poll()) != null; i++) {
// This required PaperLib to be bumped to version 1.0.4 to mark the request as urgent
PaperLib.getChunkAtAsync(this.world, chunk.getX(), chunk.getZ(), true, true)
PaperLib.getChunkAtAsync(this.bukkitWorld, chunk.getX(), chunk.getZ(), true, true)
.whenComplete((chunkObject, throwable) -> {
if (throwable != null) {
throwable.printStackTrace();
@ -186,7 +155,7 @@ public final class BukkitChunkCoordinator extends BukkitRunnable {
}
}
private void processChunk(@NotNull final Chunk chunk) {
private void processChunk(@Nonnull final Chunk chunk) {
if (!chunk.isLoaded()) {
throw new IllegalArgumentException(
String.format("Chunk %d;%d is is not loaded", chunk.getX(), chunk.getZ()));
@ -195,7 +164,7 @@ public final class BukkitChunkCoordinator extends BukkitRunnable {
this.availableChunks.add(chunk);
}
private void freeChunk(@NotNull final Chunk chunk) {
private void freeChunk(@Nonnull final Chunk chunk) {
if (!chunk.isLoaded()) {
throw new IllegalArgumentException(
String.format("Chunk %d;%d is is not loaded", chunk.getX(), chunk.getZ()));
@ -208,7 +177,7 @@ public final class BukkitChunkCoordinator extends BukkitRunnable {
*
* @return Snapshot view of remaining chunk count
*/
public int getRemainingChunks() {
@Override public int getRemainingChunks() {
return this.expectedSize.get();
}
@ -217,7 +186,7 @@ public final class BukkitChunkCoordinator extends BukkitRunnable {
*
* @return Requested chunk count
*/
public int getTotalChunks() {
@Override public int getTotalChunks() {
return this.totalSize;
}
@ -227,11 +196,10 @@ public final class BukkitChunkCoordinator extends BukkitRunnable {
* @param subscriber Subscriber
*/
public void subscribeToProgress(
@NotNull final BukkitChunkCoordinator.ProgressSubscriber subscriber) {
@Nonnull final BukkitChunkCoordinator.ProgressSubscriber subscriber) {
this.progressSubscribers.add(subscriber);
}
@FunctionalInterface
public interface ProgressSubscriber {
@ -241,88 +209,9 @@ public final class BukkitChunkCoordinator extends BukkitRunnable {
* @param coordinator Coordinator instance that triggered the notification
* @param progress Progress in the range [0, 1]
*/
void notifyProgress(@NotNull final BukkitChunkCoordinator coordinator,
void notifyProgress(@Nonnull final BukkitChunkCoordinator coordinator,
final float progress);
}
public static final class ChunkCoordinatorBuilder {
private final List<BlockVector2> requestedChunks = new LinkedList<>();
private Consumer<Throwable> throwableConsumer = Throwable::printStackTrace;
private World world;
private Consumer<Chunk> chunkConsumer;
private Runnable whenDone = () -> {
};
private long maxIterationTime = 60; // A little over 1 tick;
private int initialBatchSize = 4;
private ChunkCoordinatorBuilder() {
}
@NotNull public ChunkCoordinatorBuilder inWorld(@NotNull final World world) {
this.world = Preconditions.checkNotNull(world, "World may not be null");
return this;
}
@NotNull
public ChunkCoordinatorBuilder withChunk(@NotNull final BlockVector2 chunkLocation) {
this.requestedChunks
.add(Preconditions.checkNotNull(chunkLocation, "Chunk location may not be null"));
return this;
}
@NotNull public ChunkCoordinatorBuilder withChunks(
@NotNull final Collection<BlockVector2> chunkLocations) {
chunkLocations.forEach(this::withChunk);
return this;
}
@NotNull
public ChunkCoordinatorBuilder withConsumer(@NotNull final Consumer<Chunk> chunkConsumer) {
this.chunkConsumer =
Preconditions.checkNotNull(chunkConsumer, "Chunk consumer may not be null");
return this;
}
@NotNull public ChunkCoordinatorBuilder withFinalAction(@NotNull final Runnable whenDone) {
this.whenDone = Preconditions.checkNotNull(whenDone, "Final action may not be null");
return this;
}
@NotNull public ChunkCoordinatorBuilder withMaxIterationTime(final long maxIterationTime) {
Preconditions
.checkArgument(maxIterationTime > 0, "Max iteration time must be positive");
this.maxIterationTime = maxIterationTime;
return this;
}
@NotNull public ChunkCoordinatorBuilder withInitialBatchSize(final int initialBatchSize) {
Preconditions
.checkArgument(initialBatchSize > 0, "Initial batch size must be positive");
this.initialBatchSize = initialBatchSize;
return this;
}
@NotNull public ChunkCoordinatorBuilder withThrowableConsumer(
@NotNull final Consumer<Throwable> throwableConsumer) {
this.throwableConsumer =
Preconditions.checkNotNull(throwableConsumer, "Throwable consumer may not be null");
return this;
}
@NotNull public BukkitChunkCoordinator build() {
Preconditions.checkNotNull(this.world, "No world was supplied");
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 new BukkitChunkCoordinator(this.maxIterationTime, this.initialBatchSize,
this.chunkConsumer, this.world, this.requestedChunks, this.whenDone,
this.throwableConsumer);
}
}
}

View File

@ -25,8 +25,11 @@
*/
package com.plotsquared.bukkit.queue;
import com.google.inject.Inject;
import com.plotsquared.bukkit.schematic.StateWrapper;
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.LocalChunk;
import com.plotsquared.core.util.BlockUtil;
@ -42,20 +45,25 @@ import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Container;
import org.bukkit.block.data.BlockData;
import javax.annotation.Nonnull;
import java.util.function.Consumer;
public class BukkitQueueCoordinator extends BasicQueueCoordinator {
private final World world;
private final SideEffectSet sideEffectSet;
@Inject private ChunkCoordinatorBuilderFactory chunkCoordinatorBuilderFactory;
@Inject private ChunkCoordinatorFactory chunkCoordinatorFactory;
private Runnable whenDone;
public BukkitQueueCoordinator(World world) {
@Inject public BukkitQueueCoordinator(World world) {
super(world);
this.world = world;
sideEffectSet = SideEffectSet.none().with(SideEffect.LIGHTING, SideEffect.State.OFF)
@ -73,19 +81,18 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator {
}
@Override public boolean enqueue() {
BukkitChunkCoordinator.builder().inWorld(BukkitAdapter.adapt(world))
.withChunks(getBlockChunks().keySet()).withInitialBatchSize(3).withMaxIterationTime(40)
.withThrowableConsumer(Throwable::printStackTrace).withFinalAction(whenDone)
.withConsumer(chunk -> {
LocalChunk localChunk =
getBlockChunks().get(BlockVector2.at(chunk.getX(), chunk.getZ()));
Consumer<BlockVector2> consumer = getChunkConsumer();
if (consumer == null) {
consumer = blockVector2 -> {
LocalChunk localChunk = getBlockChunks().get(blockVector2);
if (localChunk == null) {
throw new NullPointerException(
"LocalChunk cannot be null when accessed from ChunkCoordinator");
}
World worldObj = getWorld();
int sx = chunk.getX() << 4;
int sz = chunk.getX() << 4;
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++) {
BaseBlock[] blocksLayer = localChunk.getBaseblocks()[layer];
if (blocksLayer == null) {
@ -100,11 +107,19 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator {
int y = MainUtil.y_loc[layer][j];
int z = sz + MainUtil.z_loc[layer][j];
try {
worldObj.setBlock(BlockVector3.at(x, y, z), block, sideEffectSet);
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());
@ -123,7 +138,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator {
CompoundTag tag = block.getNbtData();
StateWrapper sw = new StateWrapper(tag);
sw.restoreTag(worldObj.getName(), existing.getX(), existing.getY(),
sw.restoreTag(world.getName(), existing.getX(), existing.getY(),
existing.getZ());
}
}
@ -142,22 +157,27 @@ 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];
worldObj.setBiome(BlockVector3.at(x, y, z), biome);
world.setBiome(BlockVector3.at(x, y, z), biome);
}
}
if (localChunk.getTiles().size() > 0) {
localChunk.getTiles().forEach(((blockVector3, tag) -> {
try {
BaseBlock block = worldObj.getBlock(blockVector3).toBaseBlock(tag);
worldObj.setBlock(blockVector3, block, sideEffectSet);
BaseBlock block = world.getBlock(blockVector3).toBaseBlock(tag);
world.setBlock(blockVector3, block, sideEffectSet);
} catch (WorldEditException ignored) {
StateWrapper sw = new StateWrapper(tag);
sw.restoreTag(worldObj.getName(), blockVector3.getX(),
blockVector3.getY(), blockVector3.getZ());
sw.restoreTag(world.getName(), blockVector3.getX(), blockVector3.getY(),
blockVector3.getZ());
}
}));
}
});
};
}
chunkCoordinatorBuilderFactory.create(chunkCoordinatorFactory).inWorld(world)
.withChunks(getBlockChunks().keySet()).withInitialBatchSize(3).withMaxIterationTime(40)
.withThrowableConsumer(Throwable::printStackTrace).withFinalAction(whenDone)
.withConsumer(consumer);
return super.enqueue();
}

View File

@ -39,8 +39,6 @@ import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
@ -60,13 +58,21 @@ public class GenChunk extends ScopedQueueCoordinator {
public String world;
public int chunkX;
public int chunkZ;
@Getter @Setter private ChunkData chunkData = null;
private ChunkData chunkData = null;
public GenChunk() {
super(null, Location.at("", 0, 0, 0), Location.at("", 15, 255, 15));
this.biomes = Biome.values();
}
public ChunkData getChunkData() {
return this.chunkData;
}
public void setChunkData(ChunkData chunkData) {
this.chunkData = chunkData;
}
public Chunk getChunk() {
if (chunk == null) {
World worldObj = BukkitUtil.getWorld(world);

View File

@ -30,6 +30,8 @@ import com.google.inject.Singleton;
import com.plotsquared.bukkit.BukkitPlatform;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.generator.AugmentedUtils;
import com.plotsquared.core.inject.factory.ChunkCoordinatorBuilderFactory;
import com.plotsquared.core.inject.factory.ChunkCoordinatorFactory;
import com.plotsquared.core.location.Location;
import com.plotsquared.core.location.PlotLoc;
import com.plotsquared.core.plot.Plot;
@ -86,16 +88,17 @@ public class BukkitRegionManager extends RegionManager {
private static final Logger logger =
LoggerFactory.getLogger("P2/" + BukkitRegionManager.class.getSimpleName());
private final WorldUtil worldUtil;
private final ChunkCoordinatorFactory chunkCoordinatorFactory;
private final ChunkCoordinatorBuilderFactory chunkCoordinatorBuilderFactory;
@Inject public BukkitRegionManager(@Nonnull final ChunkManager chunkManager,
@Nonnull final WorldUtil worldUtil) {
super(chunkManager, worldUtil);
@Nonnull final WorldUtil worldUtil,
@Nonnull ChunkCoordinatorFactory chunkCoordinatorFactory,
@Nonnull ChunkCoordinatorBuilderFactory chunkCoordinatorBuilderFactory) {
super(chunkManager, worldUtil, chunkCoordinatorBuilderFactory);
this.worldUtil = worldUtil;
}
public static boolean isIn(CuboidRegion region, int x, int z) {
return x >= region.getMinimumPoint().getX() && x <= region.getMaximumPoint().getX()
&& z >= region.getMinimumPoint().getZ() && z <= region.getMaximumPoint().getZ();
this.chunkCoordinatorFactory = chunkCoordinatorFactory;
this.chunkCoordinatorBuilderFactory = chunkCoordinatorBuilderFactory;
}
@Override public Set<BlockVector2> getChunkChunks(String world) {
@ -207,37 +210,33 @@ public class BukkitRegionManager extends RegionManager {
return count;
}
@Override public boolean copyRegion(Location pos1, Location pos2, Location newPos,
@Override @Inject
public boolean copyRegion(final Location pos1, final Location pos2, final Location newPos,
final Runnable whenDone) {
final int relX = newPos.getX() - pos1.getX();
final int relZ = newPos.getZ() - pos1.getZ();
final CuboidRegion region =
RegionUtil.createRegion(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ());
final BukkitWorld oldWorld = new BukkitWorld((World) pos1.getWorld());
final com.sk89q.worldedit.world.World oldWorld = worldUtil.getWeWorld(pos1.getWorldName());
final BukkitWorld newWorld = new BukkitWorld((World) newPos.getWorld());
assert oldWorld.equals(newWorld);
final ContentMap map = new ContentMap();
final QueueCoordinator queue =
PlotSquared.platform().getGlobalBlockQueue().getNewQueue(newWorld, false);
ChunkManager.chunkTask(pos1, pos2, new RunnableVal<int[]>() {
@Override public void run(int[] value) {
int bx = value[2];
int bz = value[3];
int tx = value[4];
int tz = value[5];
BlockVector2 loc = BlockVector2.at(value[0], value[1]);
int cxx = loc.getX() << 4;
int czz = loc.getZ() << 4;
PaperLib.getChunkAtAsync(oldWorld, loc.getX(), loc.getZ())
.thenAccept(chunk1 -> map.saveEntitiesIn(chunk1, region)).thenRun(() -> {
for (int x = bx & 15; x <= (tx & 15); x++) {
for (int z = bz & 15; z <= (tz & 15); z++) {
map.saveBlocks(oldWorld, 256, cxx + x, czz + z, relX, relZ);
}
chunkCoordinatorBuilderFactory.create(chunkCoordinatorFactory).inWorld(newWorld)
.withRegion(pos1, pos2).withThrowableConsumer(Throwable::printStackTrace)
.withRegion(pos1, pos2).withInitialBatchSize(4).withMaxIterationTime(45)
.withConsumer(chunk -> {
int cbx = chunk.getX();
int cbz = chunk.getZ();
int bx = Math.max(pos1.getX() & 15, 0);
int bz = Math.max(pos1.getZ() & 15, 0);
int tx = Math.min(pos2.getX() & 15, 15);
int tz = Math.min(pos2.getZ() & 15, 15);
for (int x = bx; x <= tx; x++) {
for (int z = bz; z <= tz; z++) {
map.saveBlocks(newWorld, 256, cbx + x, cbz + z, relX, relZ);
}
});
}
}, () -> {
}
}).withFinalAction(() -> {
for (Entry<PlotLoc, BaseBlock[]> entry : map.allBlocks.entrySet()) {
PlotLoc loc = entry.getKey();
BaseBlock[] blocks = entry.getValue();
@ -250,17 +249,17 @@ public class BukkitRegionManager extends RegionManager {
}
queue.setCompleteTask(() -> {
//map.restoreBlocks(newWorld, 0, 0);
map.restoreEntities((World) newPos.getWorld(), relX, relZ);
map.restoreEntities(Bukkit.getWorld(newPos.getWorldName()), relX, relZ);
TaskManager.runTask(whenDone);
});
queue.enqueue();
}, 5);
});
return true;
}
@Override public boolean regenerateRegion(final Location pos1, final Location pos2,
@Override @Inject public boolean regenerateRegion(final Location pos1, final Location pos2,
final boolean ignoreAugment, final Runnable whenDone) {
final String world = pos1.getWorldName();
final BukkitWorld world = new BukkitWorld((World) pos1.getWorld());
final int p1x = pos1.getX();
final int p1z = pos1.getZ();
@ -278,137 +277,123 @@ public class BukkitRegionManager extends RegionManager {
chunks.add(BlockVector2.at(x, z));
}
}
final World worldObj = Bukkit.getWorld(world);
checkNotNull(worldObj, "Critical error during regeneration.");
final BukkitWorld bukkitWorldObj = new BukkitWorld(worldObj);
TaskManager.runTask(new Runnable() {
@Override public void run() {
long start = System.currentTimeMillis();
while (!chunks.isEmpty() && System.currentTimeMillis() - start < 5) {
final BlockVector2 chunk = chunks.remove(0);
int x = chunk.getX();
int z = chunk.getZ();
int xxb = x << 4;
int zzb = z << 4;
int xxt = xxb + 15;
int zzt = zzb + 15;
PaperLib.getChunkAtAsync(worldObj, x, z, false).thenAccept(chunkObj -> {
if (chunkObj == null) {
return;
}
final QueueCoordinator queue =
PlotSquared.platform().getGlobalBlockQueue().getNewQueue(world, false);
if (xxb >= p1x && xxt <= p2x && zzb >= p1z && zzt <= p2z) {
AugmentedUtils.bypass(ignoreAugment,
() -> queue.regenChunkSafe(chunk.getX(), chunk.getZ()));
return;
}
boolean checkX1 = false;
int xxb2;
final QueueCoordinator queue =
PlotSquared.platform().getGlobalBlockQueue().getNewQueue(world, false);
chunkCoordinatorBuilderFactory.create(chunkCoordinatorFactory).inWorld(world)
.withRegion(pos1, pos2).withThrowableConsumer(Throwable::printStackTrace)
.withRegion(pos1, pos2).withInitialBatchSize(4).withMaxIterationTime(45)
.withConsumer(chunk -> {
if (x == bcx) {
xxb2 = p1x - 1;
checkX1 = true;
} else {
xxb2 = xxb;
}
boolean checkX2 = false;
int xxt2;
if (x == tcx) {
xxt2 = p2x + 1;
checkX2 = true;
} else {
xxt2 = xxt;
}
boolean checkZ1 = false;
int zzb2;
if (z == bcz) {
zzb2 = p1z - 1;
checkZ1 = true;
} else {
zzb2 = zzb;
}
boolean checkZ2 = false;
int zzt2;
if (z == tcz) {
zzt2 = p2z + 1;
checkZ2 = true;
} else {
zzt2 = zzt;
}
final ContentMap map = new ContentMap();
if (checkX1) {
map.saveRegion(bukkitWorldObj, xxb, xxb2, zzb2, zzt2); //
}
if (checkX2) {
map.saveRegion(bukkitWorldObj, xxt2, xxt, zzb2, zzt2); //
}
if (checkZ1) {
map.saveRegion(bukkitWorldObj, xxb2, xxt2, zzb, zzb2); //
}
if (checkZ2) {
map.saveRegion(bukkitWorldObj, xxb2, xxt2, zzt2, zzt); //
}
if (checkX1 && checkZ1) {
map.saveRegion(bukkitWorldObj, xxb, xxb2, zzb, zzb2); //
}
if (checkX2 && checkZ1) {
map.saveRegion(bukkitWorldObj, xxt2, xxt, zzb, zzb2); // ?
}
if (checkX1 && checkZ2) {
map.saveRegion(bukkitWorldObj, xxb, xxb2, zzt2, zzt); // ?
}
if (checkX2 && checkZ2) {
map.saveRegion(bukkitWorldObj, xxt2, xxt, zzt2, zzt); //
}
CuboidRegion currentPlotClear = RegionUtil
.createRegion(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ());
map.saveEntitiesOut(chunkObj, currentPlotClear);
AugmentedUtils.bypass(ignoreAugment, () -> ChunkManager
.setChunkInPlotArea(null, new RunnableVal<ScopedQueueCoordinator>() {
@Override public void run(ScopedQueueCoordinator value) {
Location min = value.getMin();
int bx = min.getX();
int bz = min.getZ();
for (int x1 = 0; x1 < 16; x1++) {
for (int z1 = 0; z1 < 16; z1++) {
PlotLoc plotLoc = new PlotLoc(bx + x1, bz + z1);
BaseBlock[] ids = map.allBlocks.get(plotLoc);
if (ids != null) {
for (int y = 0;
y < Math.min(128, ids.length); y++) {
BaseBlock id = ids[y];
if (id != null) {
value.setBlock(x1, y, z1, id);
} else {
value.setBlock(x1, y, z1,
BlockTypes.AIR.getDefaultState());
}
}
for (int y = Math.min(128, ids.length);
y < ids.length; y++) {
BaseBlock id = ids[y];
if (id != null) {
value.setBlock(x1, y, z1, id);
}
}
int x = chunk.getX();
int z = chunk.getZ();
int xxb = x << 4;
int zzb = z << 4;
int xxt = xxb + 15;
int zzt = zzb + 15;
if (xxb >= p1x && xxt <= p2x && zzb >= p1z && zzt <= p2z) {
AugmentedUtils.bypass(ignoreAugment,
() -> queue.regenChunkSafe(chunk.getX(), chunk.getZ()));
return;
}
boolean checkX1 = false;
int xxb2;
if (x == bcx) {
xxb2 = p1x - 1;
checkX1 = true;
} else {
xxb2 = xxb;
}
boolean checkX2 = false;
int xxt2;
if (x == tcx) {
xxt2 = p2x + 1;
checkX2 = true;
} else {
xxt2 = xxt;
}
boolean checkZ1 = false;
int zzb2;
if (z == bcz) {
zzb2 = p1z - 1;
checkZ1 = true;
} else {
zzb2 = zzb;
}
boolean checkZ2 = false;
int zzt2;
if (z == tcz) {
zzt2 = p2z + 1;
checkZ2 = true;
} else {
zzt2 = zzt;
}
final ContentMap map = new ContentMap();
if (checkX1) {
map.saveRegion(world, xxb, xxb2, zzb2, zzt2); //
}
if (checkX2) {
map.saveRegion(world, xxt2, xxt, zzb2, zzt2); //
}
if (checkZ1) {
map.saveRegion(world, xxb2, xxt2, zzb, zzb2); //
}
if (checkZ2) {
map.saveRegion(world, xxb2, xxt2, zzt2, zzt); //
}
if (checkX1 && checkZ1) {
map.saveRegion(world, xxb, xxb2, zzb, zzb2); //
}
if (checkX2 && checkZ1) {
map.saveRegion(world, xxt2, xxt, zzb, zzb2); // ?
}
if (checkX1 && checkZ2) {
map.saveRegion(world, xxb, xxb2, zzt2, zzt); // ?
}
if (checkX2 && checkZ2) {
map.saveRegion(world, xxt2, xxt, zzt2, zzt); //
}
CuboidRegion currentPlotClear =
RegionUtil.createRegion(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ());
map.saveEntitiesOut(Bukkit.getWorld(world.getName()).getChunkAt(x, z),
currentPlotClear);
AugmentedUtils.bypass(ignoreAugment, () -> ChunkManager
.setChunkInPlotArea(null, new RunnableVal<ScopedQueueCoordinator>() {
@Override public void run(ScopedQueueCoordinator value) {
Location min = value.getMin();
int bx = min.getX();
int bz = min.getZ();
for (int x1 = 0; x1 < 16; x1++) {
for (int z1 = 0; z1 < 16; z1++) {
PlotLoc plotLoc = new PlotLoc(bx + x1, bz + z1);
BaseBlock[] ids = map.allBlocks.get(plotLoc);
if (ids != null) {
for (int y = 0; y < Math.min(128, ids.length); y++) {
BaseBlock id = ids[y];
if (id != null) {
value.setBlock(x1, y, z1, id);
} else {
value.setBlock(x1, y, z1,
BlockTypes.AIR.getDefaultState());
}
}
for (int y = Math.min(128, ids.length);
y < ids.length; y++) {
BaseBlock id = ids[y];
if (id != null) {
value.setBlock(x1, y, z1, id);
}
}
}
}
}, world, chunk));
//map.restoreBlocks(worldObj, 0, 0);
map.restoreEntities(worldObj, 0, 0);
});
}
if (!chunks.isEmpty()) {
TaskManager.runTaskLater(this, TaskTime.ticks(1L));
} else {
TaskManager.runTaskLater(whenDone, TaskTime.ticks(1L));
}
}
});
}
}
}, world.getName(), chunk));
//map.restoreBlocks(worldObj, 0, 0);
map.restoreEntities(Bukkit.getWorld(world.getName()), 0, 0);
}).withFinalAction(whenDone);
return true;
}
@ -471,19 +456,22 @@ public class BukkitRegionManager extends RegionManager {
region.getMinimumPoint().getY(), region.getMinimumPoint().getZ() - extendBiome);
Location pos2 = Location.at(world, region.getMaximumPoint().getX() + extendBiome,
region.getMaximumPoint().getY(), region.getMaximumPoint().getZ() + extendBiome);
final QueueCoordinator queue =
PlotSquared.platform().getGlobalBlockQueue().getNewQueue(world, false);
final QueueCoordinator queue = PlotSquared.platform().getGlobalBlockQueue()
.getNewQueue(worldUtil.getWeWorld(world), false);
ChunkManager.chunkTask(pos1, pos2, new RunnableVal<int[]>() {
@Override public void run(int[] value) {
BlockVector2 loc = BlockVector2.at(value[0], value[1]);
PlotSquared.platform().getChunkManager().loadChunk(world, loc, false)
.thenRun(() -> {
MainUtil.setBiome(world, value[2], value[3], value[4], value[5], biome);
queue.refreshChunk(value[0], value[1]);
});
}
}, whenDone, 5);
final int minX = pos1.getX();
final int minZ = pos1.getZ();
final int maxX = pos2.getX();
final int maxZ = pos2.getZ();
queue.setChunkConsumer(blockVector2 -> {
final int cx = blockVector2.getX() << 4;
final int cz = blockVector2.getZ() << 4;
MainUtil
.setBiome(world, Math.max(minX, cx), Math.max(minZ, cz), Math.min(maxX, cx + 15),
Math.min(maxZ, cz + 15), biome);
worldUtil.refreshChunk(blockVector2.getBlockX(), blockVector2.getBlockZ(), world);
});
queue.enqueue();
}
private void count(int[] count, Entity entity) {

View File

@ -111,15 +111,18 @@ import java.util.function.IntConsumer;
import java.util.stream.Stream;
@SuppressWarnings({"unused", "WeakerAccess"})
@Singleton public class BukkitUtil extends WorldUtil {
@Singleton
public class BukkitUtil extends WorldUtil {
private static final Logger logger = LoggerFactory.getLogger("P2/" + BukkitUtil.class.getSimpleName());
private static final Logger logger =
LoggerFactory.getLogger("P2/" + BukkitUtil.class.getSimpleName());
private static String lastString = null;
private static World lastWorld = null;
private static Player lastPlayer = null;
private static BukkitPlayer lastPlotPlayer = null;
private final Collection<BlockType> tileEntityTypes = new HashSet<>();
@Inject public BukkitUtil(@Nonnull final RegionManager regionManager) {
super(regionManager);
@ -139,7 +142,8 @@ import java.util.stream.Stream;
final Player player = OfflinePlayerUtil.loadPlayer(op);
player.loadData();
return new BukkitPlayer(PlotSquared.get().getPlotAreaManager(),
PlotSquared.get().getEventDispatcher(), player, true, PlotSquared.platform().getEconHandler());
PlotSquared.get().getEventDispatcher(), player, true,
PlotSquared.platform().getEconHandler());
}
/**
@ -194,18 +198,6 @@ import java.util.stream.Stream;
return PlotPlayer.wrap(player);
}
/**
* Gets the PlotPlayer for a UUID. The PlotPlayer is usually cached and
* will provide useful functions relating to players.
*
* @param uuid the uuid to wrap
* @return a {@code PlotPlayer}
* @see PlotPlayer#wrap(Object)
*/
@Override public PlotPlayer<?> wrapPlayer(UUID uuid) {
return PlotPlayer.wrap(Bukkit.getOfflinePlayer(uuid));
}
/**
* Gets the number of plots, which the player is able to build in.
*
@ -287,18 +279,19 @@ import java.util.stream.Stream;
public static Location getLocation(final org.bukkit.Location location) {
return Location.at(com.plotsquared.bukkit.util.BukkitWorld.of(location.getWorld()),
MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()), MathMan.roundInt(location.getZ()));
MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()),
MathMan.roundInt(location.getZ()));
}
public static Location getLocationFull(final org.bukkit.Location location) {
return Location.at(com.plotsquared.bukkit.util.BukkitWorld.of(location.getWorld()),
MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()), MathMan.roundInt(location.getZ()), location.getYaw(),
location.getPitch());
MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()),
MathMan.roundInt(location.getZ()), location.getYaw(), location.getPitch());
}
public static org.bukkit.Location getLocation(@Nonnull final Location location) {
return new org.bukkit.Location((World) location.getWorld().getPlatformWorld(), location.getX(),
location.getY(), location.getZ());
return new org.bukkit.Location((World) location.getWorld().getPlatformWorld(),
location.getX(), location.getY(), location.getZ());
}
public static World getWorld(@Nonnull final String string) {
@ -321,8 +314,7 @@ import java.util.stream.Stream;
public static Location getLocation(@Nonnull final Entity entity) {
final org.bukkit.Location location = entity.getLocation();
String world = location.getWorld().getName();
return Location.at(world, location.getBlockX(), location.getBlockY(),
location.getBlockZ());
return Location.at(world, location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
@Nonnull public static Location getLocationFull(@Nonnull final Entity entity) {
@ -336,6 +328,38 @@ import java.util.stream.Stream;
return BukkitAdapter.adapt(plotBlock.getBlockType());
}
private static void ensureLoaded(final String world, final int x, final int z,
final Consumer<Chunk> chunkConsumer) {
PaperLib.getChunkAtAsync(getWorld(world), x >> 4, z >> 4, true)
.thenAccept(chunk -> ensureMainThread(chunkConsumer, chunk));
}
private static void ensureLoaded(final Location location, final Consumer<Chunk> chunkConsumer) {
PaperLib.getChunkAtAsync(getLocation(location), true)
.thenAccept(chunk -> ensureMainThread(chunkConsumer, chunk));
}
private static <T> void ensureMainThread(final Consumer<T> consumer, final T value) {
if (Bukkit.isPrimaryThread()) {
consumer.accept(value);
} else {
Bukkit.getScheduler().runTask(BukkitPlatform.getPlugin(BukkitPlatform.class),
() -> consumer.accept(value));
}
}
/**
* Gets the PlotPlayer for a UUID. The PlotPlayer is usually cached and
* will provide useful functions relating to players.
*
* @param uuid the uuid to wrap
* @return a {@code PlotPlayer}
* @see PlotPlayer#wrap(Object)
*/
@Override public PlotPlayer<?> wrapPlayer(UUID uuid) {
return PlotPlayer.wrap(Bukkit.getOfflinePlayer(uuid));
}
@Override public boolean isBlockSame(BlockState block1, BlockState block2) {
if (block1.equals(block2)) {
return true;
@ -357,8 +381,7 @@ import java.util.stream.Stream;
return BukkitAdapter.adapt(getWorld(world).getBiome(x, z));
}
@Override
public void getHighestBlock(@Nonnull final String world, final int x, final int z,
@Override public void getHighestBlock(@Nonnull final String world, final int x, final int z,
final IntConsumer result) {
ensureLoaded(world, x, z, chunk -> {
final World bukkitWorld = getWorld(world);
@ -437,8 +460,9 @@ import java.util.stream.Stream;
@Override public Location getSpawn(@Nonnull final String world) {
final org.bukkit.Location temp = getWorld(world).getSpawnLocation();
return Location.at(world, temp.getBlockX(), temp.getBlockY(), temp.getBlockZ(),
temp.getYaw(), temp.getPitch());
return Location
.at(world, temp.getBlockX(), temp.getBlockY(), temp.getBlockZ(), temp.getYaw(),
temp.getPitch());
}
@Override public void setSpawn(@Nonnull final Location location) {
@ -518,7 +542,8 @@ import java.util.stream.Stream;
@Nonnull final BiomeType biomeType) {
final World world = getWorld(worldName);
if (world == null) {
logger.warn("[P2] An error occured while setting the biome because the world was null", new RuntimeException());
logger.warn("[P2] An error occured while setting the biome because the world was null",
new RuntimeException());
return;
}
final Biome biome = BukkitAdapter.adapt(biomeType);
@ -536,6 +561,10 @@ import java.util.stream.Stream;
return new BukkitWorld(Bukkit.getWorld(world));
}
@Override public void refreshChunk(int x, int z, String world) {
Bukkit.getWorld(world).refreshChunk(x, z);
}
@Override
public void getBlock(@Nonnull final Location location, final Consumer<BlockState> result) {
ensureLoaded(location, chunk -> {
@ -571,8 +600,7 @@ import java.util.stream.Stream;
Bukkit.getPlayer(player.getUUID()).setFoodLevel(foodLevel);
}
@Override
public Set<com.sk89q.worldedit.world.entity.EntityType> getTypesInCategory(
@Override public Set<com.sk89q.worldedit.world.entity.EntityType> getTypesInCategory(
final String category) {
final Collection<Class<?>> allowedInterfaces = new HashSet<>();
switch (category) {
@ -653,7 +681,6 @@ import java.util.stream.Stream;
return types;
}
private final Collection<BlockType> tileEntityTypes = new HashSet<>();
@Override public Collection<BlockType> getTileEntityTypes() {
if (this.tileEntityTypes.isEmpty()) {
// Categories
@ -665,44 +692,21 @@ import java.util.stream.Stream;
// Add these from strings
Stream.of("barrel", "beacon", "beehive", "bee_nest", "bell", "blast_furnace",
"brewing_stand", "campfire", "chest", "ender_chest", "trapped_chest",
"command_block", "end_gateway", "hopper", "jigsaw", "jubekox",
"lectern", "note_block", "black_shulker_box", "blue_shulker_box",
"brown_shulker_box", "cyan_shulker_box", "gray_shulker_box", "green_shulker_box",
"command_block", "end_gateway", "hopper", "jigsaw", "jubekox", "lectern",
"note_block", "black_shulker_box", "blue_shulker_box", "brown_shulker_box",
"cyan_shulker_box", "gray_shulker_box", "green_shulker_box",
"light_blue_shulker_box", "light_gray_shulker_box", "lime_shulker_box",
"magenta_shulker_box", "orange_shulker_box", "pink_shulker_box",
"purple_shulker_box", "red_shulker_box", "shulker_box", "white_shulker_box",
"yellow_shulker_box", "smoker", "structure_block", "structure_void")
.map(BlockTypes::get)
.filter(Objects::nonNull)
.forEach(tileEntityTypes::add);
.map(BlockTypes::get).filter(Objects::nonNull).forEach(tileEntityTypes::add);
}
return this.tileEntityTypes;
}
@Override
public int getTileEntityCount(String world, BlockVector2 chunk) {
@Override public int getTileEntityCount(String world, BlockVector2 chunk) {
return Bukkit.getWorld(world).getChunkAt(chunk.getBlockX(), chunk.getBlockZ())
.getTileEntities().length;
}
private static void ensureLoaded(final String world, final int x, final int z,
final Consumer<Chunk> chunkConsumer) {
PaperLib.getChunkAtAsync(getWorld(world), x >> 4, z >> 4, true)
.thenAccept(chunk -> ensureMainThread(chunkConsumer, chunk));
}
private static void ensureLoaded(final Location location, final Consumer<Chunk> chunkConsumer) {
PaperLib.getChunkAtAsync(getLocation(location), true)
.thenAccept(chunk -> ensureMainThread(chunkConsumer, chunk));
}
private static <T> void ensureMainThread(final Consumer<T> consumer, final T value) {
if (Bukkit.isPrimaryThread()) {
consumer.accept(value);
} else {
Bukkit.getScheduler()
.runTask(BukkitPlatform.getPlugin(BukkitPlatform.class), () -> consumer.accept(value));
}
}
}