From 02c47a67a956da42ac10039ad3c34aa2603aacbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=84=97=E3=84=A0=CB=8B=20=E3=84=91=E3=84=A7=CB=8A?= Date: Sun, 5 Apr 2020 14:59:10 +0800 Subject: [PATCH] Optimizations for network diff --git a/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java index a85466bc7..324af1a12 100644 --- a/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java +++ b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java @@ -106,7 +106,7 @@ public final class StandardPaperServerListPingEventImpl extends PaperServerListP } // Send response - networkManager.sendPacket(new PacketStatusOutServerInfo(ping)); + networkManager.sendPacketAsync(new PacketStatusOutServerInfo(ping)); // Akarin - Async Sending packets } } diff --git a/src/main/java/net/minecraft/server/HandshakeListener.java b/src/main/java/net/minecraft/server/HandshakeListener.java index 0532f975b..e7be1074b 100644 --- a/src/main/java/net/minecraft/server/HandshakeListener.java +++ b/src/main/java/net/minecraft/server/HandshakeListener.java @@ -39,7 +39,7 @@ public class HandshakeListener implements PacketHandshakingInListener { if (throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - throttleTracker.get(address) < connectionThrottle) { throttleTracker.put(address, currentTime); chatmessage = new ChatMessage(com.destroystokyo.paper.PaperConfig.connectionThrottleKickMessage); // Paper - Configurable connection throttle kick message - this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage)); + this.b.sendPacketAsync(new PacketLoginOutDisconnect(chatmessage)); // Akarin - Async Sending packets this.b.close(chatmessage); return; } @@ -66,11 +66,11 @@ public class HandshakeListener implements PacketHandshakingInListener { if (packethandshakinginsetprotocol.c() > SharedConstants.getGameVersion().getProtocolVersion()) { chatmessage = new ChatMessage( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getGameVersion().getName() ) ); // Spigot - this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage)); + this.b.sendPacketAsync(new PacketLoginOutDisconnect(chatmessage)); this.b.close(chatmessage); } else if (packethandshakinginsetprotocol.c() < SharedConstants.getGameVersion().getProtocolVersion()) { chatmessage = new ChatMessage( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), SharedConstants.getGameVersion().getName() ) ); // Spigot - this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage)); + this.b.sendPacketAsync(new PacketLoginOutDisconnect(chatmessage)); this.b.close(chatmessage); } else { this.b.setPacketListener(new LoginListener(this.a, this.b)); diff --git a/src/main/java/net/minecraft/server/LoginListener.java b/src/main/java/net/minecraft/server/LoginListener.java index f1222fcb2..522cfed4c 100644 --- a/src/main/java/net/minecraft/server/LoginListener.java +++ b/src/main/java/net/minecraft/server/LoginListener.java @@ -111,6 +111,19 @@ public class LoginListener implements PacketLoginInListener { } + // Akarin Start - Async Sending packets + public void disconnectAsync(IChatBaseComponent ichatbasecomponent) { + try { + LoginListener.LOGGER.info("Disconnecting {}: {}", this.d(), ichatbasecomponent.getString()); + this.networkManager.sendPacketAsync(new PacketLoginOutDisconnect(ichatbasecomponent)); + this.networkManager.close(ichatbasecomponent); + } catch (Exception exception) { + LoginListener.LOGGER.error("Error whilst disconnecting player", exception); + } + + } + // Akarin End - Async Sending packets + // Paper start - Cache authenticator threads private static final AtomicInteger threadId = new AtomicInteger(0); private static final java.util.concurrent.ExecutorService authenticatorPool = java.util.concurrent.Executors.newCachedThreadPool( @@ -192,7 +205,7 @@ public class LoginListener implements PacketLoginInListener { this.i = packetlogininstart.b(); if (this.server.getOnlineMode() && !this.networkManager.isLocal()) { this.g = LoginListener.EnumProtocolState.KEY; - this.networkManager.sendPacket(new PacketLoginOutEncryptionBegin("", this.server.getKeyPair().getPublic(), this.e)); + this.networkManager.sendPacketAsync(new PacketLoginOutEncryptionBegin("", this.server.getKeyPair().getPublic(), this.e)); // Akarin - Async Sending packets } else { // Paper start - Velocity support if (com.destroystokyo.paper.PaperConfig.velocitySupport) { @@ -254,7 +267,7 @@ public class LoginListener implements PacketLoginInListener { LoginListener.this.i = LoginListener.this.a(gameprofile); LoginListener.this.g = LoginListener.EnumProtocolState.READY_TO_ACCEPT; } else { - LoginListener.this.disconnect(new ChatMessage("multiplayer.disconnect.unverified_username", new Object[0])); + LoginListener.this.disconnectAsync(new ChatMessage("multiplayer.disconnect.unverified_username", new Object[0])); // Akarin - Async Sending packets LoginListener.LOGGER.error("Username '{}' tried to join with an invalid session", gameprofile.getName()); } } catch (AuthenticationUnavailableException authenticationunavailableexception) { @@ -267,7 +280,7 @@ public class LoginListener implements PacketLoginInListener { if (com.destroystokyo.paper.PaperConfig.authenticationServersDownKickMessage != null) { LoginListener.this.disconnect(new ChatComponentText(com.destroystokyo.paper.PaperConfig.authenticationServersDownKickMessage)); } else // Paper end - LoginListener.this.disconnect(new ChatMessage("multiplayer.disconnect.authservers_down", new Object[0])); + LoginListener.this.disconnectAsync(new ChatMessage("multiplayer.disconnect.authservers_down", new Object[0])); // Akarin - Async Sending packets LoginListener.LOGGER.error("Couldn't verify username because servers are unavailable"); } // CraftBukkit start - catch all exceptions @@ -376,7 +389,7 @@ public class LoginListener implements PacketLoginInListener { return; } // Paper end - this.disconnect(new ChatMessage("multiplayer.disconnect.unexpected_query_response", new Object[0])); + this.disconnectAsync(new ChatMessage("multiplayer.disconnect.unexpected_query_response", new Object[0])); // Akarin - Async Sending packets } protected GameProfile a(GameProfile gameprofile) { diff --git a/src/main/java/net/minecraft/server/NetworkManager.java b/src/main/java/net/minecraft/server/NetworkManager.java index 96a785af2..c5e32e424 100644 --- a/src/main/java/net/minecraft/server/NetworkManager.java +++ b/src/main/java/net/minecraft/server/NetworkManager.java @@ -43,6 +43,8 @@ public class NetworkManager extends SimpleChannelInboundHandler> { }); private final EnumProtocolDirection h; private final Queue packetQueue = Queues.newConcurrentLinkedQueue(); private final Queue getPacketQueue() { return this.packetQueue; } // Paper - OBFHELPER + private boolean handled = false; // Akarin - free packet queue + private EnumProtocol protocol; // Akarin - avoid map lookup public Channel channel; public SocketAddress socketAddress; public void setSpoofedRemoteAddress(SocketAddress address) { this.socketAddress = address; } // Paper - OBFHELPER // Spigot Start @@ -88,6 +90,7 @@ public class NetworkManager extends SimpleChannelInboundHandler> { public void setProtocol(EnumProtocol enumprotocol) { this.channel.attr(NetworkManager.c).set(enumprotocol); + protocol = enumprotocol; // Akarin - avoid map lookup this.channel.config().setAutoRead(true); NetworkManager.LOGGER.debug("Enabled auto read"); } @@ -175,8 +178,8 @@ public class NetworkManager extends SimpleChannelInboundHandler> { private void dispatchPacket(Packet packet, @Nullable GenericFutureListener> genericFutureListener) { this.b(packet, genericFutureListener); } // Paper - OBFHELPER private void b(Packet packet, @Nullable GenericFutureListener> genericfuturelistener) { - EnumProtocol enumprotocol = EnumProtocol.a(packet); - EnumProtocol enumprotocol1 = (EnumProtocol) this.channel.attr(NetworkManager.c).get(); + EnumProtocol enumprotocol = packet.protocol();//EnumProtocol.a(packet); // Akarin - avoid map lookup + EnumProtocol enumprotocol1 = protocol;//(EnumProtocol) this.channel.attr(NetworkManager.c).get(); // Akarin - avoid map lookup ++this.q; if (enumprotocol1 != enumprotocol) { @@ -184,7 +187,7 @@ public class NetworkManager extends SimpleChannelInboundHandler> { this.channel.config().setAutoRead(false); } - if (this.channel.eventLoop().inEventLoop()) { + if (false && this.channel.eventLoop().inEventLoop()) { // Akarin - Async Sending packets if (enumprotocol != enumprotocol1) { this.setProtocol(enumprotocol); } @@ -223,9 +226,51 @@ public class NetworkManager extends SimpleChannelInboundHandler> { } + // Akarin Start - Async Sending packets - multiple packets, copied from above + public void sendPacketAsync(Packet packet) { + EnumProtocol enumprotocol = packet.protocol(); + EnumProtocol enumprotocol1 = protocol; + + ++this.q; + if (enumprotocol1 != enumprotocol) { + NetworkManager.LOGGER.debug("Disabled auto read"); + this.channel.config().setAutoRead(false); + this.setProtocol(enumprotocol); + } + + ChannelFuture channelfuture = this.channel.writeAndFlush(packet); + + channelfuture.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + + } + + public void sendPackets(Packet packet, Packet ...packets) { + EnumProtocol enumprotocol = packet.protocol(); + + ++this.q; + if (protocol != enumprotocol) { + NetworkManager.LOGGER.debug("Disabled auto read"); + this.channel.config().setAutoRead(false); + } + + this.channel.eventLoop().execute(() -> { + if (enumprotocol != protocol) { + this.setProtocol(enumprotocol); + } + + this.channel.write(packet).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + for (Packet pkt : packets) { + this.channel.write(pkt).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + } + this.channel.flush(); + }); + } + // Akarin End + // Paper start - Async-Anti-Xray - Stop dispatching further packets and return false if the peeked packet is a chunk packet which is not ready private boolean sendPacketQueue() { return this.o(); } // OBFHELPER // void -> boolean private boolean o() { // void -> boolean + if (!handled) { // Akarin - free packet queue if (this.channel != null && this.channel.isOpen()) { Queue queue = this.packetQueue; @@ -245,6 +290,8 @@ public class NetworkManager extends SimpleChannelInboundHandler> { } } + handled = true; // Akarin - free packet queue + } // Akarin - free packet queue return true; // Return true if all packets were dispatched } @@ -260,9 +307,9 @@ public class NetworkManager extends SimpleChannelInboundHandler> { ((PlayerConnection) this.packetListener).tick(); } - if (this.channel != null) { - if (enableExplicitFlush) this.channel.eventLoop().execute(() -> this.channel.flush()); // Paper - we don't need to explicit flush here, but allow opt in incase issues are found to a better version - } + //if (this.channel != null) { // Akarin - already did + //if (enableExplicitFlush) this.channel.eventLoop().execute(() -> this.channel.flush()); // Paper - we don't need to explicit flush here, but allow opt in incase issues are found to a better version + //} if (this.t++ % 20 == 0) { this.s = this.s * 0.75F + (float) this.q * 0.25F; diff --git a/src/main/java/net/minecraft/server/Packet.java b/src/main/java/net/minecraft/server/Packet.java index 8d0965a05..7e27cd280 100644 --- a/src/main/java/net/minecraft/server/Packet.java +++ b/src/main/java/net/minecraft/server/Packet.java @@ -20,4 +20,10 @@ public interface Packet { default boolean a() { return false; } + + // Akarin start - add protocol + default EnumProtocol protocol() { + return EnumProtocol.PLAY; + } + // Akarin end } diff --git a/src/main/java/net/minecraft/server/PacketLoginOutCustomPayload.java b/src/main/java/net/minecraft/server/PacketLoginOutCustomPayload.java index 7eb230f1b..d01cac0bd 100644 --- a/src/main/java/net/minecraft/server/PacketLoginOutCustomPayload.java +++ b/src/main/java/net/minecraft/server/PacketLoginOutCustomPayload.java @@ -41,4 +41,11 @@ public class PacketLoginOutCustomPayload implements Packet public void a(PacketLoginOutListener packetloginoutlistener) { packetloginoutlistener.a(this); } + + // Akarin start - add protocol + @Override + public EnumProtocol protocol() { + return EnumProtocol.LOGIN; + } + // Akarin end } diff --git a/src/main/java/net/minecraft/server/PacketLoginOutEncryptionBegin.java b/src/main/java/net/minecraft/server/PacketLoginOutEncryptionBegin.java index b0d6342c3..eeabb54c4 100644 --- a/src/main/java/net/minecraft/server/PacketLoginOutEncryptionBegin.java +++ b/src/main/java/net/minecraft/server/PacketLoginOutEncryptionBegin.java @@ -34,4 +34,11 @@ public class PacketLoginOutEncryptionBegin implements Packet { public void a(PacketLoginOutListener packetloginoutlistener) { packetloginoutlistener.a(this); } + + // Akarin start - add protocol + @Override + public EnumProtocol protocol() { + return EnumProtocol.LOGIN; + } + // Akarin end } diff --git a/src/main/java/net/minecraft/server/PacketStatusListener.java b/src/main/java/net/minecraft/server/PacketStatusListener.java index 4bb21c48b..06af567fc 100644 --- a/src/main/java/net/minecraft/server/PacketStatusListener.java +++ b/src/main/java/net/minecraft/server/PacketStatusListener.java @@ -143,7 +143,7 @@ public class PacketStatusListener implements PacketStatusInListener { @Override public void a(PacketStatusInPing packetstatusinping) { - this.networkManager.sendPacket(new PacketStatusOutPong(packetstatusinping.b())); + this.networkManager.sendPacketAsync(new PacketStatusOutPong(packetstatusinping.b())); // Akarin - Async Sending packets this.networkManager.close(PacketStatusListener.a); } } diff --git a/src/main/java/net/minecraft/server/PacketStatusOutPong.java b/src/main/java/net/minecraft/server/PacketStatusOutPong.java index 94a0da87d..577c6ef9c 100644 --- a/src/main/java/net/minecraft/server/PacketStatusOutPong.java +++ b/src/main/java/net/minecraft/server/PacketStatusOutPong.java @@ -25,4 +25,11 @@ public class PacketStatusOutPong implements Packet { public void a(PacketStatusOutListener packetstatusoutlistener) { packetstatusoutlistener.a(this); } + + // Akarin start - add protocol + @Override + public EnumProtocol protocol() { + return EnumProtocol.STATUS; + } + // Akarin end } diff --git a/src/main/java/net/minecraft/server/PacketStatusOutServerInfo.java b/src/main/java/net/minecraft/server/PacketStatusOutServerInfo.java index 50d5fb62e..4da7a2c1a 100644 --- a/src/main/java/net/minecraft/server/PacketStatusOutServerInfo.java +++ b/src/main/java/net/minecraft/server/PacketStatusOutServerInfo.java @@ -28,4 +28,11 @@ public class PacketStatusOutServerInfo implements Packet