diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index ad80a9161..31ef34609 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -44,6 +44,8 @@ import com.velocitypowered.proxy.util.bossbar.VelocityBossBar; import com.velocitypowered.proxy.util.ratelimit.Ratelimiter; import com.velocitypowered.proxy.util.ratelimit.Ratelimiters; import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; import java.io.IOException; import java.net.InetSocketAddress; @@ -268,6 +270,10 @@ public class VelocityServer implements ProxyServer { return this.cm.createWorker(group); } + public ChannelInitializer getBackendChannelInitializer() { + return this.cm.backendChannelInitializer.get(); + } + public boolean isShutdown() { return shutdown; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index a7cf3ed82..b91522507 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -80,22 +80,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, // Note: we use the event loop for the connection the player is on. This reduces context // switches. server.createBootstrap(proxyPlayer.getConnection().eventLoop()) - .handler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline() - .addLast(READ_TIMEOUT, - new ReadTimeoutHandler(server.getConfiguration().getReadTimeout(), - TimeUnit.MILLISECONDS)) - .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) - .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) - .addLast(FLOW_HANDLER, new FlowControlHandler()) - .addLast(MINECRAFT_DECODER, - new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND)) - .addLast(MINECRAFT_ENCODER, - new MinecraftEncoder(ProtocolUtils.Direction.SERVERBOUND)); - } - }) + .handler(server.getBackendChannelInitializer()) .connect(registeredServer.getServerInfo().getAddress()) .addListener((ChannelFutureListener) future -> { if (future.isSuccess()) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/BackendChannelInitializer.java b/proxy/src/main/java/com/velocitypowered/proxy/network/BackendChannelInitializer.java new file mode 100644 index 000000000..cb261fc67 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/BackendChannelInitializer.java @@ -0,0 +1,45 @@ +package com.velocitypowered.proxy.network; + +import static com.velocitypowered.proxy.network.Connections.FLOW_HANDLER; +import static com.velocitypowered.proxy.network.Connections.FRAME_DECODER; +import static com.velocitypowered.proxy.network.Connections.FRAME_ENCODER; +import static com.velocitypowered.proxy.network.Connections.MINECRAFT_DECODER; +import static com.velocitypowered.proxy.network.Connections.MINECRAFT_ENCODER; +import static com.velocitypowered.proxy.network.Connections.READ_TIMEOUT; + +import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +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 io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.handler.flow.FlowControlHandler; +import io.netty.handler.timeout.ReadTimeoutHandler; +import java.util.concurrent.TimeUnit; + +@SuppressWarnings("WeakerAccess") +public class BackendChannelInitializer extends ChannelInitializer { + + private final VelocityServer server; + + public BackendChannelInitializer(VelocityServer server) { + this.server = server; + } + + @Override + protected void initChannel(Channel ch) throws Exception { + ch.pipeline() + .addLast(READ_TIMEOUT, + new ReadTimeoutHandler(server.getConfiguration().getReadTimeout(), + TimeUnit.MILLISECONDS)) + .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) + .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) + .addLast(FLOW_HANDLER, new FlowControlHandler()) + .addLast(MINECRAFT_DECODER, + new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND)) + .addLast(MINECRAFT_ENCODER, + new MinecraftEncoder(ProtocolUtils.Direction.SERVERBOUND)); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/BackendChannelInitializerHolder.java b/proxy/src/main/java/com/velocitypowered/proxy/network/BackendChannelInitializerHolder.java new file mode 100644 index 000000000..7da1ab32d --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/BackendChannelInitializerHolder.java @@ -0,0 +1,35 @@ +package com.velocitypowered.proxy.network; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import java.util.function.Supplier; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class BackendChannelInitializerHolder implements Supplier> { + + private static final Logger LOGGER = LogManager.getLogger(ConnectionManager.class); + private ChannelInitializer initializer; + + BackendChannelInitializerHolder(final ChannelInitializer initializer) { + this.initializer = initializer; + } + + @Override + public ChannelInitializer get() { + return this.initializer; + } + + /** + * Sets the channel initializer. + * + * @param initializer the new initializer to use + * @deprecated Internal implementation detail + */ + @Deprecated + public void set(final ChannelInitializer initializer) { + LOGGER.warn("The backend channel initializer has been replaced by {}", + Thread.currentThread().getStackTrace()[2]); + this.initializer = initializer; + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java index 765af2261..649830544 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java @@ -42,10 +42,12 @@ public final class ConnectionManager { private final EventLoopGroup bossGroup; private final EventLoopGroup workerGroup; private final VelocityServer server; - // This is intentionally made public for plugins like ViaVersion, which inject their own + // These are intentionally made public for plugins like ViaVersion, which inject their own // protocol logic into the proxy. @SuppressWarnings("WeakerAccess") public final ServerChannelInitializerHolder serverChannelInitializer; + @SuppressWarnings("WeakerAccess") + public final BackendChannelInitializerHolder backendChannelInitializer; private final DnsAddressResolverGroup resolverGroup; private final AsyncHttpClient httpClient; @@ -62,6 +64,8 @@ public final class ConnectionManager { this.workerGroup = this.transportType.createEventLoopGroup(TransportType.Type.WORKER); this.serverChannelInitializer = new ServerChannelInitializerHolder( new ServerChannelInitializer(this.server)); + this.backendChannelInitializer = new BackendChannelInitializerHolder( + new BackendChannelInitializer(this.server)); this.resolverGroup = new DnsAddressResolverGroup(new DnsNameResolverBuilder() .channelType(this.transportType.datagramChannelClass) .negativeTtl(15) @@ -204,4 +208,8 @@ public final class ConnectionManager { public AsyncHttpClient getHttpClient() { return httpClient; } + + public BackendChannelInitializerHolder getBackendChannelInitializer() { + return this.backendChannelInitializer; + } }