From 55f9509c6e680529198a390c41994cdf5540bb4d Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 2 Sep 2024 02:25:04 -0400 Subject: [PATCH] Add a `MinecraftVarintLengthCompositeEncoder` for backend connections (#1419) This is an optimization that has been in BungeeCord for some time, but it's an idea that makes a lot of sense: avoid a memory copy when we don't need to do one. The OS will hopefully be smart enough to use `writev()` or similar for this. --- .../network/BackendChannelInitializer.java | 4 +- ...MinecraftVarintLengthCompositeEncoder.java | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintLengthCompositeEncoder.java diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/BackendChannelInitializer.java b/proxy/src/main/java/com/velocitypowered/proxy/network/BackendChannelInitializer.java index 1e6f387b3..f6fb43ea6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/BackendChannelInitializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/BackendChannelInitializer.java @@ -30,7 +30,7 @@ import com.velocitypowered.proxy.protocol.netty.AutoReadHolderHandler; import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder; import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder; -import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthEncoder; +import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthCompositeEncoder; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.handler.timeout.ReadTimeoutHandler; @@ -55,7 +55,7 @@ public class BackendChannelInitializer extends ChannelInitializer { .addLast(READ_TIMEOUT, new ReadTimeoutHandler(server.getConfiguration().getReadTimeout(), TimeUnit.MILLISECONDS)) - .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) + .addLast(FRAME_ENCODER, MinecraftVarintLengthCompositeEncoder.INSTANCE) .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND)) .addLast(FLOW_HANDLER, new AutoReadHolderHandler()) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintLengthCompositeEncoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintLengthCompositeEncoder.java new file mode 100644 index 000000000..18679b161 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintLengthCompositeEncoder.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018-2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.protocol.netty; + +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageEncoder; +import java.util.List; + +/** + * Handler for appending a length for Minecraft packets using composite buffers. + */ +@ChannelHandler.Sharable +public class MinecraftVarintLengthCompositeEncoder extends MessageToMessageEncoder { + + public static final MinecraftVarintLengthCompositeEncoder INSTANCE = new MinecraftVarintLengthCompositeEncoder(); + + private MinecraftVarintLengthCompositeEncoder() { + } + + @Override + protected void encode(ChannelHandlerContext ctx, ByteBuf buf, + List list) throws Exception { + ByteBuf varIntBuffer = ctx.alloc().ioBuffer(ProtocolUtils.varIntBytes(buf.readableBytes())); + ProtocolUtils.writeVarInt(varIntBuffer, buf.readableBytes()); + list.add(varIntBuffer); + list.add(buf.retain()); + } +}