This commit is contained in:
Matt Worzala 2021-01-08 21:15:58 -05:00
parent 5a9e393ae2
commit 0f080b9dc8
6 changed files with 137 additions and 8 deletions

View File

@ -28,7 +28,8 @@ public class AbsoluteBlockBatch implements Batch<Runnable> {
// In the form of <Chunk Index, Batch> // In the form of <Chunk Index, Batch>
private final Long2ObjectMap<ChunkBatch> chunkBatchesMap = new Long2ObjectOpenHashMap<>(); private final Long2ObjectMap<ChunkBatch> chunkBatchesMap = new Long2ObjectOpenHashMap<>();
private final CountDownLatch readyLatch; // Available for other implementations to handle.
protected final CountDownLatch readyLatch;
private final BatchOption options; private final BatchOption options;
public AbsoluteBlockBatch() { public AbsoluteBlockBatch() {
@ -86,6 +87,7 @@ public class AbsoluteBlockBatch implements Batch<Runnable> {
* *
* @param instance The instance in which the batch should be applied * @param instance The instance in which the batch should be applied
* @param callback The callback to be executed when the batch is 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}
*/ */
@Override @Override
public AbsoluteBlockBatch apply(@NotNull Instance instance, @Nullable Runnable callback) { public AbsoluteBlockBatch apply(@NotNull Instance instance, @Nullable Runnable callback) {
@ -98,6 +100,7 @@ public class AbsoluteBlockBatch implements Batch<Runnable> {
* *
* @param instance The instance in which the batch should be applied * @param instance The instance in which the batch should be applied
* @param callback The callback to be executed when the batch is 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}
*/ */
public AbsoluteBlockBatch unsafeApply(@NotNull Instance instance, @Nullable Runnable callback) { public AbsoluteBlockBatch unsafeApply(@NotNull Instance instance, @Nullable Runnable callback) {
return apply(instance, callback, false); return apply(instance, callback, false);
@ -110,6 +113,7 @@ public class AbsoluteBlockBatch implements Batch<Runnable> {
* @param callback The callback to be executed when the batch is applied * @param callback The callback to be executed when the batch is applied
* @param safeCallback If true, the callback will be executed in the next instance update. * @param safeCallback If true, the callback will be executed in the next instance update.
* Otherwise it will be executed immediately upon completion * Otherwise it will be executed immediately upon completion
* @return The inverse of this batch, if inverse is enabled in the {@link BatchOption}
*/ */
protected AbsoluteBlockBatch 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(); if (!this.options.isUnsafeApply()) this.awaitReady();

View File

@ -50,8 +50,6 @@ public interface Batch<Callback> extends BlockModifier {
/** /**
* Gets if the batch is ready to be applied to an instance. * 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 * @return true if the batch is ready to apply
*/ */

View File

@ -1,7 +1,12 @@
package net.minestom.server.instance.batch; package net.minestom.server.instance.batch;
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/**
* Represents options for {@link Batch}s.
*/
public class BatchOption { public class BatchOption {
private boolean fullChunk = false; private boolean fullChunk = false;
private boolean calculateInverse = false; private boolean calculateInverse = false;
@ -14,6 +19,8 @@ public class BatchOption {
* Gets if the batch is responsible for composing the whole chunk. * Gets if the batch is responsible for composing the whole chunk.
* <p> * <p>
* Having it to true means that the batch will clear the chunk data before placing the blocks. * Having it to true means that the batch will clear the chunk data before placing the blocks.
* <p>
* Defaults to false.
* *
* @return true if the batch is responsible for all the chunk * @return true if the batch is responsible for all the chunk
*/ */
@ -21,10 +28,35 @@ public class BatchOption {
return fullChunk; return fullChunk;
} }
/**
* Gets if the batch will calculate the inverse of the batch when it is applied for an 'undo' behavior.
* <p>
* This flag will determine the return value of {@link Batch#apply(Instance, Object)} (and other variants).
* If true, a {@link Batch} will be returned. Otherwise null will be returned.
* <p>
* Defaults to false.
*
* @return true if the batch will calculate its inverse on application
* @see #isUnsafeApply()
*/
public boolean shouldCalculateInverse() { public boolean shouldCalculateInverse() {
return calculateInverse; return calculateInverse;
} }
/**
* Gets if the batch will wait ignore whether it is ready or not when applying it.
* <p>
* If set, the batch may not be ready, or it may be partially ready which will cause an undefined result.
* {@link Batch#isReady()} and {@link Batch#awaitReady()} may be used to check if it is ready and block
* until it is ready.
*
* The default implementations of {@link ChunkBatch}, {@link AbsoluteBlockBatch}, and {@link RelativeBlockBatch}
* are always ready unless they are an inverse batch. This is not a safe assumption, and may change in the future.
* <p>
* Defaults to false.
*
* @return true if the batch will immediately
*/
public boolean isUnsafeApply() { public boolean isUnsafeApply() {
return this.unsafeApply; return this.unsafeApply;
} }
@ -35,18 +67,32 @@ public class BatchOption {
* @see #isFullChunk() * @see #isFullChunk()
*/ */
@NotNull @NotNull
@Contract("_ -> this")
public BatchOption setFullChunk(boolean fullChunk) { public BatchOption setFullChunk(boolean fullChunk) {
this.fullChunk = fullChunk; this.fullChunk = fullChunk;
return this; return this;
} }
/**
* @param calculateInverse true to make this batch calculate the inverse on application
* @return 'this' for chaining
* @see #shouldCalculateInverse()
*/
@NotNull @NotNull
@Contract("_ -> this")
public BatchOption setCalculateInverse(boolean calculateInverse) { public BatchOption setCalculateInverse(boolean calculateInverse) {
this.calculateInverse = calculateInverse; this.calculateInverse = calculateInverse;
return this; return this;
} }
/**
* @param unsafeApply true to make this batch apply without checking if it is ready to apply.
* @return 'this' for chaining
* @see #isUnsafeApply()
* @see Batch#isReady()
*/
@NotNull @NotNull
@Contract("_ -> this")
public BatchOption setUnsafeApply(boolean unsafeApply) { public BatchOption setUnsafeApply(boolean unsafeApply) {
this.unsafeApply = unsafeApply; this.unsafeApply = unsafeApply;
return this; return this;

View File

@ -42,7 +42,8 @@ public class ChunkBatch implements Batch<ChunkCallback> {
// block index - data // block index - data
private final Int2ObjectMap<Data> blockDataMap; private final Int2ObjectMap<Data> blockDataMap;
private final CountDownLatch readyLatch; // Available for other implementations to handle.
protected final CountDownLatch readyLatch;
private final BatchOption options; private final BatchOption options;
public ChunkBatch() { public ChunkBatch() {
@ -110,6 +111,7 @@ public class ChunkBatch implements Batch<ChunkCallback> {
* *
* @param instance The instance in which the batch should be applied * @param instance The instance in which the batch should be applied
* @param callback The callback to be executed when the batch is 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}
*/ */
@Override @Override
public ChunkBatch apply(@NotNull Instance instance, @Nullable ChunkCallback callback) { public ChunkBatch apply(@NotNull Instance instance, @Nullable ChunkCallback callback) {
@ -123,6 +125,7 @@ public class ChunkBatch implements Batch<ChunkCallback> {
* @param chunkX The x chunk coordinate of the target chunk * @param chunkX The x chunk coordinate of the target chunk
* @param chunkZ The z chunk coordinate of the target chunk * @param chunkZ The z chunk coordinate of the target chunk
* @param callback The callback to be executed when the batch is 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}
*/ */
public ChunkBatch 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); final Chunk chunk = instance.getChunk(chunkX, chunkZ);
@ -140,6 +143,7 @@ public class ChunkBatch implements Batch<ChunkCallback> {
* @param instance The instance in which the batch should be applied * @param instance The instance in which the batch should be applied
* @param chunk The target chunk * @param chunk The target chunk
* @param callback The callback to be executed when the batch is 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}
*/ */
public ChunkBatch apply(@NotNull Instance instance, @NotNull Chunk chunk, @Nullable ChunkCallback callback) { public ChunkBatch apply(@NotNull Instance instance, @NotNull Chunk chunk, @Nullable ChunkCallback callback) {
return apply(instance, chunk, callback, true); return apply(instance, chunk, callback, true);
@ -152,6 +156,7 @@ public class ChunkBatch implements Batch<ChunkCallback> {
* @param instance The instance in which the batch should be applied * @param instance The instance in which the batch should be applied
* @param chunk The target chunk * @param chunk The target chunk
* @param callback The callback to be executed when the batch is 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}
*/ */
public ChunkBatch unsafeApply(@NotNull Instance instance, @NotNull Chunk chunk, @Nullable ChunkCallback callback) { public ChunkBatch unsafeApply(@NotNull Instance instance, @NotNull Chunk chunk, @Nullable ChunkCallback callback) {
return apply(instance, chunk, callback, false); return apply(instance, chunk, callback, false);
@ -165,6 +170,7 @@ public class ChunkBatch implements Batch<ChunkCallback> {
* @param callback The callback to be executed when the batch is applied * @param callback The callback to be executed when the batch is applied
* @param safeCallback If true, the callback will be executed in the next instance update. * @param safeCallback If true, the callback will be executed in the next instance update.
* Otherwise it will be executed immediately upon completion * Otherwise it will be executed immediately upon completion
* @return The inverse of this batch, if inverse is enabled in the {@link BatchOption}
*/ */
protected ChunkBatch apply(@NotNull Instance instance, protected ChunkBatch apply(@NotNull Instance instance,
@NotNull Chunk chunk, @Nullable ChunkCallback callback, @NotNull Chunk chunk, @Nullable ChunkCallback callback,

View File

@ -11,6 +11,25 @@ import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
/**
* A {@link Batch} which can be used when changes are required across chunk borders, and
* are going to be reused in different places. If translation is not required, {@link AbsoluteBlockBatch}
* should be used instead for efficiency purposes.
* <p>
* Coordinates are relative to (0, 0, 0) with some limitations. All coordinates must
* fit within a 16 bit integer of the first coordinate (32,767 blocks). If blocks must
* be spread out over a larger area, an {@link AbsoluteBlockBatch} should be used.
* <p>
* All inverses are {@link AbsoluteBlockBatch}s and represent the inverse of the application
* at the position which it was applied.
* <p>
* If a batch will be used multiple times at the same coordinate, it is suggested
* to convert it to an {@link AbsoluteBlockBatch} and cache the result. Application
* of absolute batches (currently) is significantly faster than their relative counterpart.
*
* @see Batch
* @see AbsoluteBlockBatch
*/
public class RelativeBlockBatch implements Batch<Runnable> { public class RelativeBlockBatch implements Batch<Runnable> {
// relative pos format: nothing/relative x/relative y/relative z (16/16/16/16 bits) // relative pos format: nothing/relative x/relative y/relative z (16/16/16/16 bits)
@ -81,32 +100,92 @@ public class RelativeBlockBatch implements Batch<Runnable> {
} }
} }
/**
* Applies this batch to the given instance at the origin (0, 0, 0) of the instance.
*
* @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}
*/
@Override @Override
public AbsoluteBlockBatch apply(@NotNull Instance instance, @Nullable Runnable callback) { public AbsoluteBlockBatch apply(@NotNull Instance instance, @Nullable Runnable callback) {
return apply(instance, 0, 0, 0, callback); return apply(instance, 0, 0, 0, callback);
} }
/**
* Applies this batch to the given instance at the given block position.
*
* @param instance The instance in which the batch should be applied
* @param position The position to apply the batch
* @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}
*/
public AbsoluteBlockBatch apply(@NotNull Instance instance, @NotNull BlockPosition position, @Nullable Runnable callback) { public AbsoluteBlockBatch apply(@NotNull Instance instance, @NotNull BlockPosition position, @Nullable Runnable callback) {
return apply(instance, position.getX(), position.getY(), position.getZ(), callback); return apply(instance, position.getX(), position.getY(), position.getZ(), callback);
} }
/**
* Applies this batch to the given instance at the given position.
*
* @param instance The instance in which the batch should be applied
* @param x The x position to apply the batch
* @param y The y position to apply the batch
* @param z The z position to apply the batch
* @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}
*/
public AbsoluteBlockBatch apply(@NotNull Instance instance, int x, int y, int z, @Nullable Runnable callback) { public AbsoluteBlockBatch apply(@NotNull Instance instance, int x, int y, int z, @Nullable Runnable callback) {
return apply(instance, x, y, z, callback, true); return apply(instance, x, y, z, callback, true);
} }
/**
* Applies this batch to the given instance at the given position, and execute the callback
* immediately when the blocks have been applied, int an unknown thread.
*
* @param instance The instance in which the batch should be applied
* @param x The x position to apply the batch
* @param y The y position to apply the batch
* @param z The z position to apply the batch
* @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}
*/
public AbsoluteBlockBatch applyUnsafe(@NotNull Instance instance, int x, int y, int z, @Nullable Runnable callback) { public AbsoluteBlockBatch applyUnsafe(@NotNull Instance instance, int x, int y, int z, @Nullable Runnable callback) {
return apply(instance, x, y, z, callback, false); return apply(instance, x, y, z, callback, false);
} }
/**
* Applies this batch to the given instance at the given position, execute the callback depending on safeCallback.
*
* @param instance The instance in which the batch should be applied
* @param x The x position to apply the batch
* @param y The y position to apply the batch
* @param z The z position to apply the batch
* @param callback The callback to be executed when the batch is applied
* @param safeCallback If true, the callback will be executed in the next instance update. Otherwise it will be executed immediately upon completion
* @return The inverse of this batch, if inverse is enabled in the {@link BatchOption}
*/
protected AbsoluteBlockBatch apply(@NotNull Instance instance, int x, int y, int z, @Nullable Runnable callback, boolean safeCallback) { 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); return this.toAbsoluteBatch(x, y, z).apply(instance, callback, safeCallback);
} }
/**
* Converts this batch to an absolute batch at the origin (0, 0, 0).
*
* @return An absolute batch of this batch at the origin
*/
@NotNull @NotNull
public AbsoluteBlockBatch toAbsoluteBatch() { public AbsoluteBlockBatch toAbsoluteBatch() {
return toAbsoluteBatch(0, 0, 0); return toAbsoluteBatch(0, 0, 0);
} }
/**
* Converts this batch to an absolute batch at the given coordinates.
*
* @param x The x position of the batch in the world
* @param y The y position of the batch in the world
* @param z The z position of the batch in the world
* @return An absolute batch of this batch at (x, y, z)
*/
@NotNull @NotNull
public AbsoluteBlockBatch toAbsoluteBatch(int x, int y, int z) { public AbsoluteBlockBatch toAbsoluteBatch(int x, int y, int z) {
final AbsoluteBlockBatch batch = new AbsoluteBlockBatch(this.options); final AbsoluteBlockBatch batch = new AbsoluteBlockBatch(this.options);

View File

@ -1,14 +1,11 @@
package demo.commands; package demo.commands;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.chat.ChatColor;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.command.CommandSender; import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.Arguments; import net.minestom.server.command.builder.Arguments;
import net.minestom.server.command.builder.Command; import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.arguments.ArgumentType; 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.entity.Player;
import net.minestom.server.instance.InstanceContainer; import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.instance.batch.AbsoluteBlockBatch; import net.minestom.server.instance.batch.AbsoluteBlockBatch;
@ -19,7 +16,6 @@ import net.minestom.server.instance.block.Block;
import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.utils.time.TimeUnit;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicReference;
public class CubeBatchCommand extends Command { public class CubeBatchCommand extends Command {