diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index c6ce3cbd1..ff16dbbff 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -44,6 +44,7 @@ import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.Position; import net.minestom.server.utils.binary.BinaryWriter; +import net.minestom.server.utils.chunk.ChunkCallback; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.validate.Check; import net.minestom.server.world.DimensionType; @@ -571,7 +572,7 @@ public class Player extends LivingEntity implements CommandSender { final int chunkX = ChunkUtils.getChunkCoordX(visibleChunk); final int chunkZ = ChunkUtils.getChunkCoordZ(visibleChunk); - Consumer callback = (chunk) -> { + ChunkCallback callback = (chunk) -> { if (chunk != null) { chunk.addViewer(this); if (chunk.getChunkX() == Math.floorDiv((int) getPosition().getX(), 16) && chunk.getChunkZ() == Math.floorDiv((int) getPosition().getZ(), 16)) diff --git a/src/main/java/net/minestom/server/instance/IChunkLoader.java b/src/main/java/net/minestom/server/instance/IChunkLoader.java index dbe993253..7e9d9199e 100644 --- a/src/main/java/net/minestom/server/instance/IChunkLoader.java +++ b/src/main/java/net/minestom/server/instance/IChunkLoader.java @@ -1,6 +1,6 @@ package net.minestom.server.instance; -import java.util.function.Consumer; +import net.minestom.server.utils.chunk.ChunkCallback; /** * Interface implemented to change the way chunks are loaded/saved @@ -17,7 +17,7 @@ public interface IChunkLoader { * @param callback the callback executed when the chunk is done loading * @return true if the chunk loaded successfully, false otherwise */ - boolean loadChunk(Instance instance, int chunkX, int chunkZ, Consumer callback); + boolean loadChunk(Instance instance, int chunkX, int chunkZ, ChunkCallback callback); /** * Save a specific chunk with a callback for when it is done diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index 903624ac8..604efc7f5 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -22,6 +22,7 @@ import net.minestom.server.network.packet.server.play.TimeUpdatePacket; import net.minestom.server.storage.StorageLocation; import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.Position; +import net.minestom.server.utils.chunk.ChunkCallback; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.time.CooldownUtils; import net.minestom.server.utils.time.TimeUnit; @@ -125,7 +126,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta * @param callback consumer called after the chunk has been generated, * the returned chunk will never be null */ - public abstract void loadChunk(int chunkX, int chunkZ, Consumer callback); + public abstract void loadChunk(int chunkX, int chunkZ, ChunkCallback callback); /** * Load the chunk if the chunk is already loaded or if @@ -136,7 +137,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta * @param callback consumer called after the chunk has tried to be loaded, * contains a chunk if it is successful, null otherwise */ - public abstract void loadOptionalChunk(int chunkX, int chunkZ, Consumer callback); + public abstract void loadOptionalChunk(int chunkX, int chunkZ, ChunkCallback callback); /** * Schedule the removal of a chunk, this method does not promise when it will be done @@ -226,9 +227,9 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta */ public abstract void setStorageLocation(StorageLocation storageLocation); - protected abstract void retrieveChunk(int chunkX, int chunkZ, Consumer callback); + protected abstract void retrieveChunk(int chunkX, int chunkZ, ChunkCallback callback); - protected abstract void createChunk(int chunkX, int chunkZ, Consumer callback); + protected abstract void createChunk(int chunkX, int chunkZ, ChunkCallback callback); /** * When set to true, chunks will load with players moving closer @@ -489,13 +490,13 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta * @param position the chunk position * @param callback the callback to run when the chunk is loaded */ - public void loadChunk(Position position, Consumer callback) { + public void loadChunk(Position position, ChunkCallback callback) { final int chunkX = ChunkUtils.getChunkCoordinate((int) position.getX()); final int chunkZ = ChunkUtils.getChunkCoordinate((int) position.getZ()); loadChunk(chunkX, chunkZ, callback); } - public void loadOptionalChunk(Position position, Consumer callback) { + public void loadOptionalChunk(Position position, ChunkCallback callback) { final int chunkX = ChunkUtils.getChunkCoordinate((int) position.getX()); final int chunkZ = ChunkUtils.getChunkCoordinate((int) position.getZ()); loadOptionalChunk(chunkX, chunkZ, callback); diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index 4acd67ac7..dfb62893b 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -23,6 +23,7 @@ import net.minestom.server.storage.StorageLocation; import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.Position; import net.minestom.server.utils.block.CustomBlockUtils; +import net.minestom.server.utils.chunk.ChunkCallback; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.thread.MinestomThread; import net.minestom.server.utils.time.TimeUnit; @@ -38,7 +39,6 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.BiFunction; -import java.util.function.Consumer; /** * InstanceContainer is an instance that contains chunks in contrary to SharedInstance. @@ -338,7 +338,7 @@ public class InstanceContainer extends Instance { } @Override - public void loadChunk(int chunkX, int chunkZ, Consumer callback) { + public void loadChunk(int chunkX, int chunkZ, ChunkCallback callback) { final Chunk chunk = getChunk(chunkX, chunkZ); if (chunk != null) { // Chunk already loaded @@ -351,7 +351,7 @@ public class InstanceContainer extends Instance { } @Override - public void loadOptionalChunk(int chunkX, int chunkZ, Consumer callback) { + public void loadOptionalChunk(int chunkX, int chunkZ, ChunkCallback callback) { final Chunk chunk = getChunk(chunkX, chunkZ); if (chunk != null) { // Chunk already loaded @@ -463,7 +463,7 @@ public class InstanceContainer extends Instance { } @Override - protected void retrieveChunk(int chunkX, int chunkZ, Consumer callback) { + protected void retrieveChunk(int chunkX, int chunkZ, ChunkCallback callback) { final boolean loaded = chunkLoader.loadChunk(this, chunkX, chunkZ, chunk -> { cacheChunk(chunk); callChunkLoadEvent(chunkX, chunkZ); @@ -479,7 +479,7 @@ public class InstanceContainer extends Instance { } @Override - protected void createChunk(int chunkX, int chunkZ, Consumer callback) { + protected void createChunk(int chunkX, int chunkZ, ChunkCallback callback) { Biome[] biomes = new Biome[Chunk.BIOME_COUNT]; if (chunkGenerator == null) { Arrays.fill(biomes, MinecraftServer.getBiomeManager().getById(0)); @@ -646,7 +646,9 @@ public class InstanceContainer extends Instance { // Unload all waiting chunks UNSAFE_unloadChunks(); + // Time/world border super.tick(time); + Lock wrlock = changingBlockLock.writeLock(); wrlock.lock(); currentlyChangingBlocks.clear(); diff --git a/src/main/java/net/minestom/server/instance/MinestomBasicChunkLoader.java b/src/main/java/net/minestom/server/instance/MinestomBasicChunkLoader.java index 6ad54806c..dd70f39cd 100644 --- a/src/main/java/net/minestom/server/instance/MinestomBasicChunkLoader.java +++ b/src/main/java/net/minestom/server/instance/MinestomBasicChunkLoader.java @@ -2,11 +2,10 @@ package net.minestom.server.instance; import net.minestom.server.reader.ChunkReader; import net.minestom.server.storage.StorageLocation; +import net.minestom.server.utils.chunk.ChunkCallback; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.function.Consumer; - public class MinestomBasicChunkLoader implements IChunkLoader { private final static Logger LOGGER = LoggerFactory.getLogger(MinestomBasicChunkLoader.class); @@ -42,7 +41,7 @@ public class MinestomBasicChunkLoader implements IChunkLoader { } @Override - public boolean loadChunk(Instance instance, int chunkX, int chunkZ, Consumer callback) { + public boolean loadChunk(Instance instance, int chunkX, int chunkZ, ChunkCallback callback) { final byte[] bytes = storageLocation == null ? null : storageLocation.get(getChunkKey(chunkX, chunkZ)); if (bytes == null) { diff --git a/src/main/java/net/minestom/server/instance/SharedInstance.java b/src/main/java/net/minestom/server/instance/SharedInstance.java index 78d2d2bb3..1df2661b4 100644 --- a/src/main/java/net/minestom/server/instance/SharedInstance.java +++ b/src/main/java/net/minestom/server/instance/SharedInstance.java @@ -7,11 +7,11 @@ 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; +import net.minestom.server.utils.chunk.ChunkCallback; import net.minestom.server.utils.time.TimeUnit; import java.util.Collection; import java.util.UUID; -import java.util.function.Consumer; /** * The {@link SharedInstance} is an instance that shares the same chunks as its linked {@link InstanceContainer}, @@ -37,12 +37,12 @@ public class SharedInstance extends Instance { } @Override - public void loadChunk(int chunkX, int chunkZ, Consumer callback) { + public void loadChunk(int chunkX, int chunkZ, ChunkCallback callback) { instanceContainer.loadChunk(chunkX, chunkZ, callback); } @Override - public void loadOptionalChunk(int chunkX, int chunkZ, Consumer callback) { + public void loadOptionalChunk(int chunkX, int chunkZ, ChunkCallback callback) { instanceContainer.loadOptionalChunk(chunkX, chunkZ, callback); } @@ -102,12 +102,12 @@ public class SharedInstance extends Instance { } @Override - public void retrieveChunk(int chunkX, int chunkZ, Consumer callback) { + public void retrieveChunk(int chunkX, int chunkZ, ChunkCallback callback) { instanceContainer.retrieveChunk(chunkX, chunkZ, callback); } @Override - protected void createChunk(int chunkX, int chunkZ, Consumer callback) { + protected void createChunk(int chunkX, int chunkZ, ChunkCallback callback) { instanceContainer.createChunk(chunkX, chunkZ, callback); } diff --git a/src/main/java/net/minestom/server/instance/batch/BlockBatch.java b/src/main/java/net/minestom/server/instance/batch/BlockBatch.java index 12ca13479..25d8066c7 100644 --- a/src/main/java/net/minestom/server/instance/batch/BlockBatch.java +++ b/src/main/java/net/minestom/server/instance/batch/BlockBatch.java @@ -79,9 +79,13 @@ public class BlockBatch implements InstanceBatch { final boolean isLast = counter.incrementAndGet() == data.size(); + // Execute the callback if this was the last chunk to process if (isLast) { - if (callback != null) - callback.run(); + if (callback != null) { + instance.scheduleNextTick(inst -> { + callback.run(); + }); + } } } diff --git a/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java b/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java index 029794676..fa318186f 100644 --- a/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java +++ b/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java @@ -7,11 +7,11 @@ import net.minestom.server.instance.ChunkPopulator; import net.minestom.server.instance.InstanceContainer; import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.utils.block.CustomBlockUtils; +import net.minestom.server.utils.chunk.ChunkCallback; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.function.Consumer; /** * Use chunk coordinate (0-16) instead of world's @@ -60,7 +60,7 @@ public class ChunkBatch implements InstanceBatch { this.dataList.add(blockData); } - public void flushChunkGenerator(ChunkGenerator chunkGenerator, Consumer callback) { + public void flushChunkGenerator(ChunkGenerator chunkGenerator, ChunkCallback callback) { batchesPool.execute(() -> { final List populators = chunkGenerator.getPopulators(); final boolean hasPopulator = populators != null && !populators.isEmpty(); @@ -81,7 +81,7 @@ public class ChunkBatch implements InstanceBatch { }); } - public void flush(Consumer callback) { + public void flush(ChunkCallback callback) { batchesPool.execute(() -> { singleThreadFlush(callback); }); @@ -91,7 +91,7 @@ public class ChunkBatch implements InstanceBatch { dataList.clear(); } - private void singleThreadFlush(Consumer callback) { + private void singleThreadFlush(ChunkCallback callback) { synchronized (dataList) { synchronized (chunk) { if (!chunk.isLoaded()) @@ -104,8 +104,11 @@ public class ChunkBatch implements InstanceBatch { // Refresh chunk for viewers chunk.sendChunkUpdate(); - if (callback != null) - callback.accept(chunk); + if (callback != null) { + instance.scheduleNextTick(inst -> { + callback.accept(chunk); + }); + } } } } diff --git a/src/main/java/net/minestom/server/reader/ChunkReader.java b/src/main/java/net/minestom/server/reader/ChunkReader.java index 47ce77100..f1bbceaf4 100644 --- a/src/main/java/net/minestom/server/reader/ChunkReader.java +++ b/src/main/java/net/minestom/server/reader/ChunkReader.java @@ -8,12 +8,11 @@ import net.minestom.server.instance.DynamicChunk; import net.minestom.server.instance.Instance; import net.minestom.server.instance.batch.ChunkBatch; import net.minestom.server.utils.binary.BinaryReader; +import net.minestom.server.utils.chunk.ChunkCallback; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.world.biomes.Biome; import net.minestom.server.world.biomes.BiomeManager; -import java.util.function.Consumer; - public class ChunkReader { private static final BiomeManager BIOME_MANAGER = MinecraftServer.getBiomeManager(); @@ -29,7 +28,7 @@ public class ChunkReader { * @param chunkZ the chunk Z * @param callback the consumer called once the chunk has been read */ - public static void readChunk(byte[] b, Instance instance, int chunkX, int chunkZ, Consumer callback) { + public static void readChunk(byte[] b, Instance instance, int chunkX, int chunkZ, ChunkCallback callback) { BinaryReader binaryReader = new BinaryReader(b); // Used for blocks data diff --git a/src/main/java/net/minestom/server/utils/chunk/ChunkCallback.java b/src/main/java/net/minestom/server/utils/chunk/ChunkCallback.java new file mode 100644 index 000000000..88664e44d --- /dev/null +++ b/src/main/java/net/minestom/server/utils/chunk/ChunkCallback.java @@ -0,0 +1,8 @@ +package net.minestom.server.utils.chunk; + +import net.minestom.server.instance.Chunk; + +import java.util.function.Consumer; + +public interface ChunkCallback extends Consumer { +}