Overall performance improvement

This commit is contained in:
TheMode 2021-04-09 05:40:40 +02:00
parent c2f302ad0e
commit 01d233f7d8
8 changed files with 69 additions and 27 deletions

View File

@ -4,8 +4,10 @@ import com.google.common.collect.Queues;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager; import net.minestom.server.instance.InstanceManager;
import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.player.NettyPlayerConnection;
import net.minestom.server.thread.PerInstanceThreadProvider; import net.minestom.server.thread.PerInstanceThreadProvider;
import net.minestom.server.thread.ThreadProvider; import net.minestom.server.thread.ThreadProvider;
import net.minestom.server.utils.async.AsyncUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
@ -80,6 +82,12 @@ public final class UpdateManager {
// Tick end callbacks // Tick end callbacks
doTickCallback(tickEndCallbacks, tickTime / 1000000L); 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) { } catch (Exception e) {
MinecraftServer.getExceptionManager().handleException(e); MinecraftServer.getExceptionManager().handleException(e);
} }

View File

@ -1,8 +1,5 @@
package net.minestom.server.instance; 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.MinecraftServer;
import net.minestom.server.data.Data; import net.minestom.server.data.Data;
import net.minestom.server.data.SerializableData; import net.minestom.server.data.SerializableData;
@ -34,6 +31,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
@ -56,7 +54,7 @@ public class InstanceContainer extends Instance {
// the chunk generator used, can be null // the chunk generator used, can be null
private ChunkGenerator chunkGenerator; private ChunkGenerator chunkGenerator;
// (chunk index -> chunk) map, contains all the chunks in the instance // (chunk index -> chunk) map, contains all the chunks in the instance
private final Long2ObjectMap<Chunk> chunks = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); private final Map<Long, Chunk> chunks = new ConcurrentHashMap<>();
// contains all the chunks to remove during the next instance tick, should be synchronized // contains all the chunks to remove during the next instance tick, should be synchronized
protected final Set<Chunk> scheduledChunksToRemove = new HashSet<>(); protected final Set<Chunk> scheduledChunksToRemove = new HashSet<>();

View File

@ -19,6 +19,7 @@ import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.cache.CacheablePacket; import net.minestom.server.utils.cache.CacheablePacket;
import net.minestom.server.utils.cache.TemporaryCache; 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.cache.TimedBuffer;
import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.world.biomes.Biome; import net.minestom.server.world.biomes.Biome;
@ -34,8 +35,7 @@ import java.util.concurrent.TimeUnit;
public class ChunkDataPacket implements ServerPacket, CacheablePacket { public class ChunkDataPacket implements ServerPacket, CacheablePacket {
private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager(); private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
private static final TemporaryCache<TimedBuffer> CACHE = new TemporaryCache<>(5, TimeUnit.MINUTES, private static final TemporaryCache<TimedBuffer> CACHE = new TemporaryPacketCache(5, TimeUnit.MINUTES);
notification -> notification.getValue().getBuffer().release());
public boolean fullChunk; public boolean fullChunk;
public Biome[] biomes; public Biome[] biomes;

View File

@ -6,6 +6,7 @@ import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.cache.CacheablePacket; import net.minestom.server.utils.cache.CacheablePacket;
import net.minestom.server.utils.cache.TemporaryCache; 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.cache.TimedBuffer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -17,8 +18,7 @@ import java.util.concurrent.TimeUnit;
public class UpdateLightPacket implements ServerPacket, CacheablePacket { public class UpdateLightPacket implements ServerPacket, CacheablePacket {
private static final TemporaryCache<TimedBuffer> CACHE = new TemporaryCache<>(5, TimeUnit.MINUTES, private static final TemporaryCache<TimedBuffer> CACHE = new TemporaryPacketCache(5, TimeUnit.MINUTES);
notification -> notification.getValue().getBuffer().release());
public int chunkX; public int chunkX;
public int chunkZ; public int chunkZ;
@ -102,7 +102,7 @@ public class UpdateLightPacket implements ServerPacket, CacheablePacket {
skyLight.clear(); skyLight.clear();
for (int i = 0; i < 14; i++) { for (int i = 0; i < 14; i++) {
int length = reader.readVarInt(); int length = reader.readVarInt();
if(length != 2048) { if (length != 2048) {
throw new IllegalStateException("Length must be 2048."); throw new IllegalStateException("Length must be 2048.");
} }
@ -114,7 +114,7 @@ public class UpdateLightPacket implements ServerPacket, CacheablePacket {
blockLight.clear(); blockLight.clear();
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
int length = reader.readVarInt(); int length = reader.readVarInt();
if(length != 2048) { if (length != 2048) {
throw new IllegalStateException("Length must be 2048."); throw new IllegalStateException("Length must be 2048.");
} }

View File

@ -71,22 +71,6 @@ public class NettyPlayerConnection extends PlayerConnection {
this.tickBuffer.ensureWritable(INITIAL_BUFFER_SIZE); 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. * 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) { if (tickBuffer.writerIndex() == 0) {
// Nothing to write // Nothing to write
return; 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 @NotNull
@Override @Override
public SocketAddress getRemoteAddress() { public SocketAddress getRemoteAddress() {

View File

@ -46,6 +46,9 @@ public interface CacheablePacket {
@Nullable @Nullable
static FramedPacket getCache(@NotNull ServerPacket serverPacket) { static FramedPacket getCache(@NotNull ServerPacket serverPacket) {
if (!(serverPacket instanceof CacheablePacket))
return null;
final CacheablePacket cacheablePacket = (CacheablePacket) serverPacket; final CacheablePacket cacheablePacket = (CacheablePacket) serverPacket;
final UUID identifier = cacheablePacket.getIdentifier(); final UUID identifier = cacheablePacket.getIdentifier();
if (identifier == null) { 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);
}
}
}
} }

View File

@ -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<TimedBuffer> {
public TemporaryPacketCache(long duration, TimeUnit timeUnit) {
super(duration, timeUnit, notification -> {
final ByteBuf buffer = notification.getValue().getBuffer();
synchronized (buffer) {
buffer.release();
}
});
}
}

View File

@ -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") @Contract("_ -> fail")
public static void fail(@NotNull String reason) { public static void fail(@NotNull String reason) {
throw new IllegalArgumentException(reason); throw new IllegalArgumentException(reason);