From da4216a51ffddbcbd6a4642dcaa10b885e95e3f6 Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 20 Nov 2020 16:37:59 +0100 Subject: [PATCH 1/2] Fixed chunk synchronization during generation and packet sending --- .../net/minestom/server/instance/Chunk.java | 8 +++---- .../server/instance/batch/ChunkBatch.java | 24 ++++++++++--------- .../server/utils/cache/TemporaryCache.java | 6 ++--- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/main/java/net/minestom/server/instance/Chunk.java b/src/main/java/net/minestom/server/instance/Chunk.java index e2327e266..91b046004 100644 --- a/src/main/java/net/minestom/server/instance/Chunk.java +++ b/src/main/java/net/minestom/server/instance/Chunk.java @@ -459,7 +459,7 @@ public abstract class Chunk implements Viewable, DataContainer { * * @param player the player */ - protected void sendChunk(@NotNull Player player) { + protected synchronized void sendChunk(@NotNull Player player) { // Only send loaded chunk if (!isLoaded()) return; @@ -503,7 +503,7 @@ public abstract class Chunk implements Viewable, DataContainer { * * @param player the player to update the chunk to */ - public void sendChunkUpdate(@NotNull Player player) { + public synchronized void sendChunkUpdate(@NotNull Player player) { final PlayerConnection playerConnection = player.getPlayerConnection(); playerConnection.sendPacket(getFreshFullDataPacket()); } @@ -511,7 +511,7 @@ public abstract class Chunk implements Viewable, DataContainer { /** * Sends a full {@link ChunkDataPacket} to all chunk viewers. */ - public void sendChunkUpdate() { + public synchronized void sendChunkUpdate() { final Set chunkViewers = getViewers(); if (!chunkViewers.isEmpty()) { chunkViewers.forEach(player -> { @@ -528,7 +528,7 @@ public abstract class Chunk implements Viewable, DataContainer { * @param player the player to send the packet to * @throws IllegalArgumentException if {@code section} is not a valid section */ - public void sendChunkSectionUpdate(int section, @NotNull Player player) { + public synchronized void sendChunkSectionUpdate(int section, @NotNull Player player) { if (!PlayerUtils.isNettyClient(player)) return; Check.argCondition(!MathUtils.isBetween(section, 0, CHUNK_SECTION_COUNT), 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 40440a5e7..1e7c61567 100644 --- a/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java +++ b/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java @@ -116,21 +116,23 @@ public class ChunkBatch implements InstanceBatch { */ public void flushChunkGenerator(@NotNull ChunkGenerator chunkGenerator, @Nullable ChunkCallback callback) { BLOCK_BATCH_POOL.execute(() -> { - final List populators = chunkGenerator.getPopulators(); - final boolean hasPopulator = populators != null && !populators.isEmpty(); + synchronized (chunk) { + final List populators = chunkGenerator.getPopulators(); + final boolean hasPopulator = populators != null && !populators.isEmpty(); - chunkGenerator.generateChunkData(this, chunk.getChunkX(), chunk.getChunkZ()); + chunkGenerator.generateChunkData(this, chunk.getChunkX(), chunk.getChunkZ()); - if (hasPopulator) { - for (ChunkPopulator chunkPopulator : populators) { - chunkPopulator.populateChunk(this, chunk); + if (hasPopulator) { + for (ChunkPopulator chunkPopulator : populators) { + chunkPopulator.populateChunk(this, chunk); + } } - } - // Safe callback - instance.scheduleNextTick(inst -> { - OptionalCallback.execute(callback, chunk); - }); + // Safe callback + instance.scheduleNextTick(inst -> { + OptionalCallback.execute(callback, chunk); + }); + } }); } diff --git a/src/main/java/net/minestom/server/utils/cache/TemporaryCache.java b/src/main/java/net/minestom/server/utils/cache/TemporaryCache.java index 07ea8a51f..960626a20 100644 --- a/src/main/java/net/minestom/server/utils/cache/TemporaryCache.java +++ b/src/main/java/net/minestom/server/utils/cache/TemporaryCache.java @@ -23,7 +23,7 @@ public class TemporaryCache { // Identifier = time protected ConcurrentHashMap cacheTime = new ConcurrentHashMap<>(); - private long keepTime; + private final long keepTime; /** * Creates a new temporary cache. @@ -42,13 +42,13 @@ public class TemporaryCache { } /** - * Caches an object + * Caches an object. * * @param identifier the object identifier * @param value the object to cache * @param time the current time in milliseconds */ - public synchronized void cacheObject(@NotNull UUID identifier, T value, long time) { + public void cacheObject(@NotNull UUID identifier, T value, long time) { this.cache.put(identifier, value); this.cacheTime.put(identifier, time); } From 7a1a43279a5ab8c2f5f6b9bacca5210d15236fd6 Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 20 Nov 2020 17:13:00 +0100 Subject: [PATCH 2/2] Fixed empty chunk when connecting during its generation --- .../java/net/minestom/server/instance/Chunk.java | 9 ++------- .../server/instance/batch/ChunkBatch.java | 15 ++++++++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/net/minestom/server/instance/Chunk.java b/src/main/java/net/minestom/server/instance/Chunk.java index 91b046004..ce068d7e5 100644 --- a/src/main/java/net/minestom/server/instance/Chunk.java +++ b/src/main/java/net/minestom/server/instance/Chunk.java @@ -17,6 +17,7 @@ import net.minestom.server.network.packet.server.play.ChunkDataPacket; import net.minestom.server.network.packet.server.play.UpdateLightPacket; import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.utils.MathUtils; +import net.minestom.server.utils.PacketUtils; import net.minestom.server.utils.Position; import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.chunk.ChunkCallback; @@ -512,13 +513,7 @@ public abstract class Chunk implements Viewable, DataContainer { * Sends a full {@link ChunkDataPacket} to all chunk viewers. */ public synchronized void sendChunkUpdate() { - final Set chunkViewers = getViewers(); - if (!chunkViewers.isEmpty()) { - chunkViewers.forEach(player -> { - final PlayerConnection playerConnection = player.getPlayerConnection(); - playerConnection.sendPacket(getFreshFullDataPacket()); - }); - } + PacketUtils.sendGroupedPacket(getViewers(), getFreshFullDataPacket()); } /** 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 1e7c61567..aed940473 100644 --- a/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java +++ b/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java @@ -127,12 +127,17 @@ public class ChunkBatch implements InstanceBatch { chunkPopulator.populateChunk(this, chunk); } } - - // Safe callback - instance.scheduleNextTick(inst -> { - OptionalCallback.execute(callback, chunk); - }); } + + // Refresh chunk for viewers + this.chunk.sendChunkUpdate(); + + this.instance.refreshLastBlockChangeTime(); + + // Safe callback + instance.scheduleNextTick(inst -> { + OptionalCallback.execute(callback, chunk); + }); }); }