diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java index 230071f4d..334354a62 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java @@ -16,6 +16,7 @@ import net.minestom.server.utils.Utils; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.cache.CacheablePacket; import net.minestom.server.utils.cache.TemporaryCache; +import net.minestom.server.utils.cache.TimedBuffer; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.world.biomes.Biome; import org.jetbrains.annotations.NotNull; @@ -27,7 +28,7 @@ import java.util.UUID; public class ChunkDataPacket implements ServerPacket, CacheablePacket { private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager(); - private static final TemporaryCache CACHE = new TemporaryCache<>(10000L); + private static final TemporaryCache CACHE = new TemporaryCache<>(10000L); public boolean fullChunk; public Biome[] biomes; @@ -46,12 +47,12 @@ public class ChunkDataPacket implements ServerPacket, CacheablePacket { private static final int MAX_BUFFER_SIZE = (Short.BYTES + Byte.BYTES + 5 * Byte.BYTES + (4096 * MAX_BITS_PER_ENTRY / Long.SIZE * Long.BYTES)) * CHUNK_SECTION_COUNT + 256 * Integer.BYTES; // Cacheable data - private UUID identifier; - private long lastUpdate; + private final UUID identifier; + private final long timestamp; - public ChunkDataPacket(@Nullable UUID identifier, long lastUpdate) { + public ChunkDataPacket(@Nullable UUID identifier, long timestamp) { this.identifier = identifier; - this.lastUpdate = lastUpdate; + this.timestamp = timestamp; } @Override @@ -139,7 +140,7 @@ public class ChunkDataPacket implements ServerPacket, CacheablePacket { @NotNull @Override - public TemporaryCache getCache() { + public TemporaryCache getCache() { return CACHE; } @@ -147,4 +148,9 @@ public class ChunkDataPacket implements ServerPacket, CacheablePacket { public UUID getIdentifier() { return identifier; } + + @Override + public long getTimestamp() { + return timestamp; + } } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/network/packet/server/play/UpdateLightPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/UpdateLightPacket.java index 55c2fafe5..50dde6143 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/UpdateLightPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/UpdateLightPacket.java @@ -1,11 +1,11 @@ package net.minestom.server.network.packet.server.play; -import io.netty.buffer.ByteBuf; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.cache.CacheablePacket; import net.minestom.server.utils.cache.TemporaryCache; +import net.minestom.server.utils.cache.TimedBuffer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,7 +14,7 @@ import java.util.UUID; public class UpdateLightPacket implements ServerPacket, CacheablePacket { - private static final TemporaryCache CACHE = new TemporaryCache<>(10000L); + private static final TemporaryCache CACHE = new TemporaryCache<>(10000L); public int chunkX; public int chunkZ; @@ -31,12 +31,12 @@ public class UpdateLightPacket implements ServerPacket, CacheablePacket { public List blockLight; // Cacheable data - private UUID identifier; - private long lastUpdate; + private final UUID identifier; + private final long timestamp; - public UpdateLightPacket(@Nullable UUID identifier, long lastUpdate) { + public UpdateLightPacket(@Nullable UUID identifier, long timestamp) { this.identifier = identifier; - this.lastUpdate = lastUpdate; + this.timestamp = timestamp; } @Override @@ -72,7 +72,7 @@ public class UpdateLightPacket implements ServerPacket, CacheablePacket { @NotNull @Override - public TemporaryCache getCache() { + public TemporaryCache getCache() { return CACHE; } @@ -80,4 +80,9 @@ public class UpdateLightPacket implements ServerPacket, CacheablePacket { public UUID getIdentifier() { return identifier; } + + @Override + public long getTimestamp() { + return timestamp; + } } diff --git a/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java b/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java index b60ae5794..e15d8b558 100644 --- a/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java +++ b/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java @@ -18,6 +18,7 @@ import net.minestom.server.network.packet.server.login.SetCompressionPacket; import net.minestom.server.utils.PacketUtils; import net.minestom.server.utils.cache.CacheablePacket; import net.minestom.server.utils.cache.TemporaryCache; +import net.minestom.server.utils.cache.TimedBuffer; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -128,15 +129,25 @@ public class NettyPlayerConnection extends PlayerConnection { // This packet explicitly asks to do not retrieve the cache write(serverPacket); } else { + final long time = cacheablePacket.getTimestamp(); // Try to retrieve the cached buffer - TemporaryCache temporaryCache = cacheablePacket.getCache(); - ByteBuf buffer = temporaryCache.retrieve(identifier); - if (buffer == null) { + TemporaryCache temporaryCache = cacheablePacket.getCache(); + TimedBuffer timedBuffer = temporaryCache.retrieve(identifier); + boolean shouldUpdate = false; + if (timedBuffer == null) { // Buffer not found, create and cache it - buffer = PacketUtils.createFramedPacket(serverPacket, false); - temporaryCache.cache(identifier, buffer); + final ByteBuf buffer = PacketUtils.createFramedPacket(serverPacket, false); + timedBuffer = new TimedBuffer(buffer, time); + shouldUpdate = true; + } else if (time > timedBuffer.getTimestamp()) { // Verify if `serverPacket` is more up-to-date + shouldUpdate = true; } - FramedPacket framedPacket = new FramedPacket(buffer); + + if (shouldUpdate) { + temporaryCache.cache(identifier, timedBuffer); + } + + FramedPacket framedPacket = new FramedPacket(timedBuffer.getBuffer()); write(framedPacket); } diff --git a/src/main/java/net/minestom/server/utils/cache/CacheablePacket.java b/src/main/java/net/minestom/server/utils/cache/CacheablePacket.java index b607fb97a..dcb83fe31 100644 --- a/src/main/java/net/minestom/server/utils/cache/CacheablePacket.java +++ b/src/main/java/net/minestom/server/utils/cache/CacheablePacket.java @@ -1,6 +1,5 @@ package net.minestom.server.utils.cache; -import io.netty.buffer.ByteBuf; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,7 +22,7 @@ public interface CacheablePacket { * @return the temporary packet cache */ @NotNull - TemporaryCache getCache(); + TemporaryCache getCache(); /** * Gets the identifier of this packet. @@ -35,4 +34,11 @@ public interface CacheablePacket { @Nullable UUID getIdentifier(); + /** + * Gets the last time this packet changed. + * + * @return the last packet update time in milliseconds + */ + long getTimestamp(); + } diff --git a/src/main/java/net/minestom/server/utils/cache/TimedBuffer.java b/src/main/java/net/minestom/server/utils/cache/TimedBuffer.java new file mode 100644 index 000000000..a74c8f764 --- /dev/null +++ b/src/main/java/net/minestom/server/utils/cache/TimedBuffer.java @@ -0,0 +1,28 @@ +package net.minestom.server.utils.cache; + +import io.netty.buffer.ByteBuf; +import org.jetbrains.annotations.NotNull; + +/** + * Object containing a {@link ByteBuf buffer} and its timestamp. + * Used for packet-caching to use the most recent. + */ +public class TimedBuffer { + + private final ByteBuf buffer; + private final long timestamp; + + public TimedBuffer(@NotNull ByteBuf buffer, long timestamp) { + this.buffer = buffer; + this.timestamp = timestamp; + } + + @NotNull + public ByteBuf getBuffer() { + return buffer; + } + + public long getTimestamp() { + return timestamp; + } +}