mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2024-11-22 13:16:45 +01:00
begin new block setting/chunk pipeline
This will ultimately replace both the GlobalBlockQueue and the ChunkTask stuff
This commit is contained in:
parent
8eb903ad72
commit
def9a1bcf8
@ -26,7 +26,7 @@
|
|||||||
package com.plotsquared.bukkit.queue;
|
package com.plotsquared.bukkit.queue;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.plotsquared.bukkit.BukkitMain;
|
import com.plotsquared.bukkit.BukkitPlatform;
|
||||||
import com.sk89q.worldedit.math.BlockVector2;
|
import com.sk89q.worldedit.math.BlockVector2;
|
||||||
import io.papermc.lib.PaperLib;
|
import io.papermc.lib.PaperLib;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
@ -44,34 +44,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
public final class BukkitChunkCoordinator extends BukkitRunnable {
|
||||||
* 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 ChunkCoordinator extends BukkitRunnable {
|
|
||||||
|
|
||||||
private final List<ProgressSubscriber> progressSubscribers = new LinkedList<>();
|
|
||||||
|
|
||||||
private final Queue<BlockVector2> requestedChunks;
|
private final Queue<BlockVector2> requestedChunks;
|
||||||
private final Queue<Chunk> availableChunks;
|
private final Queue<Chunk> availableChunks;
|
||||||
@ -80,48 +53,32 @@ public final class ChunkCoordinator extends BukkitRunnable {
|
|||||||
private final Consumer<Chunk> chunkConsumer;
|
private final Consumer<Chunk> chunkConsumer;
|
||||||
private final World world;
|
private final World world;
|
||||||
private final Runnable whenDone;
|
private final Runnable whenDone;
|
||||||
private final Consumer<Throwable> throwableConsumer;
|
|
||||||
private final int totalSize;
|
|
||||||
|
|
||||||
private AtomicInteger expectedSize;
|
private AtomicInteger expectedSize;
|
||||||
private int batchSize;
|
private int batchSize;
|
||||||
|
|
||||||
private ChunkCoordinator(final long maxIterationTime, final int initialBatchSize,
|
private BukkitChunkCoordinator(final long maxIterationTime, final int initialBatchSize,
|
||||||
@NotNull final Consumer<Chunk> chunkConsumer, @NotNull final World world,
|
@NotNull final Consumer<Chunk> chunkConsumer, @NotNull final World world,
|
||||||
@NotNull final Collection<BlockVector2> requestedChunks, @NotNull final Runnable whenDone,
|
@NotNull final Collection<BlockVector2> requestedChunks, @NotNull final Runnable whenDone) {
|
||||||
@NotNull final Consumer<Throwable> throwableConsumer) {
|
|
||||||
this.requestedChunks = new LinkedBlockingQueue<>(requestedChunks);
|
this.requestedChunks = new LinkedBlockingQueue<>(requestedChunks);
|
||||||
this.availableChunks = new LinkedBlockingQueue<>();
|
this.availableChunks = new LinkedBlockingQueue<>();
|
||||||
this.totalSize = requestedChunks.size();
|
this.expectedSize = new AtomicInteger(requestedChunks.size());
|
||||||
this.expectedSize = new AtomicInteger(this.totalSize);
|
|
||||||
this.world = world;
|
this.world = world;
|
||||||
this.batchSize = initialBatchSize;
|
this.batchSize = initialBatchSize;
|
||||||
this.chunkConsumer = chunkConsumer;
|
this.chunkConsumer = chunkConsumer;
|
||||||
this.maxIterationTime = maxIterationTime;
|
this.maxIterationTime = maxIterationTime;
|
||||||
this.whenDone = whenDone;
|
this.whenDone = whenDone;
|
||||||
this.throwableConsumer = throwableConsumer;
|
this.plugin = JavaPlugin.getPlugin(BukkitPlatform.class);
|
||||||
this.plugin = JavaPlugin.getPlugin(BukkitMain.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link ChunkCoordinator} instance
|
|
||||||
*
|
|
||||||
* @return Coordinator builder instance
|
|
||||||
*/
|
|
||||||
@NotNull public static ChunkCoordinatorBuilder builder() {
|
|
||||||
return new ChunkCoordinatorBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the coordinator instance
|
|
||||||
*/
|
|
||||||
public void start() {
|
|
||||||
// Request initial batch
|
// Request initial batch
|
||||||
this.requestBatch();
|
this.requestBatch();
|
||||||
// Wait until next tick to give the chunks a chance to be loaded
|
// Wait until next tick to give the chunks a chance to be loaded
|
||||||
this.runTaskTimer(this.plugin, 1L, 1L);
|
this.runTaskTimer(this.plugin, 1L, 1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull public static ChunkCoordinatorBuilder builder() {
|
||||||
|
return new ChunkCoordinatorBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
Chunk chunk = this.availableChunks.poll();
|
Chunk chunk = this.availableChunks.poll();
|
||||||
if (chunk == null) {
|
if (chunk == null) {
|
||||||
@ -133,8 +90,7 @@ public final class ChunkCoordinator extends BukkitRunnable {
|
|||||||
final long start = System.currentTimeMillis();
|
final long start = System.currentTimeMillis();
|
||||||
try {
|
try {
|
||||||
this.chunkConsumer.accept(chunk);
|
this.chunkConsumer.accept(chunk);
|
||||||
} catch (final Throwable throwable) {
|
} catch (final Exception ignored) {
|
||||||
this.throwableConsumer.accept(throwable);
|
|
||||||
}
|
}
|
||||||
this.freeChunk(chunk);
|
this.freeChunk(chunk);
|
||||||
processedChunks++;
|
processedChunks++;
|
||||||
@ -147,19 +103,10 @@ public final class ChunkCoordinator extends BukkitRunnable {
|
|||||||
// Adjust batch size based on the amount of processed chunks per tick
|
// Adjust batch size based on the amount of processed chunks per tick
|
||||||
this.batchSize = processedChunks;
|
this.batchSize = processedChunks;
|
||||||
}
|
}
|
||||||
|
if (this.expectedSize.addAndGet(-processedChunks) <= 0) {
|
||||||
final int expected = this.expectedSize.addAndGet(-processedChunks);
|
|
||||||
|
|
||||||
final float progress = ((float) totalSize - (float) expected) / (float) totalSize;
|
|
||||||
for (final ProgressSubscriber subscriber : this.progressSubscribers) {
|
|
||||||
subscriber.notifyProgress(this, progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expected <= 0) {
|
|
||||||
try {
|
try {
|
||||||
this.whenDone.run();
|
this.whenDone.run();
|
||||||
} catch (final Throwable throwable) {
|
} catch (final Exception ignored) {
|
||||||
this.throwableConsumer.accept(throwable);
|
|
||||||
}
|
}
|
||||||
this.cancel();
|
this.cancel();
|
||||||
} else {
|
} else {
|
||||||
@ -203,52 +150,10 @@ public final class ChunkCoordinator extends BukkitRunnable {
|
|||||||
chunk.removePluginChunkTicket(this.plugin);
|
chunk.removePluginChunkTicket(this.plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the amount of remaining chunks (at the time of the method call)
|
|
||||||
*
|
|
||||||
* @return Snapshot view of remaining chunk count
|
|
||||||
*/
|
|
||||||
public int getRemainingChunks() {
|
|
||||||
return this.expectedSize.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the amount of requested chunks
|
|
||||||
*
|
|
||||||
* @return Requested chunk count
|
|
||||||
*/
|
|
||||||
public int getTotalChunks() {
|
|
||||||
return this.totalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscribe to coordinator progress updates
|
|
||||||
*
|
|
||||||
* @param subscriber Subscriber
|
|
||||||
*/
|
|
||||||
public void subscribeToProgress(@NotNull final ChunkCoordinator.ProgressSubscriber subscriber) {
|
|
||||||
this.progressSubscribers.add(subscriber);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface ProgressSubscriber {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify about a progress update in the coordinator
|
|
||||||
*
|
|
||||||
* @param coordinator Coordinator instance that triggered the notification
|
|
||||||
* @param progress Progress in the range [0, 1]
|
|
||||||
*/
|
|
||||||
void notifyProgress(@NotNull final ChunkCoordinator coordinator, final float progress);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static final class ChunkCoordinatorBuilder {
|
public static final class ChunkCoordinatorBuilder {
|
||||||
|
|
||||||
private final List<BlockVector2> requestedChunks = new LinkedList<>();
|
private final List<BlockVector2> requestedChunks = new LinkedList<>();
|
||||||
private Consumer<Throwable> throwableConsumer = Throwable::printStackTrace;
|
|
||||||
private World world;
|
private World world;
|
||||||
private Consumer<Chunk> chunkConsumer;
|
private Consumer<Chunk> chunkConsumer;
|
||||||
private Runnable whenDone = () -> {
|
private Runnable whenDone = () -> {
|
||||||
@ -303,22 +208,12 @@ public final class ChunkCoordinator extends BukkitRunnable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull public ChunkCoordinatorBuilder withThrowableConsumer(
|
@NotNull public BukkitChunkCoordinator build() {
|
||||||
@NotNull final Consumer<Throwable> throwableConsumer) {
|
|
||||||
this.throwableConsumer =
|
|
||||||
Preconditions.checkNotNull(throwableConsumer, "Throwable consumer may not be null");
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull public ChunkCoordinator build() {
|
|
||||||
Preconditions.checkNotNull(this.world, "No world was supplied");
|
Preconditions.checkNotNull(this.world, "No world was supplied");
|
||||||
Preconditions.checkNotNull(this.chunkConsumer, "No chunk consumer was supplied");
|
Preconditions.checkNotNull(this.chunkConsumer, "No chunk consumer was supplied");
|
||||||
Preconditions.checkNotNull(this.whenDone, "No final action was supplied");
|
Preconditions.checkNotNull(this.whenDone, "No final action was supplied");
|
||||||
Preconditions
|
return new BukkitChunkCoordinator(this.maxIterationTime, this.initialBatchSize,
|
||||||
.checkNotNull(this.throwableConsumer, "No throwable consumer was supplied");
|
this.chunkConsumer, this.world, this.requestedChunks, this.whenDone);
|
||||||
return new ChunkCoordinator(this.maxIterationTime, this.initialBatchSize,
|
|
||||||
this.chunkConsumer, this.world, this.requestedChunks, this.whenDone,
|
|
||||||
this.throwableConsumer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* _____ _ _ _____ _
|
||||||
|
* | __ \| | | | / ____| | |
|
||||||
|
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
|
||||||
|
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
|
||||||
|
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
|
||||||
|
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
|
||||||
|
* | |
|
||||||
|
* |_|
|
||||||
|
* PlotSquared plot management system for Minecraft
|
||||||
|
* Copyright (C) 2020 IntellectualSites
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.plotsquared.bukkit.queue;
|
||||||
|
|
||||||
|
import com.plotsquared.bukkit.util.BukkitBlockUtil;
|
||||||
|
import com.plotsquared.core.queue.BasicQueueCoordinator;
|
||||||
|
import com.plotsquared.core.util.BlockUtil;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
|
||||||
|
public class BukkitQueueCoordinator extends BasicQueueCoordinator {
|
||||||
|
|
||||||
|
public BukkitQueueCoordinator(String world) {
|
||||||
|
super(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public BlockState getBlock(int x, int y, int z) {
|
||||||
|
World worldObj = Bukkit.getWorld(getWorld());
|
||||||
|
if (worldObj != null) {
|
||||||
|
Block block = worldObj.getBlockAt(x, y, z);
|
||||||
|
return BukkitBlockUtil.get(block);
|
||||||
|
} else {
|
||||||
|
return BlockUtil.get(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* _____ _ _ _____ _
|
||||||
|
* | __ \| | | | / ____| | |
|
||||||
|
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
|
||||||
|
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
|
||||||
|
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
|
||||||
|
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
|
||||||
|
* | |
|
||||||
|
* |_|
|
||||||
|
* PlotSquared plot management system for Minecraft
|
||||||
|
* Copyright (C) 2020 IntellectualSites
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.plotsquared.core.inject.annotations;
|
||||||
|
|
||||||
|
import com.google.inject.BindingAnnotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target({ElementType.PARAMETER, ElementType.FIELD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@BindingAnnotation
|
||||||
|
public @interface QueuePipeline {
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* _____ _ _ _____ _
|
||||||
|
* | __ \| | | | / ____| | |
|
||||||
|
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
|
||||||
|
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
|
||||||
|
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
|
||||||
|
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
|
||||||
|
* | |
|
||||||
|
* |_|
|
||||||
|
* PlotSquared plot management system for Minecraft
|
||||||
|
* Copyright (C) 2020 IntellectualSites
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.plotsquared.core.inject.factory;
|
||||||
|
|
||||||
|
import com.plotsquared.core.queue.QueueCoordinator;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
public interface QueueCoordinatorFactory {
|
||||||
|
|
||||||
|
@Nonnull QueueCoordinator create();
|
||||||
|
|
||||||
|
}
|
@ -26,22 +26,23 @@
|
|||||||
package com.plotsquared.core.queue;
|
package com.plotsquared.core.queue;
|
||||||
|
|
||||||
import com.plotsquared.core.plot.PlotArea;
|
import com.plotsquared.core.plot.PlotArea;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class AreaBoundDelegateLocalBlockQueue extends DelegateLocalBlockQueue {
|
public class AreaBoundDelegateQueueCoordinator extends DelegateQueueCoordinator {
|
||||||
|
|
||||||
@Getter private final PlotArea area;
|
@Getter private final PlotArea area;
|
||||||
|
|
||||||
public AreaBoundDelegateLocalBlockQueue(@Nonnull final PlotArea area,
|
public AreaBoundDelegateQueueCoordinator(@Nonnull final PlotArea area,
|
||||||
@Nullable final LocalBlockQueue parent) {
|
@Nullable final QueueCoordinator parent) {
|
||||||
super(parent);
|
super(parent);
|
||||||
this.area = Objects.requireNonNull(area);
|
this.area = Objects.requireNonNull(area);
|
||||||
}
|
}
|
||||||
@ -74,4 +75,11 @@ public class AreaBoundDelegateLocalBlockQueue extends DelegateLocalBlockQueue {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||||
|
if (area.contains(x, z)) {
|
||||||
|
return super.setTile(x, y, z, tag);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,272 +0,0 @@
|
|||||||
/*
|
|
||||||
* _____ _ _ _____ _
|
|
||||||
* | __ \| | | | / ____| | |
|
|
||||||
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
|
|
||||||
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
|
|
||||||
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
|
|
||||||
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
|
|
||||||
* | |
|
|
||||||
* |_|
|
|
||||||
* PlotSquared plot management system for Minecraft
|
|
||||||
* Copyright (C) 2020 IntellectualSites
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.plotsquared.core.queue;
|
|
||||||
|
|
||||||
import com.plotsquared.core.util.MainUtil;
|
|
||||||
import com.plotsquared.core.util.MathMan;
|
|
||||||
import com.plotsquared.core.util.PatternUtil;
|
|
||||||
import com.plotsquared.core.util.task.RunnableVal;
|
|
||||||
import com.plotsquared.core.util.task.TaskManager;
|
|
||||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
|
|
||||||
public abstract class BasicLocalBlockQueue extends LocalBlockQueue {
|
|
||||||
|
|
||||||
private final String world;
|
|
||||||
private final ConcurrentHashMap<Long, LocalChunk> blockChunks = new ConcurrentHashMap<>();
|
|
||||||
private final ConcurrentLinkedDeque<LocalChunk> chunks = new ConcurrentLinkedDeque<>();
|
|
||||||
private long modified;
|
|
||||||
private LocalChunk lastWrappedChunk;
|
|
||||||
private int lastX = Integer.MIN_VALUE;
|
|
||||||
private int lastZ = Integer.MIN_VALUE;
|
|
||||||
private boolean setbiome = false;
|
|
||||||
|
|
||||||
private GlobalBlockQueue globalBlockQueue;
|
|
||||||
|
|
||||||
public BasicLocalBlockQueue(String world) {
|
|
||||||
super(world);
|
|
||||||
this.world = world;
|
|
||||||
this.modified = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract LocalChunk getLocalChunk(int x, int z);
|
|
||||||
|
|
||||||
@Override public abstract BlockState getBlock(int x, int y, int z);
|
|
||||||
|
|
||||||
public abstract void setComponents(LocalChunk lc)
|
|
||||||
throws ExecutionException, InterruptedException;
|
|
||||||
|
|
||||||
@Override public final String getWorld() {
|
|
||||||
return world;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public final boolean next() {
|
|
||||||
lastX = Integer.MIN_VALUE;
|
|
||||||
lastZ = Integer.MIN_VALUE;
|
|
||||||
try {
|
|
||||||
if (this.blockChunks.size() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
synchronized (blockChunks) {
|
|
||||||
LocalChunk chunk = chunks.poll();
|
|
||||||
if (chunk != null) {
|
|
||||||
blockChunks.remove(chunk.longHash());
|
|
||||||
return this.execute(chunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean execute(@Nonnull LocalChunk lc)
|
|
||||||
throws ExecutionException, InterruptedException {
|
|
||||||
this.setComponents(lc);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void startSet(boolean parallel) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void endSet(boolean parallel) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public final int size() {
|
|
||||||
return chunks.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public final long getModified() {
|
|
||||||
return modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public final void setModified(long modified) {
|
|
||||||
this.modified = modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean setBlock(int x, int y, int z, @Nonnull Pattern pattern) {
|
|
||||||
return setBlock(x, y, z, PatternUtil.apply(pattern, x, y, z));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean setBlock(int x, int y, int z, BaseBlock id) {
|
|
||||||
if ((y > 255) || (y < 0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int cx = x >> 4;
|
|
||||||
int cz = z >> 4;
|
|
||||||
if (cx != lastX || cz != lastZ) {
|
|
||||||
lastX = cx;
|
|
||||||
lastZ = cz;
|
|
||||||
long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL;
|
|
||||||
lastWrappedChunk = this.blockChunks.get(pair);
|
|
||||||
if (lastWrappedChunk == null) {
|
|
||||||
lastWrappedChunk = this.getLocalChunk(x >> 4, z >> 4);
|
|
||||||
lastWrappedChunk.setBlock(x & 15, y, z & 15, id);
|
|
||||||
LocalChunk previous = this.blockChunks.put(pair, lastWrappedChunk);
|
|
||||||
if (previous == null) {
|
|
||||||
return chunks.add(lastWrappedChunk);
|
|
||||||
}
|
|
||||||
this.blockChunks.put(pair, previous);
|
|
||||||
lastWrappedChunk = previous;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastWrappedChunk.setBlock(x & 15, y, z & 15, id);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean setBlock(int x, int y, int z, BlockState id) {
|
|
||||||
// Trying to mix BlockState and BaseBlock leads to all kinds of issues.
|
|
||||||
// Since BaseBlock has more features than BlockState, simply convert
|
|
||||||
// all BlockStates to BaseBlocks
|
|
||||||
return setBlock(x, y, z, id.toBaseBlock());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public final boolean setBiome(int x, int z, BiomeType biomeType) {
|
|
||||||
long pair = (long) (x >> 4) << 32 | (z >> 4) & 0xFFFFFFFFL;
|
|
||||||
LocalChunk result = this.blockChunks.get(pair);
|
|
||||||
if (result == null) {
|
|
||||||
result = this.getLocalChunk(x >> 4, z >> 4);
|
|
||||||
LocalChunk previous = this.blockChunks.put(pair, result);
|
|
||||||
if (previous != null) {
|
|
||||||
this.blockChunks.put(pair, previous);
|
|
||||||
result = previous;
|
|
||||||
} else {
|
|
||||||
chunks.add(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.setBiome(x & 15, z & 15, biomeType);
|
|
||||||
setbiome = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public final boolean setBiome() {
|
|
||||||
return setbiome;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void setChunk(LocalChunk chunk) {
|
|
||||||
LocalChunk previous = this.blockChunks.put(chunk.longHash(), chunk);
|
|
||||||
if (previous != null) {
|
|
||||||
chunks.remove(previous);
|
|
||||||
}
|
|
||||||
chunks.add(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void flush() {
|
|
||||||
this.globalBlockQueue.dequeue(this);
|
|
||||||
TaskManager.getImplementation().sync(new RunnableVal<Object>() {
|
|
||||||
@Override public void run(Object value) {
|
|
||||||
while (next()) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class LocalChunk {
|
|
||||||
public final BasicLocalBlockQueue parent;
|
|
||||||
public final int z;
|
|
||||||
public final int x;
|
|
||||||
|
|
||||||
public BaseBlock[][] baseblocks;
|
|
||||||
public BiomeType[][] biomes;
|
|
||||||
|
|
||||||
public LocalChunk(BasicLocalBlockQueue parent, int x, int z) {
|
|
||||||
this.parent = parent;
|
|
||||||
this.x = x;
|
|
||||||
this.z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the parent queue this chunk belongs to
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public BasicLocalBlockQueue getParent() {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getX() {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getZ() {
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void setBlock(final int x, final int y, final int z, final BaseBlock block);
|
|
||||||
|
|
||||||
public void setBiome(int x, int z, BiomeType biomeType) {
|
|
||||||
if (this.biomes == null) {
|
|
||||||
this.biomes = new BiomeType[16][];
|
|
||||||
}
|
|
||||||
BiomeType[] index = this.biomes[x];
|
|
||||||
if (index == null) {
|
|
||||||
index = this.biomes[x] = new BiomeType[16];
|
|
||||||
}
|
|
||||||
index[z] = biomeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long longHash() {
|
|
||||||
return MathMan.pairInt(x, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int hashCode() {
|
|
||||||
return MathMan.pair((short) x, (short) z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class BasicLocalChunk extends LocalChunk {
|
|
||||||
|
|
||||||
public BasicLocalChunk(BasicLocalBlockQueue parent, int x, int z) {
|
|
||||||
super(parent, x, z);
|
|
||||||
baseblocks = new BaseBlock[16][];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void setBlock(int x, int y, int z, BaseBlock block) {
|
|
||||||
this.setInternal(x, y, z, block);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setInternal(final int x, final int y, final int z, final BaseBlock baseBlock) {
|
|
||||||
final int i = MainUtil.CACHE_I[y][x][z];
|
|
||||||
final int j = MainUtil.CACHE_J[y][x][z];
|
|
||||||
BaseBlock[] array = baseblocks[i];
|
|
||||||
if (array == null) {
|
|
||||||
array = (baseblocks[i] = new BaseBlock[4096]);
|
|
||||||
}
|
|
||||||
array[j] = baseBlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* _____ _ _ _____ _
|
||||||
|
* | __ \| | | | / ____| | |
|
||||||
|
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
|
||||||
|
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
|
||||||
|
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
|
||||||
|
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
|
||||||
|
* | |
|
||||||
|
* |_|
|
||||||
|
* PlotSquared plot management system for Minecraft
|
||||||
|
* Copyright (C) 2020 IntellectualSites
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.plotsquared.core.queue;
|
||||||
|
|
||||||
|
import com.plotsquared.core.util.PatternUtil;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public abstract class BasicQueueCoordinator extends QueueCoordinator {
|
||||||
|
|
||||||
|
private final String world;
|
||||||
|
private final ConcurrentHashMap<Long, LocalChunk> blockChunks = new ConcurrentHashMap<>();
|
||||||
|
private long modified;
|
||||||
|
private LocalChunk lastWrappedChunk;
|
||||||
|
private int lastX = Integer.MIN_VALUE;
|
||||||
|
private int lastZ = Integer.MIN_VALUE;
|
||||||
|
private boolean setbiome = false;
|
||||||
|
|
||||||
|
private GlobalBlockQueue globalBlockQueue;
|
||||||
|
|
||||||
|
public BasicQueueCoordinator(String world) {
|
||||||
|
this.world = world;
|
||||||
|
this.modified = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalChunk getLocalChunk(int x, int z) {
|
||||||
|
return new LocalChunk(this, x, z) {
|
||||||
|
// Allow implementation-specific custom stuff here
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public abstract BlockState getBlock(int x, int y, int z);
|
||||||
|
|
||||||
|
@Override public final String getWorld() {
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public final int size() {
|
||||||
|
return blockChunks.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public final void setModified(long modified) {
|
||||||
|
this.modified = modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean setBlock(int x, int y, int z, @Nonnull Pattern pattern) {
|
||||||
|
return setBlock(x, y, z, PatternUtil.apply(pattern, x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean setBlock(int x, int y, int z, BaseBlock id) {
|
||||||
|
if ((y > 255) || (y < 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LocalChunk chunk = getChunk(x >> 4, z >> 4);
|
||||||
|
chunk.setBlock(x & 15, y, z & 15, id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean setBlock(int x, int y, int z, BlockState id) {
|
||||||
|
// Trying to mix BlockState and BaseBlock leads to all kinds of issues.
|
||||||
|
// Since BaseBlock has more features than BlockState, simply convert
|
||||||
|
// all BlockStates to BaseBlocks
|
||||||
|
return setBlock(x, y, z, id.toBaseBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public final boolean setBiome(int x, int z, BiomeType biomeType) {
|
||||||
|
LocalChunk chunk = getChunk(x >> 4, z >> 4);
|
||||||
|
chunk.setBiome(x & 15, z & 15, biomeType);
|
||||||
|
setbiome = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public final boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||||
|
LocalChunk chunk = getChunk(x >> 4, z >> 4);
|
||||||
|
chunk.setTile(x, y, z, tag);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public final boolean settingBiome() {
|
||||||
|
return setbiome;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setChunk(LocalChunk chunk) {
|
||||||
|
this.blockChunks.put(chunk.longHash(), chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocalChunk getChunk(final int chunkX, final int ChunkZ) {
|
||||||
|
if (chunkX != lastX || ChunkZ != lastZ) {
|
||||||
|
lastX = chunkX;
|
||||||
|
lastZ = ChunkZ;
|
||||||
|
long pair = (long) (chunkX) << 32 | (ChunkZ) & 0xFFFFFFFFL;
|
||||||
|
lastWrappedChunk = this.blockChunks.get(pair);
|
||||||
|
if (lastWrappedChunk == null) {
|
||||||
|
lastWrappedChunk = this.getLocalChunk(chunkX, ChunkZ);
|
||||||
|
LocalChunk previous = this.blockChunks.put(pair, lastWrappedChunk);
|
||||||
|
if (previous == null) {
|
||||||
|
return lastWrappedChunk;
|
||||||
|
}
|
||||||
|
lastWrappedChunk = previous;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lastWrappedChunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -31,26 +31,24 @@ import com.sk89q.worldedit.math.BlockVector3;
|
|||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class ChunkBlockQueue extends ScopedLocalBlockQueue {
|
public class ChunkQueueCoordinator extends ScopedQueueCoordinator {
|
||||||
|
|
||||||
public final BiomeType[] biomeGrid;
|
public final BiomeType[] biomeGrid;
|
||||||
public final BlockState[][][] result;
|
public final BlockState[][][] result;
|
||||||
private final int width;
|
private final int width;
|
||||||
private final int length;
|
private final int length;
|
||||||
@Deprecated private final int area;
|
|
||||||
private final BlockVector3 bot;
|
private final BlockVector3 bot;
|
||||||
private final BlockVector3 top;
|
private final BlockVector3 top;
|
||||||
|
|
||||||
public ChunkBlockQueue(BlockVector3 bot, BlockVector3 top, boolean biomes) {
|
public ChunkQueueCoordinator(BlockVector3 bot, BlockVector3 top, boolean biomes) {
|
||||||
super(null, Location.at("", 0, 0, 0), Location.at("", 15, 255, 15));
|
super(null, Location.at("", 0, 0, 0), Location.at("", 15, 255, 15));
|
||||||
this.width = top.getX() - bot.getX() + 1;
|
this.width = top.getX() - bot.getX() + 1;
|
||||||
this.length = top.getZ() - bot.getZ() + 1;
|
this.length = top.getZ() - bot.getZ() + 1;
|
||||||
this.area = width * length;
|
|
||||||
this.result = new BlockState[256][][];
|
this.result = new BlockState[256][][];
|
||||||
this.biomeGrid = biomes ? new BiomeType[width * length] : null;
|
this.biomeGrid = biomes ? new BiomeType[width * length] : null;
|
||||||
this.bot = bot;
|
this.bot = bot;
|
@ -25,45 +25,32 @@
|
|||||||
*/
|
*/
|
||||||
package com.plotsquared.core.queue;
|
package com.plotsquared.core.queue;
|
||||||
|
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
public class DelegateLocalBlockQueue extends LocalBlockQueue {
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
private final LocalBlockQueue parent;
|
public class DelegateQueueCoordinator extends QueueCoordinator {
|
||||||
|
|
||||||
public DelegateLocalBlockQueue(LocalBlockQueue parent) {
|
private final QueueCoordinator parent;
|
||||||
super(parent == null ? null : parent.getWorld());
|
|
||||||
|
public DelegateQueueCoordinator(QueueCoordinator parent) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
this.setForceSync(parent.isForceSync());
|
this.setForceSync(parent.isForceSync());
|
||||||
this.setChunkObject(parent.getChunkObject());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalBlockQueue getParent() {
|
public QueueCoordinator getParent() {
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean next() {
|
|
||||||
return parent.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void startSet(boolean parallel) {
|
|
||||||
if (parent != null) {
|
|
||||||
parent.startSet(parallel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void endSet(boolean parallel) {
|
|
||||||
if (parent != null) {
|
|
||||||
parent.endSet(parallel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int size() {
|
@Override public int size() {
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
return parent.size();
|
return parent.size();
|
||||||
@ -71,19 +58,6 @@ public class DelegateLocalBlockQueue extends LocalBlockQueue {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void optimize() {
|
|
||||||
if (parent != null) {
|
|
||||||
parent.optimize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public long getModified() {
|
|
||||||
if (parent != null) {
|
|
||||||
return parent.getModified();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void setModified(long modified) {
|
@Override public void setModified(long modified) {
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
parent.setModified(modified);
|
parent.setModified(modified);
|
||||||
@ -110,36 +84,16 @@ public class DelegateLocalBlockQueue extends LocalBlockQueue {
|
|||||||
return parent.setBiome(x, z, biome);
|
return parent.setBiome(x, z, biome);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean setBiome() {
|
@Override public boolean settingBiome() {
|
||||||
return parent.setBiome();
|
return parent.settingBiome();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public String getWorld() {
|
@Override public String getWorld() {
|
||||||
return parent.getWorld();
|
return parent.getWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void flush() {
|
@Override public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||||
if (parent != null) {
|
return parent.setTile(x, y, z, tag);
|
||||||
parent.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void refreshChunk(int x, int z) {
|
|
||||||
if (parent != null) {
|
|
||||||
parent.refreshChunk(x, z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void fixChunkLighting(int x, int z) {
|
|
||||||
if (parent != null) {
|
|
||||||
parent.fixChunkLighting(x, z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void regenChunk(int x, int z) {
|
|
||||||
if (parent != null) {
|
|
||||||
parent.regenChunk(x, z);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean enqueue() {
|
@Override public boolean enqueue() {
|
@ -25,169 +25,21 @@
|
|||||||
*/
|
*/
|
||||||
package com.plotsquared.core.queue;
|
package com.plotsquared.core.queue;
|
||||||
|
|
||||||
import com.plotsquared.core.PlotSquared;
|
import lombok.Getter;
|
||||||
import com.plotsquared.core.util.task.RunnableVal2;
|
import lombok.Setter;
|
||||||
import com.plotsquared.core.util.task.TaskManager;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.ConcurrentModificationException;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
public class GlobalBlockQueue {
|
public class GlobalBlockQueue {
|
||||||
|
|
||||||
private final int PARALLEL_THREADS;
|
private final ConcurrentLinkedDeque<QueueCoordinator> activeQueues;
|
||||||
private final ConcurrentLinkedDeque<LocalBlockQueue> activeQueues;
|
@Getter @Setter private QueueProvider provider;
|
||||||
private final ConcurrentLinkedDeque<LocalBlockQueue> inactiveQueues;
|
|
||||||
private final ConcurrentLinkedDeque<Runnable> runnables;
|
|
||||||
private final AtomicBoolean running;
|
|
||||||
private final int targetTime;
|
|
||||||
private QueueProvider provider;
|
|
||||||
/**
|
|
||||||
* Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the
|
|
||||||
* server
|
|
||||||
*/
|
|
||||||
private long last;
|
|
||||||
private long secondLast;
|
|
||||||
private long lastSuccess;
|
|
||||||
private double lastPeriod = 0;
|
|
||||||
private final RunnableVal2<Long, LocalBlockQueue> SET_TASK =
|
|
||||||
new RunnableVal2<Long, LocalBlockQueue>() {
|
|
||||||
@Override public void run(Long free, LocalBlockQueue queue) {
|
|
||||||
do {
|
|
||||||
boolean more = queue.next();
|
|
||||||
if (!more) {
|
|
||||||
lastSuccess = last;
|
|
||||||
if (inactiveQueues.size() == 0 && activeQueues.size() == 0) {
|
|
||||||
runEmptyTasks();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} while ((lastPeriod =
|
|
||||||
((GlobalBlockQueue.this.secondLast = System.currentTimeMillis())
|
|
||||||
- GlobalBlockQueue.this.last)) < free);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public GlobalBlockQueue(QueueProvider provider, int threads, int targetTime) {
|
public GlobalBlockQueue(QueueProvider provider) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.activeQueues = new ConcurrentLinkedDeque<>();
|
this.activeQueues = new ConcurrentLinkedDeque<>();
|
||||||
this.inactiveQueues = new ConcurrentLinkedDeque<>();
|
|
||||||
this.runnables = new ConcurrentLinkedDeque<>();
|
|
||||||
this.running = new AtomicBoolean();
|
|
||||||
this.targetTime = targetTime;
|
|
||||||
this.PARALLEL_THREADS = threads;
|
|
||||||
}
|
|
||||||
|
|
||||||
public QueueProvider getProvider() {
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProvider(QueueProvider provider) {
|
|
||||||
this.provider = provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalBlockQueue getNewQueue(String world, boolean autoQueue) {
|
|
||||||
LocalBlockQueue queue = provider.getNewQueue(world);
|
|
||||||
// Auto-inject into the queue
|
|
||||||
PlotSquared.platform().getInjector().injectMembers(queue);
|
|
||||||
if (autoQueue) {
|
|
||||||
inactiveQueues.add(queue);
|
|
||||||
}
|
|
||||||
return queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean stop() {
|
|
||||||
if (!running.get()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
running.set(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean runTask() {
|
|
||||||
if (running.get()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
running.set(true);
|
|
||||||
TaskManager.runTaskRepeat(new Runnable() {
|
|
||||||
@Override public void run() {
|
|
||||||
if (inactiveQueues.isEmpty() && activeQueues.isEmpty()) {
|
|
||||||
lastSuccess = System.currentTimeMillis();
|
|
||||||
lastPeriod = 0;
|
|
||||||
GlobalBlockQueue.this.runEmptyTasks();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Server laggy? Skip.
|
|
||||||
if (lastPeriod > targetTime) {
|
|
||||||
lastPeriod -= targetTime;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SET_TASK.value1 = 50 + Math.min(
|
|
||||||
(50 + GlobalBlockQueue.this.last) - (GlobalBlockQueue.this.last =
|
|
||||||
System.currentTimeMillis()),
|
|
||||||
GlobalBlockQueue.this.secondLast - System.currentTimeMillis());
|
|
||||||
SET_TASK.value2 = GlobalBlockQueue.this.getNextQueue();
|
|
||||||
if (SET_TASK.value2 == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!PlotSquared.get().isMainThread(Thread.currentThread())) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"This shouldn't be possible for placement to occur off the main thread");
|
|
||||||
}
|
|
||||||
// Disable the async catcher as it can't discern async vs parallel
|
|
||||||
SET_TASK.value2.startSet(true);
|
|
||||||
try {
|
|
||||||
if (PARALLEL_THREADS <= 1) {
|
|
||||||
SET_TASK.run();
|
|
||||||
} else {
|
|
||||||
ArrayList<Thread> threads = new ArrayList<>();
|
|
||||||
for (int i = 0; i < PARALLEL_THREADS; i++) {
|
|
||||||
threads.add(new Thread(SET_TASK));
|
|
||||||
}
|
|
||||||
for (Thread thread : threads) {
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
for (Thread thread : threads) {
|
|
||||||
try {
|
|
||||||
thread.join();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
// Enable it again (note that we are still on the main thread)
|
|
||||||
SET_TASK.value2.endSet(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public QueueStage getStage(LocalBlockQueue queue) {
|
|
||||||
if (activeQueues.contains(queue)) {
|
|
||||||
return QueueStage.ACTIVE;
|
|
||||||
} else if (inactiveQueues.contains(queue)) {
|
|
||||||
return QueueStage.INACTIVE;
|
|
||||||
}
|
|
||||||
return QueueStage.NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isStage(LocalBlockQueue queue, QueueStage stage) {
|
|
||||||
switch (stage) {
|
|
||||||
case ACTIVE:
|
|
||||||
return activeQueues.contains(queue);
|
|
||||||
case INACTIVE:
|
|
||||||
return inactiveQueues.contains(queue);
|
|
||||||
case NONE:
|
|
||||||
return !activeQueues.contains(queue) && !inactiveQueues.contains(queue);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,155 +48,23 @@ public class GlobalBlockQueue {
|
|||||||
* @param queue todo
|
* @param queue todo
|
||||||
* @return true if added to queue, false otherwise
|
* @return true if added to queue, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean enqueue(LocalBlockQueue queue) {
|
public boolean enqueue(QueueCoordinator queue) {
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
success = inactiveQueues.remove(queue);
|
|
||||||
if (queue.size() > 0 && !activeQueues.contains(queue)) {
|
if (queue.size() > 0 && !activeQueues.contains(queue)) {
|
||||||
queue.optimize();
|
|
||||||
success = activeQueues.add(queue);
|
success = activeQueues.add(queue);
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dequeue(LocalBlockQueue queue) {
|
public void dequeue(QueueCoordinator queue) {
|
||||||
inactiveQueues.remove(queue);
|
|
||||||
activeQueues.remove(queue);
|
activeQueues.remove(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<LocalBlockQueue> getAllQueues() {
|
public List<QueueCoordinator> getActiveQueues() {
|
||||||
ArrayList<LocalBlockQueue> list =
|
|
||||||
new ArrayList<>(activeQueues.size() + inactiveQueues.size());
|
|
||||||
list.addAll(inactiveQueues);
|
|
||||||
list.addAll(activeQueues);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<LocalBlockQueue> getActiveQueues() {
|
|
||||||
return new ArrayList<>(activeQueues);
|
return new ArrayList<>(activeQueues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<LocalBlockQueue> getInactiveQueues() {
|
|
||||||
return new ArrayList<>(inactiveQueues);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flush(LocalBlockQueue queue) {
|
|
||||||
SET_TASK.value1 = Long.MAX_VALUE;
|
|
||||||
SET_TASK.value2 = queue;
|
|
||||||
if (SET_TASK.value2 == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (PlotSquared.get().isMainThread(Thread.currentThread())) {
|
|
||||||
throw new IllegalStateException("Must be flushed on the main thread!");
|
|
||||||
}
|
|
||||||
// Disable the async catcher as it can't discern async vs parallel
|
|
||||||
SET_TASK.value2.startSet(true);
|
|
||||||
try {
|
|
||||||
if (PARALLEL_THREADS <= 1) {
|
|
||||||
SET_TASK.run();
|
|
||||||
} else {
|
|
||||||
ArrayList<Thread> threads = new ArrayList<>();
|
|
||||||
for (int i = 0; i < PARALLEL_THREADS; i++) {
|
|
||||||
Thread thread = new Thread(SET_TASK);
|
|
||||||
thread.setName("PlotSquared Flush Task");
|
|
||||||
threads.add(thread);
|
|
||||||
}
|
|
||||||
for (Thread thread : threads) {
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
for (Thread thread : threads) {
|
|
||||||
try {
|
|
||||||
thread.join();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
// Enable it again (note that we are still on the main thread)
|
|
||||||
SET_TASK.value2.endSet(true);
|
|
||||||
dequeue(queue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalBlockQueue getNextQueue() {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
while (!activeQueues.isEmpty()) {
|
|
||||||
LocalBlockQueue queue = activeQueues.peek();
|
|
||||||
if (queue != null && queue.size() > 0) {
|
|
||||||
queue.setModified(now);
|
|
||||||
return queue;
|
|
||||||
} else {
|
|
||||||
activeQueues.poll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int size = inactiveQueues.size();
|
|
||||||
if (size > 0) {
|
|
||||||
Iterator<LocalBlockQueue> iter = inactiveQueues.iterator();
|
|
||||||
try {
|
|
||||||
int total = 0;
|
|
||||||
LocalBlockQueue firstNonEmpty = null;
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
LocalBlockQueue queue = iter.next();
|
|
||||||
long age = now - queue.getModified();
|
|
||||||
total += queue.size();
|
|
||||||
if (queue.size() == 0) {
|
|
||||||
if (age > 60000) {
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (firstNonEmpty == null) {
|
|
||||||
firstNonEmpty = queue;
|
|
||||||
}
|
|
||||||
if (total > 64) {
|
|
||||||
firstNonEmpty.setModified(now);
|
|
||||||
return firstNonEmpty;
|
|
||||||
}
|
|
||||||
if (age > 1000) {
|
|
||||||
queue.setModified(now);
|
|
||||||
return queue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (ConcurrentModificationException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDone() {
|
public boolean isDone() {
|
||||||
return activeQueues.size() == 0 && inactiveQueues.size() == 0;
|
return activeQueues.size() == 0;
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addEmptyTask(final Runnable whenDone) {
|
|
||||||
if (this.isDone()) {
|
|
||||||
// Run
|
|
||||||
this.runEmptyTasks();
|
|
||||||
if (whenDone != null) {
|
|
||||||
whenDone.run();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (whenDone != null) {
|
|
||||||
this.runnables.add(whenDone);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void runEmptyTasks() {
|
|
||||||
if (this.runnables.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final ConcurrentLinkedDeque<Runnable> tmp = new ConcurrentLinkedDeque<>(this.runnables);
|
|
||||||
this.runnables.clear();
|
|
||||||
for (final Runnable runnable : tmp) {
|
|
||||||
runnable.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum QueueStage {
|
|
||||||
INACTIVE, ACTIVE, NONE
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
package com.plotsquared.core.queue;
|
||||||
|
|
||||||
|
import com.plotsquared.core.util.MainUtil;
|
||||||
|
import com.plotsquared.core.util.MathMan;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class LocalChunk {
|
||||||
|
public final BasicQueueCoordinator parent;
|
||||||
|
public final int z;
|
||||||
|
public final int x;
|
||||||
|
|
||||||
|
public BaseBlock[][] baseblocks;
|
||||||
|
public BiomeType[][] biomes;
|
||||||
|
public HashMap<BlockVector3, CompoundTag> tiles = null;
|
||||||
|
|
||||||
|
public LocalChunk(BasicQueueCoordinator parent, int x, int z) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.x = x;
|
||||||
|
this.z = z;
|
||||||
|
baseblocks = new BaseBlock[16][];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the parent queue this chunk belongs to
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public BasicQueueCoordinator getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getZ() {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBiome(int x, int z, BiomeType biomeType) {
|
||||||
|
if (this.biomes == null) {
|
||||||
|
this.biomes = new BiomeType[16][];
|
||||||
|
}
|
||||||
|
BiomeType[] index = this.biomes[x];
|
||||||
|
if (index == null) {
|
||||||
|
index = this.biomes[x] = new BiomeType[16];
|
||||||
|
}
|
||||||
|
index[z] = biomeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long longHash() {
|
||||||
|
return MathMan.pairInt(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public int hashCode() {
|
||||||
|
return MathMan.pair((short) x, (short) z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlock(final int x, final int y, final int z, final BaseBlock baseBlock) {
|
||||||
|
final int i = MainUtil.CACHE_I[y][x][z];
|
||||||
|
final int j = MainUtil.CACHE_J[y][x][z];
|
||||||
|
BaseBlock[] array = baseblocks[i];
|
||||||
|
if (array == null) {
|
||||||
|
array = (baseblocks[i] = new BaseBlock[4096]);
|
||||||
|
}
|
||||||
|
array[j] = baseBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTile(final int x, final int y, final int z, final CompoundTag tag) {
|
||||||
|
if (tiles == null) {
|
||||||
|
tiles = new HashMap<>();
|
||||||
|
}
|
||||||
|
tiles.put(BlockVector3.at(x, y, z), tag);
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.plotsquared.core.queue;
|
package com.plotsquared.core.queue;
|
||||||
|
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
@ -35,16 +36,17 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class LocationOffsetDelegateLocalBlockQueue extends DelegateLocalBlockQueue {
|
public class LocationOffsetDelegateQueueCoordinator extends DelegateQueueCoordinator {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger("P2/" + LocationOffsetDelegateLocalBlockQueue.class.getSimpleName());
|
private static final Logger logger = LoggerFactory
|
||||||
|
.getLogger("P2/" + LocationOffsetDelegateQueueCoordinator.class.getSimpleName());
|
||||||
|
|
||||||
private final boolean[][] canPlace;
|
private final boolean[][] canPlace;
|
||||||
private final int blockX;
|
private final int blockX;
|
||||||
private final int blockZ;
|
private final int blockZ;
|
||||||
|
|
||||||
public LocationOffsetDelegateLocalBlockQueue(final boolean[][] canPlace, final int blockX,
|
public LocationOffsetDelegateQueueCoordinator(final boolean[][] canPlace, final int blockX,
|
||||||
final int blockZ, @Nullable LocalBlockQueue parent) {
|
final int blockZ, @Nullable QueueCoordinator parent) {
|
||||||
super(parent);
|
super(parent);
|
||||||
this.canPlace = canPlace;
|
this.canPlace = canPlace;
|
||||||
this.blockX = blockX;
|
this.blockX = blockX;
|
||||||
@ -78,4 +80,7 @@ public class LocationOffsetDelegateLocalBlockQueue extends DelegateLocalBlockQue
|
|||||||
return super.setBiome(x, y, biome);
|
return super.setBiome(x, y, biome);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||||
|
return super.setTile(x, y, z, tag);
|
||||||
|
}
|
||||||
}
|
}
|
@ -25,15 +25,17 @@
|
|||||||
*/
|
*/
|
||||||
package com.plotsquared.core.queue;
|
package com.plotsquared.core.queue;
|
||||||
|
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
|
|
||||||
public class OffsetLocalBlockQueue extends DelegateLocalBlockQueue {
|
public class OffsetQueueCoordinator extends DelegateQueueCoordinator {
|
||||||
private final int ox;
|
private final int ox;
|
||||||
private final int oy;
|
private final int oy;
|
||||||
private final int oz;
|
private final int oz;
|
||||||
|
|
||||||
public OffsetLocalBlockQueue(LocalBlockQueue parent, int ox, int oy, int oz) {
|
public OffsetQueueCoordinator(QueueCoordinator parent, int ox, int oy, int oz) {
|
||||||
super(parent);
|
super(parent);
|
||||||
this.ox = ox;
|
this.ox = ox;
|
||||||
this.oy = oy;
|
this.oy = oy;
|
||||||
@ -47,4 +49,12 @@ public class OffsetLocalBlockQueue extends DelegateLocalBlockQueue {
|
|||||||
@Override public boolean setBlock(int x, int y, int z, BaseBlock id) {
|
@Override public boolean setBlock(int x, int y, int z, BaseBlock id) {
|
||||||
return super.setBlock(ox + x, oy + y, oz + z, id);
|
return super.setBlock(ox + x, oy + y, oz + z, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public boolean setBlock(int x, int y, int z, Pattern pattern) {
|
||||||
|
return super.setBlock(ox + x, oy + y, oz + z, pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||||
|
return super.setTile(ox + x, oy + y, oz + z, tag);
|
||||||
|
}
|
||||||
}
|
}
|
@ -28,59 +28,31 @@ package com.plotsquared.core.queue;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.plotsquared.core.PlotSquared;
|
import com.plotsquared.core.PlotSquared;
|
||||||
import com.plotsquared.core.location.Location;
|
import com.plotsquared.core.location.Location;
|
||||||
import com.plotsquared.core.player.PlotPlayer;
|
|
||||||
import com.plotsquared.core.util.PatternUtil;
|
import com.plotsquared.core.util.PatternUtil;
|
||||||
import com.plotsquared.core.util.SchematicHandler;
|
|
||||||
import com.plotsquared.core.util.StringMan;
|
|
||||||
import com.plotsquared.core.util.WorldUtil;
|
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
import com.sk89q.worldedit.math.BlockVector2;
|
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public abstract class LocalBlockQueue {
|
public abstract class QueueCoordinator {
|
||||||
|
|
||||||
@Getter @Setter private boolean forceSync = false;
|
@Getter @Setter private boolean forceSync = false;
|
||||||
@Getter @Setter @Nullable private Object chunkObject;
|
@Getter @Setter @Nullable private Object chunkObject;
|
||||||
|
|
||||||
@Inject private SchematicHandler schematicHandler;
|
|
||||||
@Inject private WorldUtil worldUtil;
|
|
||||||
@Inject private GlobalBlockQueue blockQueue;
|
@Inject private GlobalBlockQueue blockQueue;
|
||||||
|
|
||||||
/**
|
public QueueCoordinator() {
|
||||||
* Needed for compatibility with FAWE.
|
|
||||||
*
|
|
||||||
* @param world unused
|
|
||||||
*/
|
|
||||||
@Deprecated public LocalBlockQueue(String world) {
|
|
||||||
PlotSquared.platform().getInjector().injectMembers(this);
|
PlotSquared.platform().getInjector().injectMembers(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScopedLocalBlockQueue getForChunk(int x, int z) {
|
|
||||||
int bx = x << 4;
|
|
||||||
int bz = z << 4;
|
|
||||||
return new ScopedLocalBlockQueue(this, Location.at(getWorld(), bx, 0, bz),
|
|
||||||
Location.at(getWorld(), bx + 15, 255, bz + 255));
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract boolean next();
|
|
||||||
|
|
||||||
public abstract void startSet(boolean parallel);
|
|
||||||
|
|
||||||
public abstract void endSet(boolean parallel);
|
|
||||||
|
|
||||||
public abstract int size();
|
public abstract int size();
|
||||||
|
|
||||||
public abstract void optimize();
|
|
||||||
|
|
||||||
public abstract long getModified();
|
|
||||||
|
|
||||||
public abstract void setModified(long modified);
|
public abstract void setModified(long modified);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,48 +71,22 @@ public abstract class LocalBlockQueue {
|
|||||||
return setBlock(x, y, z, PatternUtil.apply(pattern, x, y, z));
|
return setBlock(x, y, z, PatternUtil.apply(pattern, x, y, z));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
public abstract boolean setTile(int x, int y, int z, CompoundTag tag);
|
||||||
this.schematicHandler.restoreTile(this, tag, x, y, z);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract BlockState getBlock(int x, int y, int z);
|
public abstract BlockState getBlock(int x, int y, int z);
|
||||||
|
|
||||||
public abstract boolean setBiome(int x, int z, BiomeType biome);
|
public abstract boolean setBiome(int x, int z, BiomeType biome);
|
||||||
|
|
||||||
public abstract boolean setBiome();
|
public abstract boolean settingBiome();
|
||||||
|
|
||||||
public abstract String getWorld();
|
public abstract String getWorld();
|
||||||
|
|
||||||
public abstract void flush();
|
|
||||||
|
|
||||||
public final void setModified() {
|
public final void setModified() {
|
||||||
setModified(System.currentTimeMillis());
|
setModified(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void refreshChunk(int x, int z);
|
|
||||||
|
|
||||||
public abstract void fixChunkLighting(int x, int z);
|
|
||||||
|
|
||||||
public abstract void regenChunk(int x, int z);
|
|
||||||
|
|
||||||
public final void regenChunkSafe(int x, int z) {
|
|
||||||
regenChunk(x, z);
|
|
||||||
fixChunkLighting(x, z);
|
|
||||||
BlockVector2 loc = BlockVector2.at(x, z);
|
|
||||||
|
|
||||||
for (final PlotPlayer<?> pp : PlotSquared.platform().getPlayerManager().getPlayers()) {
|
|
||||||
Location pLoc = pp.getLocation();
|
|
||||||
if (!StringMan.isEqual(getWorld(), pLoc.getWorldName()) || !pLoc.getChunkLocation()
|
|
||||||
.equals(loc)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pp.teleport(pLoc.withY(this.worldUtil.getHighestBlockSynchronous(getWorld(), pLoc.getX(), pLoc.getZ())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean enqueue() {
|
public boolean enqueue() {
|
||||||
return blockQueue.enqueue(this);
|
return this.blockQueue.enqueue(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCuboid(Location pos1, Location pos2, BlockState block) {
|
public void setCuboid(Location pos1, Location pos2, BlockState block) {
|
@ -26,23 +26,23 @@
|
|||||||
package com.plotsquared.core.queue;
|
package com.plotsquared.core.queue;
|
||||||
|
|
||||||
public abstract class QueueProvider {
|
public abstract class QueueProvider {
|
||||||
public static QueueProvider of(final Class<? extends LocalBlockQueue> primary,
|
public static QueueProvider of(final Class<? extends QueueCoordinator> primary,
|
||||||
final Class<? extends LocalBlockQueue> fallback) {
|
final Class<? extends QueueCoordinator> fallback) {
|
||||||
return new QueueProvider() {
|
return new QueueProvider() {
|
||||||
|
|
||||||
private boolean failed = false;
|
private boolean failed = false;
|
||||||
|
|
||||||
@Override public LocalBlockQueue getNewQueue(String world) {
|
@Override public QueueCoordinator getNewQueue(String world) {
|
||||||
if (!failed) {
|
if (!failed) {
|
||||||
try {
|
try {
|
||||||
return (LocalBlockQueue) primary.getConstructors()[0].newInstance(world);
|
return (QueueCoordinator) primary.getConstructors()[0].newInstance(world);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
failed = true;
|
failed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return (LocalBlockQueue) fallback.getConstructors()[0].newInstance(world);
|
return (QueueCoordinator) fallback.getConstructors()[0].newInstance(world);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -51,5 +51,5 @@ public abstract class QueueProvider {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract LocalBlockQueue getNewQueue(String world);
|
public abstract QueueCoordinator getNewQueue(String world);
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,13 @@
|
|||||||
package com.plotsquared.core.queue;
|
package com.plotsquared.core.queue;
|
||||||
|
|
||||||
import com.plotsquared.core.location.Location;
|
import com.plotsquared.core.location.Location;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
|
|
||||||
public class ScopedLocalBlockQueue extends DelegateLocalBlockQueue {
|
public class ScopedQueueCoordinator extends DelegateQueueCoordinator {
|
||||||
private final int minX;
|
private final int minX;
|
||||||
private final int minY;
|
private final int minY;
|
||||||
private final int minZ;
|
private final int minZ;
|
||||||
@ -44,7 +45,7 @@ public class ScopedLocalBlockQueue extends DelegateLocalBlockQueue {
|
|||||||
private final int dy;
|
private final int dy;
|
||||||
private final int dz;
|
private final int dz;
|
||||||
|
|
||||||
public ScopedLocalBlockQueue(LocalBlockQueue parent, Location min, Location max) {
|
public ScopedQueueCoordinator(QueueCoordinator parent, Location min, Location max) {
|
||||||
super(parent);
|
super(parent);
|
||||||
this.minX = min.getX();
|
this.minX = min.getX();
|
||||||
this.minY = min.getY();
|
this.minY = min.getY();
|
||||||
@ -86,6 +87,11 @@ public class ScopedLocalBlockQueue extends DelegateLocalBlockQueue {
|
|||||||
.setBlock(x + minX, y + minY, z + minZ, pattern);
|
.setBlock(x + minX, y + minY, z + minZ, pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||||
|
return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super
|
||||||
|
.setTile(x + minX, y + minY, z + minZ, tag);
|
||||||
|
}
|
||||||
|
|
||||||
public Location getMin() {
|
public Location getMin() {
|
||||||
return Location.at(this.getWorld(), this.minX, this.minY, this.minZ);
|
return Location.at(this.getWorld(), this.minX, this.minY, this.minZ);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user