mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-09 09:57:45 +01:00
bring back BatchOption, batch inversion start
This commit is contained in:
parent
d5a53641ba
commit
5a9e393ae2
@ -10,6 +10,7 @@ import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
@ -27,7 +28,20 @@ public class AbsoluteBlockBatch implements Batch<Runnable> {
|
||||
// In the form of <Chunk Index, Batch>
|
||||
private final Long2ObjectMap<ChunkBatch> chunkBatchesMap = new Long2ObjectOpenHashMap<>();
|
||||
|
||||
private final CountDownLatch readyLatch;
|
||||
private final BatchOption options;
|
||||
|
||||
public AbsoluteBlockBatch() {
|
||||
this(new BatchOption());
|
||||
}
|
||||
|
||||
public AbsoluteBlockBatch(BatchOption options) {
|
||||
this(options, true);
|
||||
}
|
||||
|
||||
private AbsoluteBlockBatch(BatchOption options, boolean ready) {
|
||||
this.readyLatch = new CountDownLatch(ready ? 0 : 1);
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -38,7 +52,7 @@ public class AbsoluteBlockBatch implements Batch<Runnable> {
|
||||
|
||||
final ChunkBatch chunkBatch;
|
||||
synchronized (chunkBatchesMap) {
|
||||
chunkBatch = chunkBatchesMap.computeIfAbsent(chunkIndex, i -> new ChunkBatch());
|
||||
chunkBatch = chunkBatchesMap.computeIfAbsent(chunkIndex, i -> new ChunkBatch(this.options));
|
||||
}
|
||||
|
||||
final int relativeX = x - (chunkX * Chunk.CHUNK_SIZE_X);
|
||||
@ -53,6 +67,20 @@ public class AbsoluteBlockBatch implements Batch<Runnable> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return this.readyLatch.getCount() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void awaitReady() {
|
||||
try {
|
||||
this.readyLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("#awaitReady interrupted!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies this batch to the given instance.
|
||||
*
|
||||
@ -60,8 +88,8 @@ public class AbsoluteBlockBatch implements Batch<Runnable> {
|
||||
* @param callback The callback to be executed when the batch is applied
|
||||
*/
|
||||
@Override
|
||||
public void apply(@NotNull Instance instance, @Nullable Runnable callback) {
|
||||
apply(instance, callback, true);
|
||||
public AbsoluteBlockBatch apply(@NotNull Instance instance, @Nullable Runnable callback) {
|
||||
return apply(instance, callback, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,8 +99,8 @@ public class AbsoluteBlockBatch implements Batch<Runnable> {
|
||||
* @param instance The instance in which the batch should be applied
|
||||
* @param callback The callback to be executed when the batch is applied
|
||||
*/
|
||||
public void unsafeApply(@NotNull Instance instance, @Nullable Runnable callback) {
|
||||
apply(instance, callback, false);
|
||||
public AbsoluteBlockBatch unsafeApply(@NotNull Instance instance, @Nullable Runnable callback) {
|
||||
return apply(instance, callback, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,7 +111,10 @@ public class AbsoluteBlockBatch implements Batch<Runnable> {
|
||||
* @param safeCallback If true, the callback will be executed in the next instance update.
|
||||
* Otherwise it will be executed immediately upon completion
|
||||
*/
|
||||
protected void apply(@NotNull Instance instance, @Nullable Runnable callback, boolean safeCallback) {
|
||||
protected AbsoluteBlockBatch apply(@NotNull Instance instance, @Nullable Runnable callback, boolean safeCallback) {
|
||||
if (!this.options.isUnsafeApply()) this.awaitReady();
|
||||
|
||||
final AbsoluteBlockBatch inverse = this.options.shouldCalculateInverse() ? new AbsoluteBlockBatch() : null;
|
||||
synchronized (chunkBatchesMap) {
|
||||
AtomicInteger counter = new AtomicInteger();
|
||||
for (Long2ObjectMap.Entry<ChunkBatch> entry : chunkBatchesMap.long2ObjectEntrySet()) {
|
||||
@ -92,11 +123,12 @@ public class AbsoluteBlockBatch implements Batch<Runnable> {
|
||||
final int chunkZ = ChunkUtils.getChunkCoordZ(chunkIndex);
|
||||
final ChunkBatch batch = entry.getValue();
|
||||
|
||||
batch.apply(instance, chunkX, chunkZ, c -> {
|
||||
ChunkBatch chunkInverse = batch.apply(instance, chunkX, chunkZ, c -> {
|
||||
final boolean isLast = counter.incrementAndGet() == chunkBatchesMap.size();
|
||||
|
||||
// Execute the callback if this was the last chunk to process
|
||||
if (isLast) {
|
||||
if (inverse != null) inverse.readyLatch.countDown();
|
||||
|
||||
if (instance instanceof InstanceContainer) {
|
||||
// FIXME: put method in Instance instead
|
||||
@ -112,7 +144,12 @@ public class AbsoluteBlockBatch implements Batch<Runnable> {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (inverse != null)
|
||||
inverse.chunkBatchesMap.put(chunkIndex, chunkInverse);
|
||||
}
|
||||
}
|
||||
|
||||
return inverse;
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,22 @@ public interface Batch<Callback> extends BlockModifier {
|
||||
@Override
|
||||
void setSeparateBlocks(int x, int y, int z, short blockStateId, short customBlockId, @Nullable Data data);
|
||||
|
||||
/**
|
||||
* Gets if the batch is ready to be applied to an instance.
|
||||
* <p>
|
||||
* This is true by default, and will only be false while a reversal is being generated.
|
||||
*
|
||||
* @return true if the batch is ready to apply
|
||||
*/
|
||||
default boolean isReady() { return true; }
|
||||
|
||||
/**
|
||||
* Blocks the current thread until the batch is ready to be applied.
|
||||
*
|
||||
* @see #isReady() for a non-blocking way to determine if the batch is ready
|
||||
*/
|
||||
default void awaitReady() {}
|
||||
|
||||
/**
|
||||
* Removes all block data from this batch.
|
||||
*/
|
||||
@ -68,9 +84,8 @@ public interface Batch<Callback> extends BlockModifier {
|
||||
*
|
||||
* @param instance The instance in which the batch should be applied
|
||||
* @param callback The callback to be executed when the batch is applied
|
||||
* @return The inverse of this batch, if inverse is enabled in the {@link BatchOption}
|
||||
*/
|
||||
void apply(@NotNull Instance instance, @Nullable Callback callback);
|
||||
|
||||
// @NotNull
|
||||
// Batch<Callback> reversableApply(@NotNull InstanceContainer instance, @Nullable Callback callback);
|
||||
@Nullable
|
||||
Batch<Callback> apply(@NotNull Instance instance, @Nullable Callback callback);
|
||||
}
|
||||
|
@ -3,8 +3,9 @@ package net.minestom.server.instance.batch;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BatchOption {
|
||||
|
||||
private boolean fullChunk = false;
|
||||
private boolean calculateInverse = false;
|
||||
private boolean unsafeApply = false;
|
||||
|
||||
public BatchOption() {
|
||||
}
|
||||
@ -20,6 +21,14 @@ public class BatchOption {
|
||||
return fullChunk;
|
||||
}
|
||||
|
||||
public boolean shouldCalculateInverse() {
|
||||
return calculateInverse;
|
||||
}
|
||||
|
||||
public boolean isUnsafeApply() {
|
||||
return this.unsafeApply;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fullChunk true to make this batch composes the whole chunk
|
||||
* @return 'this' for chaining
|
||||
@ -30,4 +39,16 @@ public class BatchOption {
|
||||
this.fullChunk = fullChunk;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public BatchOption setCalculateInverse(boolean calculateInverse) {
|
||||
this.calculateInverse = calculateInverse;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public BatchOption setUnsafeApply(boolean unsafeApply) {
|
||||
this.unsafeApply = unsafeApply;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* A Batch used when all of the block changed are contained inside a single chunk.
|
||||
* If more than one chunk is needed, use an {@link AbsoluteBlockBatch} instead.
|
||||
@ -40,13 +42,27 @@ public class ChunkBatch implements Batch<ChunkCallback> {
|
||||
// block index - data
|
||||
private final Int2ObjectMap<Data> blockDataMap;
|
||||
|
||||
private final CountDownLatch readyLatch;
|
||||
private final BatchOption options;
|
||||
|
||||
public ChunkBatch() {
|
||||
this(new LongArrayList(), new Int2ObjectOpenHashMap<>());
|
||||
this(new BatchOption());
|
||||
}
|
||||
|
||||
protected ChunkBatch(LongList blocks, Int2ObjectMap<Data> blockDataMap) {
|
||||
public ChunkBatch(BatchOption options) {
|
||||
this(new LongArrayList(), new Int2ObjectOpenHashMap<>(), options);
|
||||
}
|
||||
|
||||
protected ChunkBatch(LongList blocks, Int2ObjectMap<Data> blockDataMap, BatchOption options) {
|
||||
this(blocks, blockDataMap, options, true);
|
||||
}
|
||||
|
||||
private ChunkBatch(LongList blocks, Int2ObjectMap<Data> blockDataMap, BatchOption options, boolean ready) {
|
||||
this.blocks = blocks;
|
||||
this.blockDataMap = blockDataMap;
|
||||
|
||||
this.readyLatch = new CountDownLatch(ready ? 0 : 1);
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -75,6 +91,20 @@ public class ChunkBatch implements Batch<ChunkCallback> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return this.readyLatch.getCount() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void awaitReady() {
|
||||
try {
|
||||
this.readyLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("#awaitReady interrupted!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply this batch to chunk (0, 0).
|
||||
*
|
||||
@ -82,8 +112,8 @@ public class ChunkBatch implements Batch<ChunkCallback> {
|
||||
* @param callback The callback to be executed when the batch is applied
|
||||
*/
|
||||
@Override
|
||||
public void apply(@NotNull Instance instance, @Nullable ChunkCallback callback) {
|
||||
apply(instance, 0, 0, callback);
|
||||
public ChunkBatch apply(@NotNull Instance instance, @Nullable ChunkCallback callback) {
|
||||
return apply(instance, 0, 0, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,14 +124,14 @@ public class ChunkBatch implements Batch<ChunkCallback> {
|
||||
* @param chunkZ The z chunk coordinate of the target chunk
|
||||
* @param callback The callback to be executed when the batch is applied.
|
||||
*/
|
||||
public void apply(@NotNull Instance instance, int chunkX, int chunkZ, @Nullable ChunkCallback callback) {
|
||||
public ChunkBatch apply(@NotNull Instance instance, int chunkX, int chunkZ, @Nullable ChunkCallback callback) {
|
||||
final Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
||||
if (chunk == null) {
|
||||
LOGGER.warn("Unable to apply ChunkBatch to unloaded chunk ({}, {}) in {}.",
|
||||
chunkX, chunkZ, instance.getUniqueId());
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
apply(instance, chunk, callback);
|
||||
return apply(instance, chunk, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,8 +141,8 @@ public class ChunkBatch implements Batch<ChunkCallback> {
|
||||
* @param chunk The target chunk
|
||||
* @param callback The callback to be executed when the batch is applied
|
||||
*/
|
||||
public void apply(@NotNull Instance instance, @NotNull Chunk chunk, @Nullable ChunkCallback callback) {
|
||||
apply(instance, chunk, callback, true);
|
||||
public ChunkBatch apply(@NotNull Instance instance, @NotNull Chunk chunk, @Nullable ChunkCallback callback) {
|
||||
return apply(instance, chunk, callback, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,8 +153,8 @@ public class ChunkBatch implements Batch<ChunkCallback> {
|
||||
* @param chunk The target chunk
|
||||
* @param callback The callback to be executed when the batch is applied
|
||||
*/
|
||||
public void unsafeApply(@NotNull Instance instance, @NotNull Chunk chunk, @Nullable ChunkCallback callback) {
|
||||
apply(instance, chunk, callback, false);
|
||||
public ChunkBatch unsafeApply(@NotNull Instance instance, @NotNull Chunk chunk, @Nullable ChunkCallback callback) {
|
||||
return apply(instance, chunk, callback, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,36 +166,44 @@ public class ChunkBatch implements Batch<ChunkCallback> {
|
||||
* @param safeCallback If true, the callback will be executed in the next instance update.
|
||||
* Otherwise it will be executed immediately upon completion
|
||||
*/
|
||||
protected void apply(@NotNull Instance instance,
|
||||
protected ChunkBatch apply(@NotNull Instance instance,
|
||||
@NotNull Chunk chunk, @Nullable ChunkCallback callback,
|
||||
boolean safeCallback) {
|
||||
BLOCK_BATCH_POOL.execute(() -> singleThreadFlush(instance, chunk, callback, safeCallback));
|
||||
if (!this.options.isUnsafeApply()) this.awaitReady();
|
||||
|
||||
final ChunkBatch inverse = this.options.shouldCalculateInverse() ? new ChunkBatch(new LongArrayList(), new Int2ObjectOpenHashMap<>(), options, false) : null;
|
||||
BLOCK_BATCH_POOL.execute(() -> singleThreadFlush(instance, chunk, inverse, callback, safeCallback));
|
||||
return inverse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies this batch in the current thread, executing the callback upon completion.
|
||||
*/
|
||||
private void singleThreadFlush(Instance instance,
|
||||
Chunk chunk, @Nullable ChunkCallback callback,
|
||||
boolean safeCallback) {
|
||||
if (blocks.isEmpty()) {
|
||||
OptionalCallback.execute(callback, chunk);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chunk.isLoaded()) {
|
||||
LOGGER.warn("Unable to apply ChunkBatch to unloaded chunk ({}, {}) in {}.",
|
||||
chunk.getChunkX(), chunk.getChunkZ(), instance.getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (blocks) {
|
||||
for (long block : blocks) {
|
||||
apply(chunk, block);
|
||||
private void singleThreadFlush(Instance instance, Chunk chunk, @Nullable ChunkBatch inverse,
|
||||
@Nullable ChunkCallback callback, boolean safeCallback) {
|
||||
try {
|
||||
if (blocks.isEmpty()) {
|
||||
OptionalCallback.execute(callback, chunk);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
updateChunk(instance, chunk, callback, safeCallback);
|
||||
if (!chunk.isLoaded()) {
|
||||
LOGGER.warn("Unable to apply ChunkBatch to unloaded chunk ({}, {}) in {}.",
|
||||
chunk.getChunkX(), chunk.getChunkZ(), instance.getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (blocks) {
|
||||
for (long block : blocks) {
|
||||
apply(chunk, block, inverse);
|
||||
}
|
||||
}
|
||||
|
||||
if (inverse != null) inverse.readyLatch.countDown();
|
||||
updateChunk(instance, chunk, callback, safeCallback);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,7 +212,7 @@ public class ChunkBatch implements Batch<ChunkCallback> {
|
||||
* @param chunk The chunk to apply the change
|
||||
* @param value block index|state id|custom block id (32|16|16 bits)
|
||||
*/
|
||||
private void apply(@NotNull Chunk chunk, long value) {
|
||||
private void apply(@NotNull Chunk chunk, long value, @Nullable ChunkBatch inverse) {
|
||||
final short customBlockId = (short) (value & 0xFFFF);
|
||||
final short blockId = (short) ((value >> 16) & 0xFFFF);
|
||||
final int index = (int) ((value >> 32) & 0xFFFFFFFFL);
|
||||
@ -186,10 +224,14 @@ public class ChunkBatch implements Batch<ChunkCallback> {
|
||||
}
|
||||
}
|
||||
|
||||
chunk.UNSAFE_setBlock(ChunkUtils.blockIndexToChunkPositionX(index),
|
||||
ChunkUtils.blockIndexToChunkPositionY(index),
|
||||
ChunkUtils.blockIndexToChunkPositionZ(index),
|
||||
blockId, customBlockId, data, CustomBlockUtils.hasUpdate(customBlockId));
|
||||
final int x = ChunkUtils.blockIndexToChunkPositionX(index);
|
||||
final int y = ChunkUtils.blockIndexToChunkPositionY(index);
|
||||
final int z = ChunkUtils.blockIndexToChunkPositionZ(index);
|
||||
|
||||
if (inverse != null)
|
||||
inverse.setSeparateBlocks(x, y, z, chunk.getBlockStateId(x, y, z), chunk.getCustomBlockId(x, y, z), chunk.getBlockData(index));
|
||||
|
||||
chunk.UNSAFE_setBlock(x, y, z, blockId, customBlockId, data, CustomBlockUtils.hasUpdate(customBlockId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,7 @@ public class ChunkGenerationBatch extends ChunkBatch {
|
||||
private final Chunk chunk;
|
||||
|
||||
public ChunkGenerationBatch(InstanceContainer instance, Chunk chunk) {
|
||||
super(null, null);
|
||||
super(null, null, new BatchOption());
|
||||
|
||||
this.instance = instance;
|
||||
this.chunk = chunk;
|
||||
@ -54,9 +54,7 @@ public class ChunkGenerationBatch extends ChunkBatch {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void apply(@NotNull Instance instance,
|
||||
@NotNull Chunk chunk, @Nullable ChunkCallback callback,
|
||||
boolean safeCallback) {
|
||||
protected ChunkBatch apply(@NotNull Instance instance, @NotNull Chunk chunk, @Nullable ChunkCallback callback, boolean safeCallback) {
|
||||
throw new IllegalStateException("#apply is not supported for chunk generation batch.");
|
||||
}
|
||||
}
|
||||
|
@ -22,9 +22,19 @@ public class RelativeBlockBatch implements Batch<Runnable> {
|
||||
// relative pos - data
|
||||
private final Long2ObjectMap<Data> blockDataMap = new Long2ObjectOpenHashMap<>();
|
||||
|
||||
private final BatchOption options;
|
||||
|
||||
private volatile boolean firstEntry = true;
|
||||
private int offsetX, offsetY, offsetZ;
|
||||
|
||||
public RelativeBlockBatch() {
|
||||
this(new BatchOption());
|
||||
}
|
||||
|
||||
public RelativeBlockBatch(BatchOption options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSeparateBlocks(int x, int y, int z, short blockStateId, short customBlockId, @Nullable Data data) {
|
||||
|
||||
@ -72,25 +82,34 @@ public class RelativeBlockBatch implements Batch<Runnable> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(@NotNull Instance instance, @Nullable Runnable callback) {
|
||||
apply(instance, 0, 0, 0, callback);
|
||||
public AbsoluteBlockBatch apply(@NotNull Instance instance, @Nullable Runnable callback) {
|
||||
return apply(instance, 0, 0, 0, callback);
|
||||
}
|
||||
|
||||
public void apply(@NotNull Instance instance, @NotNull BlockPosition position, @Nullable Runnable callback) {
|
||||
apply(instance, position.getX(), position.getY(), position.getZ(), callback);
|
||||
public AbsoluteBlockBatch apply(@NotNull Instance instance, @NotNull BlockPosition position, @Nullable Runnable callback) {
|
||||
return apply(instance, position.getX(), position.getY(), position.getZ(), callback);
|
||||
}
|
||||
|
||||
public void apply(@NotNull Instance instance, int x, int y, int z, @Nullable Runnable callback) {
|
||||
apply(instance, x, y, z, callback, true);
|
||||
public AbsoluteBlockBatch apply(@NotNull Instance instance, int x, int y, int z, @Nullable Runnable callback) {
|
||||
return apply(instance, x, y, z, callback, true);
|
||||
}
|
||||
|
||||
public void applyUnsafe(@NotNull Instance instance, int x, int y, int z, @Nullable Runnable callback) {
|
||||
apply(instance, x, y, z, callback, false);
|
||||
public AbsoluteBlockBatch applyUnsafe(@NotNull Instance instance, int x, int y, int z, @Nullable Runnable callback) {
|
||||
return apply(instance, x, y, z, callback, false);
|
||||
}
|
||||
|
||||
protected void apply(@NotNull Instance instance, int x, int y, int z, @Nullable Runnable callback, boolean safeCallback) {
|
||||
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
|
||||
protected AbsoluteBlockBatch apply(@NotNull Instance instance, int x, int y, int z, @Nullable Runnable callback, boolean safeCallback) {
|
||||
return this.toAbsoluteBatch(x, y, z).apply(instance, callback, safeCallback);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public AbsoluteBlockBatch toAbsoluteBatch() {
|
||||
return toAbsoluteBatch(0, 0, 0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public AbsoluteBlockBatch toAbsoluteBatch(int x, int y, int z) {
|
||||
final AbsoluteBlockBatch batch = new AbsoluteBlockBatch(this.options);
|
||||
synchronized (blockIdMap) {
|
||||
for (Long2IntMap.Entry entry : blockIdMap.long2IntEntrySet()) {
|
||||
final long pos = entry.getLongKey();
|
||||
@ -116,7 +135,6 @@ public class RelativeBlockBatch implements Batch<Runnable> {
|
||||
batch.setSeparateBlocks(finalX, finalY, finalZ, blockStateId, customBlockId, data);
|
||||
}
|
||||
}
|
||||
|
||||
batch.apply(instance, callback, safeCallback);
|
||||
return batch;
|
||||
}
|
||||
}
|
||||
|
@ -6,22 +6,31 @@ import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.command.CommandSender;
|
||||
import net.minestom.server.command.builder.Arguments;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.command.builder.arguments.Argument;
|
||||
import net.minestom.server.command.builder.arguments.ArgumentType;
|
||||
import net.minestom.server.command.builder.arguments.ArgumentWord;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.instance.InstanceContainer;
|
||||
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
|
||||
import net.minestom.server.instance.batch.BatchOption;
|
||||
import net.minestom.server.instance.batch.ChunkBatch;
|
||||
import net.minestom.server.instance.batch.RelativeBlockBatch;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class CubeBatchCommand extends Command {
|
||||
|
||||
public CubeBatchCommand() {
|
||||
super("cube");
|
||||
|
||||
Argument<String> subcommand = ArgumentType.Word("sub").from("create", "undo");
|
||||
|
||||
setDefaultExecutor(this::execute);
|
||||
|
||||
addSyntax(this::handleSubcommand, subcommand);
|
||||
}
|
||||
|
||||
private void execute(CommandSender sender, Arguments args) {
|
||||
@ -59,6 +68,50 @@ public class CubeBatchCommand extends Command {
|
||||
|
||||
}
|
||||
|
||||
private volatile ChunkBatch inverse = null;
|
||||
private volatile AbsoluteBlockBatch absInverse = null;
|
||||
|
||||
private void handleSubcommand(CommandSender sender, Arguments args) {
|
||||
if (!sender.isPlayer()) {
|
||||
sender.sendMessage("This command may only be run by players.");
|
||||
return;
|
||||
}
|
||||
Player player = sender.asPlayer();
|
||||
InstanceContainer instance = (InstanceContainer) player.getInstance();
|
||||
|
||||
String sub = args.getWord("sub");
|
||||
if (sub.equalsIgnoreCase("create")) {
|
||||
final ChunkBatch batch = new ChunkBatch(new BatchOption().setCalculateInverse(true));
|
||||
for (int x = 0; x < 16; x += 2) {
|
||||
for (int y = 0; y < 50; y += 2) {
|
||||
for (int z = 0; z < 16; z += 2) {
|
||||
batch.setBlockStateId(x, y + 50, z, Block.STONE.getBlockId());
|
||||
}
|
||||
}
|
||||
}
|
||||
inverse = batch.apply(instance, 1, 1, c -> sender.sendMessage("Applied batch"));
|
||||
|
||||
final AbsoluteBlockBatch absBatch = new AbsoluteBlockBatch(new BatchOption().setCalculateInverse(true));
|
||||
for (int x = 0; x < 50; x += 2) {
|
||||
for (int y = 0; y < 50; y += 2) {
|
||||
for (int z = 0; z < 50; z += 2) {
|
||||
absBatch.setBlockStateId(x - 100, y + 50, z + 50, Block.STONE.getBlockId());
|
||||
}
|
||||
}
|
||||
}
|
||||
absInverse = absBatch.apply(instance, () -> sender.sendMessage("Applied batch 2"));
|
||||
} else if (sub.equalsIgnoreCase("undo")) {
|
||||
final ChunkBatch inv = inverse;
|
||||
if (inv == null) {
|
||||
sender.sendMessage("No inverse set.");
|
||||
return;
|
||||
}
|
||||
|
||||
inv.apply(instance, 1, 1, c -> sender.sendMessage("Applied inverse"));
|
||||
absInverse.apply(instance, () -> sender.sendMessage("Applied inverse 2"));
|
||||
} else sender.sendMessage("Unknown subcommand '" + sub + "'");
|
||||
}
|
||||
|
||||
private void applyBlockShape(InstanceContainer instance) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
|
||||
|
Loading…
Reference in New Issue
Block a user