From 01d233f7d8d2f9b9a5e44291e76801446829ee53 Mon Sep 17 00:00:00 2001 From: TheMode Date: Fri, 9 Apr 2021 05:40:40 +0200 Subject: [PATCH] Overall performance improvement --- .../net/minestom/server/UpdateManager.java | 8 ++++++ .../server/instance/InstanceContainer.java | 6 ++-- .../packet/server/play/ChunkDataPacket.java | 4 +-- .../packet/server/play/UpdateLightPacket.java | 8 +++--- .../network/player/NettyPlayerConnection.java | 28 ++++++++----------- .../server/utils/cache/CacheablePacket.java | 19 +++++++++++++ .../utils/cache/TemporaryPacketCache.java | 16 +++++++++++ .../minestom/server/utils/validate/Check.java | 7 +++++ 8 files changed, 69 insertions(+), 27 deletions(-) create mode 100644 src/main/java/net/minestom/server/utils/cache/TemporaryPacketCache.java diff --git a/src/main/java/net/minestom/server/UpdateManager.java b/src/main/java/net/minestom/server/UpdateManager.java index d16841997..5fbfc3779 100644 --- a/src/main/java/net/minestom/server/UpdateManager.java +++ b/src/main/java/net/minestom/server/UpdateManager.java @@ -4,8 +4,10 @@ import com.google.common.collect.Queues; import net.minestom.server.instance.Instance; import net.minestom.server.instance.InstanceManager; import net.minestom.server.network.ConnectionManager; +import net.minestom.server.network.player.NettyPlayerConnection; import net.minestom.server.thread.PerInstanceThreadProvider; import net.minestom.server.thread.ThreadProvider; +import net.minestom.server.utils.async.AsyncUtils; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -80,6 +82,12 @@ public final class UpdateManager { // Tick end callbacks doTickCallback(tickEndCallbacks, tickTime / 1000000L); + // Flush all waiting packets + AsyncUtils.runAsync(() -> connectionManager.getOnlinePlayers().stream() + .filter(player -> player.getPlayerConnection() instanceof NettyPlayerConnection) + .map(player -> (NettyPlayerConnection) player.getPlayerConnection()) + .forEach(NettyPlayerConnection::flush)); + } catch (Exception e) { MinecraftServer.getExceptionManager().handleException(e); } diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index 5f2f67369..d12fb20cd 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -1,8 +1,5 @@ package net.minestom.server.instance; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minestom.server.MinecraftServer; import net.minestom.server.data.Data; import net.minestom.server.data.SerializableData; @@ -34,6 +31,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; @@ -56,7 +54,7 @@ public class InstanceContainer extends Instance { // the chunk generator used, can be null private ChunkGenerator chunkGenerator; // (chunk index -> chunk) map, contains all the chunks in the instance - private final Long2ObjectMap chunks = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); + private final Map chunks = new ConcurrentHashMap<>(); // contains all the chunks to remove during the next instance tick, should be synchronized protected final Set scheduledChunksToRemove = new HashSet<>(); 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 8a5a206fa..2db5515e3 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 @@ -19,6 +19,7 @@ import net.minestom.server.utils.binary.BinaryReader; 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.TemporaryPacketCache; import net.minestom.server.utils.cache.TimedBuffer; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.world.biomes.Biome; @@ -34,8 +35,7 @@ import java.util.concurrent.TimeUnit; public class ChunkDataPacket implements ServerPacket, CacheablePacket { private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager(); - private static final TemporaryCache CACHE = new TemporaryCache<>(5, TimeUnit.MINUTES, - notification -> notification.getValue().getBuffer().release()); + private static final TemporaryCache CACHE = new TemporaryPacketCache(5, TimeUnit.MINUTES); public boolean fullChunk; public Biome[] biomes; 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 3adc315db..9fee9fd22 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 @@ -6,6 +6,7 @@ import net.minestom.server.utils.binary.BinaryReader; 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.TemporaryPacketCache; import net.minestom.server.utils.cache.TimedBuffer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -17,8 +18,7 @@ import java.util.concurrent.TimeUnit; public class UpdateLightPacket implements ServerPacket, CacheablePacket { - private static final TemporaryCache CACHE = new TemporaryCache<>(5, TimeUnit.MINUTES, - notification -> notification.getValue().getBuffer().release()); + private static final TemporaryCache CACHE = new TemporaryPacketCache(5, TimeUnit.MINUTES); public int chunkX; public int chunkZ; @@ -102,7 +102,7 @@ public class UpdateLightPacket implements ServerPacket, CacheablePacket { skyLight.clear(); for (int i = 0; i < 14; i++) { int length = reader.readVarInt(); - if(length != 2048) { + if (length != 2048) { throw new IllegalStateException("Length must be 2048."); } @@ -114,7 +114,7 @@ public class UpdateLightPacket implements ServerPacket, CacheablePacket { blockLight.clear(); for (int i = 0; i < 6; i++) { int length = reader.readVarInt(); - if(length != 2048) { + if (length != 2048) { throw new IllegalStateException("Length must be 2048."); } 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 0efb81a11..1ea494238 100644 --- a/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java +++ b/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java @@ -71,22 +71,6 @@ public class NettyPlayerConnection extends PlayerConnection { this.tickBuffer.ensureWritable(INITIAL_BUFFER_SIZE); } - @Override - public void update() { - // Flush - final int bufferSize = tickBuffer.writerIndex(); - if (bufferSize > 0) { - this.channel.eventLoop().submit(() -> { - if (channel.isActive()) { - writeWaitingPackets(); - channel.flush(); - } - }); - } - // Network stats - super.update(); - } - /** * Sets the encryption key and add the codecs to the pipeline. * @@ -196,7 +180,7 @@ public class NettyPlayerConnection extends PlayerConnection { } } - private void writeWaitingPackets() { + public void writeWaitingPackets() { if (tickBuffer.writerIndex() == 0) { // Nothing to write return; @@ -221,6 +205,16 @@ public class NettyPlayerConnection extends PlayerConnection { } } + public void flush() { + final int bufferSize = tickBuffer.writerIndex(); + if (bufferSize > 0) { + if (channel.isActive()) { + writeWaitingPackets(); + channel.flush(); + } + } + } + @NotNull @Override public SocketAddress getRemoteAddress() { 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 b8507164e..86050351d 100644 --- a/src/main/java/net/minestom/server/utils/cache/CacheablePacket.java +++ b/src/main/java/net/minestom/server/utils/cache/CacheablePacket.java @@ -46,6 +46,9 @@ public interface CacheablePacket { @Nullable static FramedPacket getCache(@NotNull ServerPacket serverPacket) { + if (!(serverPacket instanceof CacheablePacket)) + return null; + final CacheablePacket cacheablePacket = (CacheablePacket) serverPacket; final UUID identifier = cacheablePacket.getIdentifier(); if (identifier == null) { @@ -72,4 +75,20 @@ public interface CacheablePacket { } } + static void writeCache(@NotNull ByteBuf buffer, @NotNull ServerPacket serverPacket) { + FramedPacket framedPacket = CacheablePacket.getCache(serverPacket); + if (framedPacket == null) { + PacketUtils.writeFramedPacket(buffer, serverPacket); + return; + } + final ByteBuf body = framedPacket.getBody(); + synchronized (body) { + if (framedPacket.getBody().refCnt() != 0) { + buffer.writeBytes(body, body.readerIndex(), body.readableBytes()); + } else { + PacketUtils.writeFramedPacket(buffer, serverPacket); + } + } + } + } diff --git a/src/main/java/net/minestom/server/utils/cache/TemporaryPacketCache.java b/src/main/java/net/minestom/server/utils/cache/TemporaryPacketCache.java new file mode 100644 index 000000000..6d6fe1d5e --- /dev/null +++ b/src/main/java/net/minestom/server/utils/cache/TemporaryPacketCache.java @@ -0,0 +1,16 @@ +package net.minestom.server.utils.cache; + +import io.netty.buffer.ByteBuf; + +import java.util.concurrent.TimeUnit; + +public class TemporaryPacketCache extends TemporaryCache { + public TemporaryPacketCache(long duration, TimeUnit timeUnit) { + super(duration, timeUnit, notification -> { + final ByteBuf buffer = notification.getValue().getBuffer(); + synchronized (buffer) { + buffer.release(); + } + }); + } +} \ No newline at end of file diff --git a/src/main/java/net/minestom/server/utils/validate/Check.java b/src/main/java/net/minestom/server/utils/validate/Check.java index 2b6827bd3..14404cf7a 100644 --- a/src/main/java/net/minestom/server/utils/validate/Check.java +++ b/src/main/java/net/minestom/server/utils/validate/Check.java @@ -37,6 +37,13 @@ public final class Check { } } + @Contract("true, _, _ -> fail") + public static void argCondition(boolean condition, @NotNull String reason, Object... arguments) { + if (condition) { + throw new IllegalArgumentException(MessageFormat.format(reason, arguments)); + } + } + @Contract("_ -> fail") public static void fail(@NotNull String reason) { throw new IllegalArgumentException(reason);