diff --git a/src/main/java/net/minestom/server/instance/BlockModifier.java b/src/main/java/net/minestom/server/instance/BlockModifier.java index c5a7fdfe2..cccf04f23 100644 --- a/src/main/java/net/minestom/server/instance/BlockModifier.java +++ b/src/main/java/net/minestom/server/instance/BlockModifier.java @@ -2,8 +2,7 @@ package net.minestom.server.instance; import net.minestom.server.MinecraftServer; import net.minestom.server.data.Data; -import net.minestom.server.instance.batch.BlockBatch; -import net.minestom.server.instance.batch.ChunkBatch; +import net.minestom.server.instance.batch.Batch; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.BlockManager; import net.minestom.server.instance.block.CustomBlock; @@ -15,7 +14,7 @@ import org.jetbrains.annotations.Nullable; /** * Represents an element which can place blocks at position. *
- * Notably used by {@link Instance}, {@link BlockBatch} and {@link ChunkBatch}. + * Notably used by {@link Instance}, {@link Batch}. */ public interface BlockModifier { diff --git a/src/main/java/net/minestom/server/instance/Chunk.java b/src/main/java/net/minestom/server/instance/Chunk.java index 736091c18..e2f8a9347 100644 --- a/src/main/java/net/minestom/server/instance/Chunk.java +++ b/src/main/java/net/minestom/server/instance/Chunk.java @@ -9,8 +9,6 @@ import net.minestom.server.entity.pathfinding.PFColumnarSpace; import net.minestom.server.event.player.PlayerChunkLoadEvent; import net.minestom.server.event.player.PlayerChunkUnloadEvent; import net.minestom.server.instance.batch.BatchOption; -import net.minestom.server.instance.batch.BlockBatch; -import net.minestom.server.instance.batch.ChunkBatch; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.BlockManager; import net.minestom.server.instance.block.CustomBlock; @@ -102,7 +100,7 @@ public abstract class Chunk implements Viewable, DataContainer { *
* This is used when the previous block has to be destroyed/replaced, meaning that it clears the previous data and update method. *
- * WARNING: this method is not thread-safe (in order to bring performance improvement with {@link ChunkBatch} and {@link BlockBatch}) + * WARNING: this method is not thread-safe (in order to bring performance improvement with {@link net.minestom.server.instance.batch.Batch}s) * The thread-safe version is {@link InstanceContainer#setSeparateBlocks(int, int, int, short, short, Data)} (or any similar instance methods) * Otherwise, you can simply do not forget to have this chunk synchronized when this is called. * @@ -253,8 +251,6 @@ public abstract class Chunk implements Viewable, DataContainer { /** * Resets the chunk, this means clearing all the data making it empty. - *
- * Used for {@link BatchOption#isFullChunk()}.
*/
public abstract void reset();
diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java
index aaa2435ec..a2c19f763 100644
--- a/src/main/java/net/minestom/server/instance/Instance.java
+++ b/src/main/java/net/minestom/server/instance/Instance.java
@@ -16,8 +16,6 @@ import net.minestom.server.event.handler.EventHandler;
import net.minestom.server.event.instance.AddEntityToInstanceEvent;
import net.minestom.server.event.instance.InstanceTickEvent;
import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent;
-import net.minestom.server.instance.batch.BlockBatch;
-import net.minestom.server.instance.batch.ChunkBatch;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.CustomBlock;
@@ -212,22 +210,6 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
*/
public abstract void saveChunksToStorage(@Nullable Runnable callback);
- /**
- * Creates a new {@link BlockBatch} linked to this instance.
- *
- * @return a {@link BlockBatch} linked to the instance
- */
- public abstract BlockBatch createBlockBatch();
-
- /**
- * Creates a new {@link Chunk} batch linked to this instance and the specified chunk.
- *
- * @param chunk the chunk to modify
- * @return a ChunkBatch linked to {@code chunk}
- * @throws NullPointerException if {@code chunk} is null
- */
- public abstract ChunkBatch createChunkBatch(@NotNull Chunk chunk);
-
/**
* Gets the instance {@link ChunkGenerator}.
*
diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java
index ac2e4b67c..704124e13 100644
--- a/src/main/java/net/minestom/server/instance/InstanceContainer.java
+++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java
@@ -10,8 +10,7 @@ import net.minestom.server.entity.Player;
import net.minestom.server.event.instance.InstanceChunkLoadEvent;
import net.minestom.server.event.instance.InstanceChunkUnloadEvent;
import net.minestom.server.event.player.PlayerBlockBreakEvent;
-import net.minestom.server.instance.batch.BlockBatch;
-import net.minestom.server.instance.batch.ChunkBatch;
+import net.minestom.server.instance.batch.ChunkGenerationBatch;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.instance.block.rule.BlockPlacementRule;
@@ -505,16 +504,6 @@ public class InstanceContainer extends Instance {
this.chunkLoader.saveChunks(chunksCollection, callback);
}
- @Override
- public BlockBatch createBlockBatch() {
- return new BlockBatch(this);
- }
-
- @Override
- public ChunkBatch createChunkBatch(@NotNull Chunk chunk) {
- return new ChunkBatch(this, chunk, false);
- }
-
@Override
protected void retrieveChunk(int chunkX, int chunkZ, @Nullable ChunkCallback callback) {
final boolean loaded = chunkLoader.loadChunk(this, chunkX, chunkZ, chunk -> {
@@ -549,9 +538,9 @@ public class InstanceContainer extends Instance {
if (chunkGenerator != null && chunk.shouldGenerate()) {
// Execute the chunk generator to populate the chunk
- final ChunkBatch chunkBatch = new ChunkBatch(this, chunk, true);
+ final ChunkGenerationBatch chunkBatch = new ChunkGenerationBatch(this, chunk);
- chunkBatch.flushChunkGenerator(chunkGenerator, callback);
+ chunkBatch.generate(chunkGenerator, callback);
} else {
// No chunk generator, execute the callback with the empty chunk
OptionalCallback.execute(callback, chunk);
diff --git a/src/main/java/net/minestom/server/instance/SharedInstance.java b/src/main/java/net/minestom/server/instance/SharedInstance.java
index 013e2a0a1..19644b480 100644
--- a/src/main/java/net/minestom/server/instance/SharedInstance.java
+++ b/src/main/java/net/minestom/server/instance/SharedInstance.java
@@ -2,8 +2,6 @@ package net.minestom.server.instance;
import net.minestom.server.data.Data;
import net.minestom.server.entity.Player;
-import net.minestom.server.instance.batch.BlockBatch;
-import net.minestom.server.instance.batch.ChunkBatch;
import net.minestom.server.storage.StorageLocation;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Position;
@@ -68,16 +66,6 @@ public class SharedInstance extends Instance {
instanceContainer.saveChunksToStorage(callback);
}
- @Override
- public BlockBatch createBlockBatch() {
- return instanceContainer.createBlockBatch();
- }
-
- @Override
- public ChunkBatch createChunkBatch(@NotNull Chunk chunk) {
- return instanceContainer.createChunkBatch(chunk);
- }
-
@Override
public void setChunkGenerator(ChunkGenerator chunkGenerator) {
this.instanceContainer.setChunkGenerator(chunkGenerator);
diff --git a/src/main/java/net/minestom/server/instance/batch/v2/AbsoluteBlockBatch.java b/src/main/java/net/minestom/server/instance/batch/AbsoluteBlockBatch.java
similarity index 98%
rename from src/main/java/net/minestom/server/instance/batch/v2/AbsoluteBlockBatch.java
rename to src/main/java/net/minestom/server/instance/batch/AbsoluteBlockBatch.java
index ea24853b4..2742748e8 100644
--- a/src/main/java/net/minestom/server/instance/batch/v2/AbsoluteBlockBatch.java
+++ b/src/main/java/net/minestom/server/instance/batch/AbsoluteBlockBatch.java
@@ -1,4 +1,4 @@
-package net.minestom.server.instance.batch.v2;
+package net.minestom.server.instance.batch;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
diff --git a/src/main/java/net/minestom/server/instance/batch/v2/Batch.java b/src/main/java/net/minestom/server/instance/batch/Batch.java
similarity index 98%
rename from src/main/java/net/minestom/server/instance/batch/v2/Batch.java
rename to src/main/java/net/minestom/server/instance/batch/Batch.java
index 6706098bf..44093d344 100644
--- a/src/main/java/net/minestom/server/instance/batch/v2/Batch.java
+++ b/src/main/java/net/minestom/server/instance/batch/Batch.java
@@ -1,4 +1,4 @@
-package net.minestom.server.instance.batch.v2;
+package net.minestom.server.instance.batch;
import net.minestom.server.MinecraftServer;
import net.minestom.server.data.Data;
diff --git a/src/main/java/net/minestom/server/instance/batch/BlockBatch.java b/src/main/java/net/minestom/server/instance/batch/BlockBatch.java
deleted file mode 100644
index a9738d334..000000000
--- a/src/main/java/net/minestom/server/instance/batch/BlockBatch.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package net.minestom.server.instance.batch;
-
-import net.minestom.server.data.Data;
-import net.minestom.server.instance.Chunk;
-import net.minestom.server.instance.InstanceContainer;
-import net.minestom.server.instance.block.CustomBlock;
-import net.minestom.server.utils.chunk.ChunkUtils;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class BlockBatch implements InstanceBatch {
- private final InstanceContainer instance;
- private final BatchOption batchOption;
-
- // In the form of
- * Uses chunk coordinate (0-15) instead of world's.
+ * The batch can be placed in any chunk in any instance, however it will always remain
+ * aligned to a chunk border. If completely translatable block changes are needed, use a
+ * {@link RelativeBlockBatch} instead.
+ *
+ * Coordinates are relative to the chunk (0-15) instead of world coordinates.
*
- * @see InstanceBatch
+ * @see Batch
*/
-public class ChunkBatch implements InstanceBatch {
-
- private final InstanceContainer instance;
- private final Chunk chunk;
- private final BatchOption batchOption;
-
- private final boolean generationBatch;
+public class ChunkBatch implements Batch
- * Being a generation batch mean that blocks set are not being stored
- * but are immediately placed on the chunks. Using less memory
- * and CPU cycles.
- *
- * @return true if this batch is part of a chunk generation
- */
- public boolean isGenerationBatch() {
- return generationBatch;
- }
-
- /**
- * Called to fill the chunk batch.
- *
- * @param chunkGenerator the chunk generator
- * @param callback the optional callback executed once the batch is done
- */
- public void flushChunkGenerator(@NotNull ChunkGenerator chunkGenerator, @Nullable ChunkCallback callback) {
- BLOCK_BATCH_POOL.execute(() -> {
- synchronized (chunk) {
- final List
- * So the callback is executed in an unexpected thread, but you are sure that it will be called immediately.
- *
- * @param callback the callback to execute once the blocks are placed
- */
- public void unsafeFlush(@Nullable ChunkCallback callback) {
- Check.stateCondition(generationBatch, "#unsafeFlush is not support for generation batch.");
- BLOCK_BATCH_POOL.execute(() -> singleThreadFlush(callback, false));
- }
-
- /**
- * Resets the chunk batch by removing all the entries.
- */
- public void clearData() {
- Check.stateCondition(generationBatch, "#clearData is not support for generation batch.");
+ @Override
+ public void clear() {
synchronized (blocks) {
this.blocks.clear();
}
}
/**
- * Executes the batch in the current thread.
+ * Apply this batch to chunk (0, 0).
*
- * @param callback the callback to execute once the blocks are placed
- * @param safeCallback true to run the callback in the instance update thread, otherwise run in the current one
+ * @param instance The instance in which the batch should be applied
+ * @param callback The callback to be executed when the batch is applied
*/
- private void singleThreadFlush(@Nullable ChunkCallback callback, boolean safeCallback) {
+ @Override
+ public void apply(@NotNull InstanceContainer instance, @Nullable ChunkCallback callback) {
+ apply(instance, 0, 0, callback);
+ }
+
+ /**
+ * Apply this batch to the given chunk.
+ *
+ * @param instance The instance in which the batch should be applied
+ * @param chunkX The x 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.
+ */
+ public void apply(@NotNull InstanceContainer 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;
+ }
+ apply(instance, chunk, callback);
+ }
+
+ /**
+ * Apply this batch to the given chunk.
+ *
+ * @param instance The instance in which the batch should be applied
+ * @param chunk The target chunk
+ * @param callback The callback to be executed when the batch is applied
+ */
+ public void apply(@NotNull InstanceContainer instance, @NotNull Chunk chunk, @Nullable ChunkCallback callback) {
+ apply(instance, chunk, callback, true);
+ }
+
+ /**
+ * Apply this batch to the given chunk, and execute the callback
+ * immediately when the blocks have been applied, in an unknown thread.
+ *
+ * @param instance The instance in which the batch should be applied
+ * @param chunk The target chunk
+ * @param callback The callback to be executed when the batch is applied
+ */
+ public void unsafeApply(@NotNull InstanceContainer instance, @NotNull Chunk chunk, @Nullable ChunkCallback callback) {
+ apply(instance, chunk, callback, false);
+ }
+
+ /**
+ * Apply this batch to the given chunk, and execute the callback depending on safeCallback.
+ *
+ * @param instance The instance in which the batch should be applied
+ * @param chunk The target chunk
+ * @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
+ */
+ protected void apply(@NotNull InstanceContainer instance, @NotNull Chunk chunk, @Nullable ChunkCallback callback, boolean safeCallback) {
+ BLOCK_BATCH_POOL.execute(() -> singleThreadFlush(instance, chunk, callback, safeCallback));
+ }
+
+ /**
+ * Applies this batch in the current thread, executing the callback upon completion.
+ */
+ private void singleThreadFlush(InstanceContainer instance, Chunk chunk, @Nullable ChunkCallback callback, boolean safeCallback) {
if (blocks.isEmpty()) {
OptionalCallback.execute(callback, chunk);
return;
}
- synchronized (chunk) {
- if (!chunk.isLoaded())
- return;
-
- synchronized (blocks) {
- for (long block : blocks) {
- apply(chunk, block);
- }
- }
-
- updateChunk(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);
+ }
+ }
+
+ updateChunk(instance, chunk, callback, safeCallback);
}
/**
- * Places a block which is encoded in a long.
+ * Applies a single block change given a chunk and a value in the described format.
*
- * @param chunk the chunk to place the block on
- * @param value the block data
+ * @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) {
final short customBlockId = (short) (value & 0xFFFF);
@@ -228,24 +184,24 @@ public class ChunkBatch implements InstanceBatch {
blockId, customBlockId, data, CustomBlockUtils.hasUpdate(customBlockId));
}
- private void updateChunk(@Nullable ChunkCallback callback, boolean safeCallback) {
-
+ /**
+ * Updates the given chunk for all of its viewers, and executes the callback.
+ */
+ private void updateChunk(InstanceContainer instance, Chunk chunk, @Nullable ChunkCallback callback, boolean safeCallback) {
// Refresh chunk for viewers
- if (batchOption.isFullChunk()) {
- chunk.sendChunk();
- } else {
- chunk.sendChunkUpdate();
- }
- this.instance.refreshLastBlockChangeTime();
+ // Formerly this had an option to do a Chunk#sendChunkUpdate
+ // however Chunk#sendChunk does the same including a light update
+ chunk.sendChunk();
+
+ instance.refreshLastBlockChangeTime();
if (callback != null) {
if (safeCallback) {
- this.instance.scheduleNextTick(inst -> callback.accept(chunk));
+ instance.scheduleNextTick(inst -> callback.accept(chunk));
} else {
callback.accept(chunk);
}
}
}
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/minestom/server/instance/batch/ChunkGenerationBatch.java b/src/main/java/net/minestom/server/instance/batch/ChunkGenerationBatch.java
new file mode 100644
index 000000000..35bc283de
--- /dev/null
+++ b/src/main/java/net/minestom/server/instance/batch/ChunkGenerationBatch.java
@@ -0,0 +1,63 @@
+package net.minestom.server.instance.batch;
+
+import net.minestom.server.data.Data;
+import net.minestom.server.instance.Chunk;
+import net.minestom.server.instance.ChunkGenerator;
+import net.minestom.server.instance.ChunkPopulator;
+import net.minestom.server.instance.InstanceContainer;
+import net.minestom.server.utils.block.CustomBlockUtils;
+import net.minestom.server.utils.chunk.ChunkCallback;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public class ChunkGenerationBatch extends ChunkBatch {
+ private final InstanceContainer instance;
+ private final Chunk chunk;
+
+ public ChunkGenerationBatch(InstanceContainer instance, Chunk chunk) {
+ super(null, null);
+
+ this.instance = instance;
+ this.chunk = chunk;
+ }
+
+ @Override
+ public void setSeparateBlocks(int x, int y, int z, short blockStateId, short customBlockId, @Nullable Data data) {
+ chunk.UNSAFE_setBlock(x, y, z, blockStateId, customBlockId, data, CustomBlockUtils.hasUpdate(customBlockId));
+ }
+
+ public void generate(@NotNull ChunkGenerator chunkGenerator, @Nullable ChunkCallback callback) {
+ BLOCK_BATCH_POOL.execute(() -> {
+ synchronized (chunk) {
+ final List
- * Does offer a performance benefit because clients are notified of the changes only once all the blocks are placed.
- */
-public interface InstanceBatch extends BlockModifier {
- ExecutorService BLOCK_BATCH_POOL = new MinestomThread(MinecraftServer.THREAD_COUNT_BLOCK_BATCH, MinecraftServer.THREAD_NAME_BLOCK_BATCH);
-}
diff --git a/src/main/java/net/minestom/server/instance/batch/RelativeBlockBatch.java b/src/main/java/net/minestom/server/instance/batch/RelativeBlockBatch.java
new file mode 100644
index 000000000..20637f731
--- /dev/null
+++ b/src/main/java/net/minestom/server/instance/batch/RelativeBlockBatch.java
@@ -0,0 +1,4 @@
+package net.minestom.server.instance.batch;
+
+public class RelativeBlockBatch {
+}
diff --git a/src/main/java/net/minestom/server/instance/batch/v2/ChunkBatch.java b/src/main/java/net/minestom/server/instance/batch/v2/ChunkBatch.java
deleted file mode 100644
index a7a461383..000000000
--- a/src/main/java/net/minestom/server/instance/batch/v2/ChunkBatch.java
+++ /dev/null
@@ -1,208 +0,0 @@
-package net.minestom.server.instance.batch.v2;
-
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
-import it.unimi.dsi.fastutil.longs.LongArrayList;
-import it.unimi.dsi.fastutil.longs.LongList;
-import net.minestom.server.data.Data;
-import net.minestom.server.instance.Chunk;
-import net.minestom.server.instance.InstanceContainer;
-import net.minestom.server.utils.block.CustomBlockUtils;
-import net.minestom.server.utils.callback.OptionalCallback;
-import net.minestom.server.utils.chunk.ChunkCallback;
-import net.minestom.server.utils.chunk.ChunkUtils;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * 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.
- *
- * The batch can be placed in any chunk in any instance, however it will always remain
- * aligned to a chunk border. If completely translatable block changes are needed, use a
- * {@link RelativeBlockBatch} instead.
- *
- * Coordinates are relative to the chunk (0-15) instead of world coordinates.
- *
- * @see Batch
- */
-public class ChunkBatch implements Batch