mirror of
https://github.com/PaperMC/Paper.git
synced 2025-07-31 20:22:05 -07:00
net/minecraft/network/
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -74,13 +_,13 @@
|
||||
public static final Marker PACKET_RECEIVED_MARKER = Util.make(MarkerFactory.getMarker("PACKET_RECEIVED"), marker -> marker.add(PACKET_MARKER));
|
||||
public static final Marker PACKET_SENT_MARKER = Util.make(MarkerFactory.getMarker("PACKET_SENT"), marker -> marker.add(PACKET_MARKER));
|
||||
public static final Supplier<NioEventLoopGroup> NETWORK_WORKER_GROUP = Suppliers.memoize(
|
||||
- () -> new NioEventLoopGroup(0, new ThreadFactoryBuilder().setNameFormat("Netty Client IO #%d").setDaemon(true).build())
|
||||
+ () -> new NioEventLoopGroup(0, new ThreadFactoryBuilder().setNameFormat("Netty Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()) // Paper
|
||||
);
|
||||
public static final Supplier<EpollEventLoopGroup> NETWORK_EPOLL_WORKER_GROUP = Suppliers.memoize(
|
||||
- () -> new EpollEventLoopGroup(0, new ThreadFactoryBuilder().setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).build())
|
||||
+ () -> new EpollEventLoopGroup(0, new ThreadFactoryBuilder().setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()) // Paper
|
||||
);
|
||||
public static final Supplier<DefaultEventLoopGroup> LOCAL_WORKER_GROUP = Suppliers.memoize(
|
||||
- () -> new DefaultEventLoopGroup(0, new ThreadFactoryBuilder().setNameFormat("Netty Local Client IO #%d").setDaemon(true).build())
|
||||
+ () -> new DefaultEventLoopGroup(0, new ThreadFactoryBuilder().setNameFormat("Netty Local Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()) // Paper
|
||||
);
|
||||
private static final ProtocolInfo<ServerHandshakePacketListener> INITIAL_PROTOCOL = HandshakeProtocols.SERVERBOUND;
|
||||
private final PacketFlow receiving;
|
||||
@@ -88,6 +_,11 @@
|
||||
private final Queue<Consumer<Connection>> pendingActions = Queues.newConcurrentLinkedQueue();
|
||||
public Channel channel;
|
||||
public SocketAddress address;
|
||||
+ // Spigot Start
|
||||
+ public java.util.UUID spoofedUUID;
|
||||
+ public com.mojang.authlib.properties.Property[] spoofedProfile;
|
||||
+ public boolean preparing = true;
|
||||
+ // Spigot End
|
||||
@Nullable
|
||||
private volatile PacketListener disconnectListener;
|
||||
@Nullable
|
||||
@@ -106,6 +_,40 @@
|
||||
private volatile DisconnectionDetails delayedDisconnect;
|
||||
@Nullable
|
||||
BandwidthDebugMonitor bandwidthDebugMonitor;
|
||||
+ public String hostname = ""; // CraftBukkit - add field
|
||||
+ // Paper start - NetworkClient implementation
|
||||
+ public int protocolVersion;
|
||||
+ public java.net.InetSocketAddress virtualHost;
|
||||
+ private static boolean enableExplicitFlush = Boolean.getBoolean("paper.explicit-flush"); // Paper - Disable explicit network manager flushing
|
||||
+ // Paper end
|
||||
+ // Paper start - add utility methods
|
||||
+ public final net.minecraft.server.level.ServerPlayer getPlayer() {
|
||||
+ if (this.packetListener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl impl) {
|
||||
+ return impl.player;
|
||||
+ } else if (this.packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl impl) {
|
||||
+ org.bukkit.craftbukkit.entity.CraftPlayer player = impl.getCraftPlayer();
|
||||
+ return player == null ? null : player.getHandle();
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper end - add utility methods
|
||||
+ // Paper start - packet limiter
|
||||
+ protected final Object PACKET_LIMIT_LOCK = new Object();
|
||||
+ protected final @Nullable io.papermc.paper.util.IntervalledCounter allPacketCounts = io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.isEnabled() ? new io.papermc.paper.util.IntervalledCounter(
|
||||
+ (long)(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.interval() * 1.0e9)
|
||||
+ ) : null;
|
||||
+ protected final java.util.Map<Class<? extends net.minecraft.network.protocol.Packet<?>>, io.papermc.paper.util.IntervalledCounter> packetSpecificLimits = new java.util.HashMap<>();
|
||||
+
|
||||
+ private boolean stopReadingPackets;
|
||||
+ private void killForPacketSpam() {
|
||||
+ this.sendPacket(new ClientboundDisconnectPacket(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage)), PacketSendListener.thenRun(() -> {
|
||||
+ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage));
|
||||
+ }), true);
|
||||
+ this.setReadOnly();
|
||||
+ this.stopReadingPackets = true;
|
||||
+ }
|
||||
+ // Paper end - packet limiter
|
||||
+ @Nullable public SocketAddress haProxyAddress; // Paper - Add API to get player's proxy address
|
||||
|
||||
public Connection(PacketFlow receiving) {
|
||||
this.receiving = receiving;
|
||||
@@ -116,6 +_,9 @@
|
||||
super.channelActive(context);
|
||||
this.channel = context.channel();
|
||||
this.address = this.channel.remoteAddress();
|
||||
+ // Spigot Start
|
||||
+ this.preparing = false;
|
||||
+ // Spigot End
|
||||
if (this.delayedDisconnect != null) {
|
||||
this.disconnect(this.delayedDisconnect);
|
||||
}
|
||||
@@ -128,14 +_,31 @@
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext context, Throwable exception) {
|
||||
+ // Paper start - Handle large packets disconnecting client
|
||||
+ if (exception instanceof io.netty.handler.codec.EncoderException && exception.getCause() instanceof PacketEncoder.PacketTooLargeException packetTooLargeException) {
|
||||
+ final Packet<?> packet = packetTooLargeException.getPacket();
|
||||
+ if (packet.packetTooLarge(this)) {
|
||||
+ ProtocolSwapHandler.handleOutboundTerminalPacket(context, packet);
|
||||
+ return;
|
||||
+ } else if (packet.isSkippable()) {
|
||||
+ Connection.LOGGER.debug("Skipping packet due to errors", exception.getCause());
|
||||
+ ProtocolSwapHandler.handleOutboundTerminalPacket(context, packet);
|
||||
+ return;
|
||||
+ } else {
|
||||
+ exception = exception.getCause();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Handle large packets disconnecting client
|
||||
if (exception instanceof SkipPacketException) {
|
||||
LOGGER.debug("Skipping packet due to errors", exception.getCause());
|
||||
} else {
|
||||
boolean flag = !this.handlingFault;
|
||||
this.handlingFault = true;
|
||||
if (this.channel.isOpen()) {
|
||||
+ net.minecraft.server.level.ServerPlayer player = this.getPlayer(); // Paper - Add API for quit reason
|
||||
if (exception instanceof TimeoutException) {
|
||||
LOGGER.debug("Timeout", exception);
|
||||
+ if (player != null) player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.TIMED_OUT; // Paper - Add API for quit reason
|
||||
this.disconnect(Component.translatable("disconnect.timeout"));
|
||||
} else {
|
||||
Component component = Component.translatable("disconnect.genericReason", "Internal Exception: " + exception);
|
||||
@@ -147,9 +_,11 @@
|
||||
disconnectionDetails = new DisconnectionDetails(component);
|
||||
}
|
||||
|
||||
+ if (player != null) player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.ERRONEOUS_STATE; // Paper - Add API for quit reason
|
||||
if (flag) {
|
||||
LOGGER.debug("Failed to sent packet", exception);
|
||||
- if (this.getSending() == PacketFlow.CLIENTBOUND) {
|
||||
+ boolean doesDisconnectExist = this.packetListener.protocol() != ConnectionProtocol.STATUS && this.packetListener.protocol() != ConnectionProtocol.HANDSHAKING; // Paper
|
||||
+ if (this.getSending() == PacketFlow.CLIENTBOUND && doesDisconnectExist) { // Paper
|
||||
Packet<?> packet = (Packet<?>)(this.sendLoginDisconnect
|
||||
? new ClientboundLoginDisconnectPacket(component)
|
||||
: new ClientboundDisconnectPacket(component));
|
||||
@@ -166,6 +_,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
+ if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) io.papermc.paper.util.TraceUtil.printStackTrace(exception); // Spigot // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -175,10 +_,60 @@
|
||||
if (packetListener == null) {
|
||||
throw new IllegalStateException("Received a packet before the packet listener was initialized");
|
||||
} else {
|
||||
+ // Paper start - packet limiter
|
||||
+ if (this.stopReadingPackets) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (this.allPacketCounts != null ||
|
||||
+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.containsKey(packet.getClass())) {
|
||||
+ long time = System.nanoTime();
|
||||
+ synchronized (PACKET_LIMIT_LOCK) {
|
||||
+ if (this.allPacketCounts != null) {
|
||||
+ this.allPacketCounts.updateAndAdd(1, time);
|
||||
+ if (this.allPacketCounts.getRate() >= io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.maxPacketRate()) {
|
||||
+ this.killForPacketSpam();
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (Class<?> check = packet.getClass(); check != Object.class; check = check.getSuperclass()) {
|
||||
+ io.papermc.paper.configuration.GlobalConfiguration.PacketLimiter.PacketLimit packetSpecificLimit =
|
||||
+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.get(check);
|
||||
+ if (packetSpecificLimit == null || !packetSpecificLimit.isEnabled()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ io.papermc.paper.util.IntervalledCounter counter = this.packetSpecificLimits.computeIfAbsent((Class)check, (clazz) -> {
|
||||
+ return new io.papermc.paper.util.IntervalledCounter((long)(packetSpecificLimit.interval() * 1.0e9));
|
||||
+ });
|
||||
+ counter.updateAndAdd(1, time);
|
||||
+ if (counter.getRate() >= packetSpecificLimit.maxPacketRate()) {
|
||||
+ switch (packetSpecificLimit.action()) {
|
||||
+ case DROP:
|
||||
+ return;
|
||||
+ case KICK:
|
||||
+ String deobfedPacketName = io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(check.getName());
|
||||
+
|
||||
+ String playerName;
|
||||
+ if (this.packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl impl) {
|
||||
+ playerName = impl.getOwner().getName();
|
||||
+ } else {
|
||||
+ playerName = this.getLoggableAddress(net.minecraft.server.MinecraftServer.getServer().logIPs());
|
||||
+ }
|
||||
+
|
||||
+ Connection.LOGGER.warn("{} kicked for packet spamming: {}", playerName, deobfedPacketName.substring(deobfedPacketName.lastIndexOf(".") + 1));
|
||||
+ this.killForPacketSpam();
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - packet limiter
|
||||
if (packetListener.shouldHandleMessage(packet)) {
|
||||
try {
|
||||
genericsFtw(packet, packetListener);
|
||||
} catch (RunningOnDifferentThreadException var5) {
|
||||
+ } catch (io.papermc.paper.util.ServerStopRejectedExecutionException ignored) { // Paper - do not prematurely disconnect players on stop
|
||||
} catch (RejectedExecutionException var6) {
|
||||
this.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown"));
|
||||
} catch (ClassCastException var7) {
|
||||
@@ -385,10 +_,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world
|
||||
+ private static int joinAttemptsThisTick; // Paper - Buffer joins to world
|
||||
+ private static int currTick; // Paper - Buffer joins to world
|
||||
public void tick() {
|
||||
this.flushQueue();
|
||||
+ // Paper start - Buffer joins to world
|
||||
+ if (Connection.currTick != net.minecraft.server.MinecraftServer.currentTick) {
|
||||
+ Connection.currTick = net.minecraft.server.MinecraftServer.currentTick;
|
||||
+ Connection.joinAttemptsThisTick = 0;
|
||||
+ }
|
||||
+ // Paper end - Buffer joins to world
|
||||
if (this.packetListener instanceof TickablePacketListener tickablePacketListener) {
|
||||
+ // Paper start - Buffer joins to world
|
||||
+ if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener)
|
||||
+ || loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING
|
||||
+ || Connection.joinAttemptsThisTick++ < MAX_PER_TICK) {
|
||||
tickablePacketListener.tick();
|
||||
+ } // Paper end - Buffer joins to world
|
||||
}
|
||||
|
||||
if (!this.isConnected() && !this.disconnectionHandled) {
|
||||
@@ -396,7 +_,7 @@
|
||||
}
|
||||
|
||||
if (this.channel != null) {
|
||||
- this.channel.flush();
|
||||
+ if (enableExplicitFlush) this.channel.eventLoop().execute(() -> this.channel.flush()); // Paper - Disable explicit network manager flushing; we don't need to explicit flush here, but allow opt in incase issues are found to a better version
|
||||
}
|
||||
|
||||
if (this.tickCount++ % 20 == 0) {
|
||||
@@ -432,12 +_,15 @@
|
||||
}
|
||||
|
||||
public void disconnect(DisconnectionDetails disconnectionDetails) {
|
||||
+ // Spigot Start
|
||||
+ this.preparing = false;
|
||||
+ // Spigot End
|
||||
if (this.channel == null) {
|
||||
this.delayedDisconnect = disconnectionDetails;
|
||||
}
|
||||
|
||||
if (this.isConnected()) {
|
||||
- this.channel.close().awaitUninterruptibly();
|
||||
+ this.channel.close(); // We can't wait as this may be called from an event loop.
|
||||
this.disconnectionDetails = disconnectionDetails;
|
||||
}
|
||||
}
|
||||
@@ -584,6 +_,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - add proper async disconnect
|
||||
+ public void enableAutoRead() {
|
||||
+ if (this.channel != null) {
|
||||
+ this.channel.config().setAutoRead(true);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - add proper async disconnect
|
||||
public void setupCompression(int threshold, boolean validateDecompressed) {
|
||||
if (threshold >= 0) {
|
||||
if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder compressionDecoder) {
|
||||
@@ -597,6 +_,7 @@
|
||||
} else {
|
||||
this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(threshold));
|
||||
}
|
||||
+ this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners
|
||||
} else {
|
||||
if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) {
|
||||
this.channel.pipeline().remove("decompress");
|
||||
@@ -605,6 +_,7 @@
|
||||
if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) {
|
||||
this.channel.pipeline().remove("compress");
|
||||
}
|
||||
+ this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_DISABLED); // Paper - Add Channel initialization listeners
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,6 +_,26 @@
|
||||
);
|
||||
packetListener1.onDisconnect(disconnectionDetails);
|
||||
}
|
||||
+ this.pendingActions.clear(); // Free up packet queue.
|
||||
+ // Paper start - Add PlayerConnectionCloseEvent
|
||||
+ if (packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) {
|
||||
+ /* Player was logged in, either game listener or configuration listener */
|
||||
+ final com.mojang.authlib.GameProfile profile = commonPacketListener.getOwner();
|
||||
+ new com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent(profile.getId(),
|
||||
+ profile.getName(), ((InetSocketAddress) this.address).getAddress(), false).callEvent();
|
||||
+ } else if (packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginListener) {
|
||||
+ /* Player is login stage */
|
||||
+ switch (loginListener.state) {
|
||||
+ case VERIFYING:
|
||||
+ case WAITING_FOR_DUPE_DISCONNECT:
|
||||
+ case PROTOCOL_SWITCHING:
|
||||
+ case ACCEPTED:
|
||||
+ final com.mojang.authlib.GameProfile profile = loginListener.authenticatedProfile; /* Should be non-null at this stage */
|
||||
+ new com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent(profile.getId(), profile.getName(),
|
||||
+ ((InetSocketAddress) this.address).getAddress(), false).callEvent();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Add PlayerConnectionCloseEvent
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
--- a/net/minecraft/network/FriendlyByteBuf.java
|
||||
+++ b/net/minecraft/network/FriendlyByteBuf.java
|
||||
@@ -70,6 +_,7 @@
|
||||
public class FriendlyByteBuf extends ByteBuf {
|
||||
public static final int DEFAULT_NBT_QUOTA = 2097152;
|
||||
private final ByteBuf source;
|
||||
+ @Nullable public final java.util.Locale adventure$locale; // Paper - track player's locale for server-side translations
|
||||
public static final short MAX_STRING_LENGTH = 32767;
|
||||
public static final int MAX_COMPONENT_STRING_LENGTH = 262144;
|
||||
private static final int PUBLIC_KEY_SIZE = 256;
|
||||
@@ -78,6 +_,7 @@
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
public FriendlyByteBuf(ByteBuf source) {
|
||||
+ this.adventure$locale = PacketEncoder.ADVENTURE_LOCALE.get(); // Paper - track player's locale for server-side translations
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@@ -106,8 +_,13 @@
|
||||
}
|
||||
|
||||
public <T> void writeJsonWithCodec(Codec<T> codec, T value) {
|
||||
+ // Paper start - Adventure; add max length parameter
|
||||
+ this.writeJsonWithCodec(codec, value, MAX_STRING_LENGTH);
|
||||
+ }
|
||||
+ public <T> void writeJsonWithCodec(Codec<T> codec, T value, int maxLength) {
|
||||
+ // Paper end - Adventure; add max length parameter
|
||||
DataResult<JsonElement> dataResult = codec.encodeStart(JsonOps.INSTANCE, value);
|
||||
- this.writeUtf(GSON.toJson(dataResult.getOrThrow(exception -> new EncoderException("Failed to encode: " + exception + " " + value))));
|
||||
+ this.writeUtf(GSON.toJson(dataResult.getOrThrow(exception -> new EncoderException("Failed to encode: " + exception + " " + value))), maxLength); // Paper - Adventure; add max length parameter
|
||||
}
|
||||
|
||||
public static <T> IntFunction<T> limitValue(IntFunction<T> function, int limit) {
|
||||
@@ -527,7 +_,7 @@
|
||||
|
||||
try {
|
||||
NbtIo.writeAnyTag(nbt, new ByteBufOutputStream(buffer));
|
||||
- } catch (IOException var3) {
|
||||
+ } catch (Exception var3) { // CraftBukkit - IOException -> Exception
|
||||
throw new EncoderException(var3);
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
--- a/net/minecraft/network/PacketEncoder.java
|
||||
+++ b/net/minecraft/network/PacketEncoder.java
|
||||
@@ -17,11 +_,13 @@
|
||||
this.protocolInfo = protocolInfo;
|
||||
}
|
||||
|
||||
+ static final ThreadLocal<java.util.Locale> ADVENTURE_LOCALE = ThreadLocal.withInitial(() -> null); // Paper - adventure; set player's locale
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext channelHandlerContext, Packet<T> packet, ByteBuf byteBuf) throws Exception {
|
||||
PacketType<? extends Packet<? super T>> packetType = packet.type();
|
||||
|
||||
try {
|
||||
+ ADVENTURE_LOCALE.set(channelHandlerContext.channel().attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).get()); // Paper - adventure; set player's locale
|
||||
this.protocolInfo.codec().encode(byteBuf, packet);
|
||||
int i = byteBuf.readableBytes();
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
@@ -32,14 +_,40 @@
|
||||
|
||||
JvmProfiler.INSTANCE.onPacketSent(this.protocolInfo.id(), packetType, channelHandlerContext.channel().remoteAddress(), i);
|
||||
} catch (Throwable var9) {
|
||||
- LOGGER.error("Error sending packet {}", packetType, var9);
|
||||
+ LOGGER.error("Error sending packet {} (skippable? {})", packetType, packet.isSkippable(), var9);
|
||||
if (packet.isSkippable()) {
|
||||
throw new SkipPacketException(var9);
|
||||
}
|
||||
|
||||
throw var9;
|
||||
} finally {
|
||||
+ // Paper start - Handle large packets disconnecting client
|
||||
+ int packetLength = byteBuf.readableBytes();
|
||||
+ if (packetLength > MAX_PACKET_SIZE || (packetLength > MAX_FINAL_PACKET_SIZE && packet.hasLargePacketFallback())) {
|
||||
+ throw new PacketTooLargeException(packet, packetLength);
|
||||
+ }
|
||||
+ // Paper end - Handle large packets disconnecting client
|
||||
ProtocolSwapHandler.handleOutboundTerminalPacket(channelHandlerContext, packet);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ // packet size is encoded into 3-byte varint
|
||||
+ private static final int MAX_FINAL_PACKET_SIZE = (1 << 21) - 1;
|
||||
+ // Vanilla Max size for the encoder (before compression)
|
||||
+ private static final int MAX_PACKET_SIZE = 8388608;
|
||||
+
|
||||
+ public static class PacketTooLargeException extends RuntimeException {
|
||||
+ private final Packet<?> packet;
|
||||
+
|
||||
+ PacketTooLargeException(Packet<?> packet, int packetLength) {
|
||||
+ super("PacketTooLarge - " + packet.getClass().getSimpleName() + " is " + packetLength + ". Max is " + MAX_PACKET_SIZE);
|
||||
+ this.packet = packet;
|
||||
+ }
|
||||
+
|
||||
+ public Packet<?> getPacket() {
|
||||
+ return this.packet;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
--- a/net/minecraft/network/VarInt.java
|
||||
+++ b/net/minecraft/network/VarInt.java
|
||||
@@ -9,6 +_,18 @@
|
||||
private static final int DATA_BITS_PER_BYTE = 7;
|
||||
|
||||
public static int getByteSize(int data) {
|
||||
+ // Paper start - Optimize VarInts
|
||||
+ return VARINT_EXACT_BYTE_LENGTHS[Integer.numberOfLeadingZeros(data)];
|
||||
+ }
|
||||
+ private static final int[] VARINT_EXACT_BYTE_LENGTHS = new int[33];
|
||||
+ static {
|
||||
+ for (int i = 0; i <= 32; ++i) {
|
||||
+ VARINT_EXACT_BYTE_LENGTHS[i] = (int) Math.ceil((31d - (i - 1)) / 7d);
|
||||
+ }
|
||||
+ VARINT_EXACT_BYTE_LENGTHS[32] = 1; // Special case for the number 0.
|
||||
+ }
|
||||
+ public static int getByteSizeOld(int data) {
|
||||
+ // Paper end - Optimize VarInts
|
||||
for (int i = 1; i < 5; i++) {
|
||||
if ((data & -1 << i * 7) == 0) {
|
||||
return i;
|
||||
@@ -39,6 +_,21 @@
|
||||
}
|
||||
|
||||
public static ByteBuf write(ByteBuf buffer, int value) {
|
||||
+ // Paper start - Optimize VarInts
|
||||
+ // Peel the one and two byte count cases explicitly as they are the most common VarInt sizes
|
||||
+ // that the proxy will write, to improve inlining.
|
||||
+ if ((value & (0xFFFFFFFF << 7)) == 0) {
|
||||
+ buffer.writeByte(value);
|
||||
+ } else if ((value & (0xFFFFFFFF << 14)) == 0) {
|
||||
+ int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
|
||||
+ buffer.writeShort(w);
|
||||
+ } else {
|
||||
+ writeOld(buffer, value);
|
||||
+ }
|
||||
+ return buffer;
|
||||
+ }
|
||||
+ public static ByteBuf writeOld(ByteBuf buffer, int value) {
|
||||
+ // Paper end - Optimize VarInts
|
||||
while ((value & -128) != 0) {
|
||||
buffer.writeByte(value & 127 | 128);
|
||||
value >>>= 7;
|
@@ -0,0 +1,15 @@
|
||||
--- a/net/minecraft/network/Varint21FrameDecoder.java
|
||||
+++ b/net/minecraft/network/Varint21FrameDecoder.java
|
||||
@@ -41,6 +_,12 @@
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext context, ByteBuf in, List<Object> out) {
|
||||
+ // Paper start - Perf: Optimize exception handling; if channel is not active just discard the packet
|
||||
+ if (!context.channel().isActive()) {
|
||||
+ in.skipBytes(in.readableBytes());
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Perf: Optimize exception handling
|
||||
in.markReaderIndex();
|
||||
this.helperBuf.clear();
|
||||
if (!copyVarint(in, this.helperBuf)) {
|
Reference in New Issue
Block a user