Added support for EaglerCraft clients

This commit is contained in:
RaphiMC 2023-04-07 19:15:43 +02:00
parent 8da007c0a4
commit 4494920acd
9 changed files with 415 additions and 7 deletions

View File

@ -16,6 +16,8 @@ For a full user guide go to the [Usage for Players](#usage-for-players-gui) sect
## Supported Client versions ## Supported Client versions
- Release (1.7.2 - 1.19.4) - Release (1.7.2 - 1.19.4)
- Classic, Alpha, Beta, Release 1.0 - 1.6.4 (Only passthrough)
- Eaglercraft 1.8
ViaProxy supports joining to any of the listed server version from any of the listed client versions. ViaProxy supports joining to any of the listed server version from any of the listed client versions.

View File

@ -59,6 +59,7 @@ public class Options {
public static String RESOURCE_PACK_URL; // Example: http://example.com/resourcepack.zip public static String RESOURCE_PACK_URL; // Example: http://example.com/resourcepack.zip
public static boolean SERVER_HAPROXY_PROTOCOL; public static boolean SERVER_HAPROXY_PROTOCOL;
public static boolean LEGACY_CLIENT_PASSTHROUGH; public static boolean LEGACY_CLIENT_PASSTHROUGH;
public static boolean ALLOW_EAGLERCRAFT_CLIENTS;
public static void parse(final String[] args) throws IOException { public static void parse(final String[] args) throws IOException {
final OptionParser parser = new OptionParser(); final OptionParser parser = new OptionParser();
@ -79,7 +80,8 @@ public class Options {
final OptionSpec<String> resourcePackUrl = parser.acceptsAll(asList("resource_pack_url", "resource_pack", "rpu", "rp"), "URL of a resource pack which clients can optionally download").withRequiredArg().ofType(String.class); final OptionSpec<String> resourcePackUrl = parser.acceptsAll(asList("resource_pack_url", "resource_pack", "rpu", "rp"), "URL of a resource pack which clients can optionally download").withRequiredArg().ofType(String.class);
final OptionSpec<String> proxyUrl = parser.acceptsAll(asList("proxy_url", "proxy"), "URL of a SOCKS(4/5)/HTTP(S) proxy which will be used for backend TCP connections").withRequiredArg().ofType(String.class); final OptionSpec<String> proxyUrl = parser.acceptsAll(asList("proxy_url", "proxy"), "URL of a SOCKS(4/5)/HTTP(S) proxy which will be used for backend TCP connections").withRequiredArg().ofType(String.class);
final OptionSpec<Void> serverHaProxyProtocol = parser.acceptsAll(asList("server-haproxy-protocol", "server-haproxy"), "Send HAProxy protocol messages to the backend server"); final OptionSpec<Void> serverHaProxyProtocol = parser.acceptsAll(asList("server-haproxy-protocol", "server-haproxy"), "Send HAProxy protocol messages to the backend server");
final OptionSpec<Void> legacyClientPassthrough = parser.acceptsAll(asList("legacy_client_passthrough", "legacy_passthrough"), "Allow <= 1.6.4 clients to connect to the backend server"); final OptionSpec<Void> legacyClientPassthrough = parser.acceptsAll(asList("legacy_client_passthrough", "legacy_passthrough"), "Allow <= 1.6.4 clients to connect to the backend server (No protocol translation)");
final OptionSpec<Void> allowEaglerCraftClients = parser.acceptsAll(asList("allow_eaglercraft_clients", "allow_eaglercraft"), "Allow EaglerCraft clients to connect to ViaProxy");
PluginManager.EVENT_MANAGER.call(new PreOptionsParseEvent(parser)); PluginManager.EVENT_MANAGER.call(new PreOptionsParseEvent(parser));
final OptionSet options = parser.parse(args); final OptionSet options = parser.parse(args);
@ -119,6 +121,7 @@ public class Options {
} }
SERVER_HAPROXY_PROTOCOL = options.has(serverHaProxyProtocol); SERVER_HAPROXY_PROTOCOL = options.has(serverHaProxyProtocol);
LEGACY_CLIENT_PASSTHROUGH = options.has(legacyClientPassthrough); LEGACY_CLIENT_PASSTHROUGH = options.has(legacyClientPassthrough);
ALLOW_EAGLERCRAFT_CLIENTS = options.has(allowEaglerCraftClients);
PluginManager.EVENT_MANAGER.call(new PostOptionsParseEvent(options)); PluginManager.EVENT_MANAGER.call(new PostOptionsParseEvent(options));
} }

View File

@ -26,11 +26,24 @@ import net.raphimc.viaproxy.cli.options.Options;
import net.raphimc.viaproxy.plugins.PluginManager; import net.raphimc.viaproxy.plugins.PluginManager;
import net.raphimc.viaproxy.plugins.events.Client2ProxyChannelInitializeEvent; import net.raphimc.viaproxy.plugins.events.Client2ProxyChannelInitializeEvent;
import net.raphimc.viaproxy.plugins.events.types.ITyped; import net.raphimc.viaproxy.plugins.events.types.ITyped;
import net.raphimc.viaproxy.proxy.client2proxy.eaglercraft.EaglercraftInitialHandler;
import net.raphimc.viaproxy.proxy.client2proxy.passthrough.LegacyClientPassthroughHandler;
import java.util.function.Supplier; import java.util.function.Supplier;
public class Client2ProxyChannelInitializer extends MinecraftChannelInitializer { public class Client2ProxyChannelInitializer extends MinecraftChannelInitializer {
public static final String EAGLERCRAFT_INITIAL_HANDLER_NAME = "eaglercraft-initial-handler";
public static final String WEBSOCKET_SSL_HANDLER_NAME = "ws-ssl-handler";
public static final String WEBSOCKET_HTTP_CODEC_NAME = "ws-http-codec";
public static final String WEBSOCKET_HTTP_AGGREGATOR_NAME = "ws-http-aggregator";
public static final String WEBSOCKET_COMPRESSION_NAME = "ws-compression";
public static final String WEBSOCKET_HANDLER_NAME = "ws-handler";
public static final String WEBSOCKET_ACTIVE_NOTIFIER_NAME = "ws-active-notifier";
public static final String EAGLERCRAFT_HANDLER_NAME = "eaglercraft-handler";
public static final String LEGACY_PASSTHROUGH_HANDLER_NAME = "legacy-passthrough-handler";
public Client2ProxyChannelInitializer(final Supplier<ChannelHandler> handlerSupplier) { public Client2ProxyChannelInitializer(final Supplier<ChannelHandler> handlerSupplier) {
super(handlerSupplier); super(handlerSupplier);
} }
@ -42,9 +55,13 @@ public class Client2ProxyChannelInitializer extends MinecraftChannelInitializer
return; return;
} }
if (Options.LEGACY_CLIENT_PASSTHROUGH) { if (Options.ALLOW_EAGLERCRAFT_CLIENTS) {
channel.pipeline().addLast("legacy-passthrough-handler", new LegacyClientPassthroughHandler()); channel.pipeline().addLast(EAGLERCRAFT_INITIAL_HANDLER_NAME, new EaglercraftInitialHandler());
} }
if (Options.LEGACY_CLIENT_PASSTHROUGH) {
channel.pipeline().addLast(LEGACY_PASSTHROUGH_HANDLER_NAME, new LegacyClientPassthroughHandler());
}
super.initChannel(channel); super.initChannel(channel);
channel.attr(MCPipeline.PACKET_REGISTRY_ATTRIBUTE_KEY).set(PacketRegistryUtil.getHandshakeRegistry(false)); channel.attr(MCPipeline.PACKET_REGISTRY_ATTRIBUTE_KEY).set(PacketRegistryUtil.getHandshakeRegistry(false));

View File

@ -0,0 +1,266 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2023 RK_01/RaphiMC and 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 <http://www.gnu.org/licenses/>.
*/
package net.raphimc.viaproxy.proxy.client2proxy.eaglercraft;
import com.google.common.net.HostAndPort;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import net.raphimc.netminecraft.constants.ConnectionState;
import net.raphimc.netminecraft.constants.MCPackets;
import net.raphimc.netminecraft.constants.MCPipeline;
import net.raphimc.netminecraft.packet.PacketTypes;
import net.raphimc.viaproxy.ViaProxy;
import net.raphimc.viaproxy.util.logging.Logger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
// Thanks to ayunami2000 for helping with the eaglercraft protocol
public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, ByteBuf> {
private static final int CLIENT_VERSION = 0x01;
private static final int SERVER_VERSION = 0x02;
private static final int VERSION_MISMATCH = 0x03;
private static final int CLIENT_REQUEST_LOGIN = 0x04;
private static final int SERVER_ALLOW_LOGIN = 0x05;
private static final int SERVER_DENY_LOGIN = 0x06;
private static final int CLIENT_PROFILE_DATA = 0x07;
private static final int CLIENT_FINISH_LOGIN = 0x08;
private static final int SERVER_FINISH_LOGIN = 0x09;
private static final int SERVER_ERROR = 0xFF;
private HostAndPort host;
private State state = State.PRE_HANDSHAKE;
private int protocolVersion;
private String username;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).set(-2); // Disable automatic compression in Proxy2ServerHandler
ctx.pipeline().remove(MCPipeline.SIZER_HANDLER_NAME);
super.channelActive(ctx);
}
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
if (this.state != State.LOGIN_COMPLETE) {
throw new IllegalStateException("Cannot send packets before login is completed");
}
out.add(new BinaryWebSocketFrame(in.retain()));
}
@Override
protected void decode(ChannelHandlerContext ctx, WebSocketFrame in, List<Object> out) {
if (in instanceof BinaryWebSocketFrame) {
final ByteBuf data = in.content();
switch (this.state) {
case PRE_HANDSHAKE:
if (data.readableBytes() >= 2) { // Check for legacy client
if (data.getByte(0) == (byte) 2 && data.getByte(1) == (byte) 69) {
throw new IllegalStateException("Your client is not yet supported");
}
}
this.state = State.HANDSHAKE;
case HANDSHAKE:
int packetId = data.readUnsignedByte(); // packet id
if (packetId == CLIENT_VERSION) {
int eaglercraftVersion = data.readUnsignedByte(); // eaglercraft version
final int minecraftVersion;
if (eaglercraftVersion == 1) {
minecraftVersion = data.readUnsignedByte(); // minecraft version
} else if (eaglercraftVersion == 2) {
int count = data.readUnsignedShort(); // eaglercraft versions
final List<Integer> eaglercraftVersions = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
eaglercraftVersions.add(data.readUnsignedShort()); // eaglercraft version id
}
if (!eaglercraftVersions.contains(2) && !eaglercraftVersions.contains(3)) {
Logger.LOGGER.error("No supported eaglercraft versions found");
ctx.close();
return;
}
if (eaglercraftVersions.contains(3)) {
eaglercraftVersion = 3;
}
count = data.readUnsignedShort(); // minecraft versions
final List<Integer> minecraftVersions = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
minecraftVersions.add(data.readUnsignedShort()); // minecraft version id
}
if (minecraftVersions.size() != 1) {
Logger.LOGGER.error("No supported minecraft versions found");
ctx.close();
}
minecraftVersion = minecraftVersions.get(0);
} else {
throw new IllegalArgumentException("Unknown Eaglercraft version: " + eaglercraftVersion);
}
final String clientBrand = data.readCharSequence(data.readUnsignedByte(), StandardCharsets.US_ASCII).toString(); // client brand
final String clientVersionString = data.readCharSequence(data.readUnsignedByte(), StandardCharsets.US_ASCII).toString(); // client version
if (eaglercraftVersion >= 2) {
data.skipBytes(1); // auth enabled
data.skipBytes(data.readUnsignedByte()); // auth username
}
if (data.isReadable()) {
throw new IllegalArgumentException("Too much data in packet: " + data.readableBytes() + " bytes");
}
this.state = State.HANDSHAKE_COMPLETE;
this.protocolVersion = minecraftVersion;
Logger.LOGGER.info("Eaglercraft client connected: " + clientBrand + " " + clientVersionString);
final String serverBrand = "ViaProxy";
final String serverVersionString = ViaProxy.VERSION;
final ByteBuf response = ctx.alloc().buffer();
response.writeByte(SERVER_VERSION); // packet id
if (eaglercraftVersion == 1) {
response.writeByte(1); // eaglercraft version
} else {
response.writeShort(eaglercraftVersion); // eaglercraft version
response.writeShort(minecraftVersion); // minecraft version
}
response.writeByte(serverBrand.length()).writeCharSequence(serverBrand, StandardCharsets.US_ASCII); // server brand
response.writeByte(serverVersionString.length()).writeCharSequence(serverVersionString, StandardCharsets.US_ASCII); // server version
response.writeByte(0); // auth method
response.writeShort(0); // salt length
ctx.writeAndFlush(new BinaryWebSocketFrame(response));
} else {
throw new IllegalStateException("Unexpected packet id " + packetId + " in state " + this.state);
}
break;
case HANDSHAKE_COMPLETE:
packetId = data.readUnsignedByte(); // packet id
if (packetId == CLIENT_REQUEST_LOGIN) {
final String username = data.readCharSequence(data.readUnsignedByte(), StandardCharsets.US_ASCII).toString(); // username
data.readCharSequence(data.readUnsignedByte(), StandardCharsets.US_ASCII).toString(); // requested server
data.skipBytes(data.readUnsignedByte()); // auth password
if (data.isReadable()) {
throw new IllegalArgumentException("Too much data in packet: " + data.readableBytes() + " bytes");
}
this.state = State.LOGIN;
this.username = username;
final UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
final ByteBuf response = ctx.alloc().buffer();
response.writeByte(SERVER_ALLOW_LOGIN); // packet id
response.writeByte(username.length()).writeCharSequence(username, StandardCharsets.US_ASCII); // username
response.writeLong(uuid.getMostSignificantBits()).writeLong(uuid.getLeastSignificantBits()); // uuid
ctx.writeAndFlush(new BinaryWebSocketFrame(response));
} else {
throw new IllegalStateException("Unexpected packet id " + packetId + " in state " + this.state);
}
break;
case LOGIN:
packetId = data.readUnsignedByte(); // packet id
if (packetId == CLIENT_PROFILE_DATA) {
final String type = data.readCharSequence(data.readUnsignedByte(), StandardCharsets.US_ASCII).toString();
final byte[] dataBytes = new byte[data.readUnsignedShort()];
data.readBytes(dataBytes);
if (data.isReadable()) {
throw new IllegalArgumentException("Too much data in packet: " + data.readableBytes() + " bytes");
}
} else if (packetId == CLIENT_FINISH_LOGIN) {
if (data.isReadable()) {
throw new IllegalArgumentException("Too much data in packet: " + data.readableBytes() + " bytes");
}
this.state = State.LOGIN_COMPLETE;
final int handshakeId = MCPackets.C2S_HANDSHAKE.getId(this.protocolVersion);
final int loginHelloId = MCPackets.C2S_LOGIN_HELLO.getId(this.protocolVersion);
if (handshakeId == -1 || loginHelloId == -1) {
Logger.LOGGER.error("Unsupported protocol version: " + this.protocolVersion);
ctx.close();
return;
}
final ByteBuf handshake = ctx.alloc().buffer();
PacketTypes.writeVarInt(handshake, handshakeId); // packet id
PacketTypes.writeVarInt(handshake, this.protocolVersion); // protocol version
PacketTypes.writeString(handshake, this.host.getHost()); // address
handshake.writeShort(this.host.getPort()); // port
PacketTypes.writeVarInt(handshake, ConnectionState.LOGIN.getId()); // next state
out.add(handshake);
final ByteBuf loginHello = ctx.alloc().buffer();
PacketTypes.writeVarInt(loginHello, loginHelloId); // packet id
PacketTypes.writeString(loginHello, this.username); // username
out.add(loginHello);
final ByteBuf response = ctx.alloc().buffer();
response.writeByte(SERVER_FINISH_LOGIN); // packet id
ctx.writeAndFlush(new BinaryWebSocketFrame(response));
} else {
throw new IllegalStateException("Unexpected packet id " + packetId + " in state " + this.state);
}
break;
case LOGIN_COMPLETE:
out.add(data.retain());
break;
default:
throw new IllegalStateException("Unexpected binary frame in state " + this.state);
}
} else if (in instanceof TextWebSocketFrame) {
final String text = ((TextWebSocketFrame) in).text();
ctx.close();
if (this.state != State.PRE_HANDSHAKE) {
throw new IllegalStateException("Unexpected text frame in state " + this.state);
}
} else {
throw new UnsupportedOperationException("Unsupported frame type: " + in.getClass().getName());
}
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
final WebSocketServerProtocolHandler.HandshakeComplete handshake = (WebSocketServerProtocolHandler.HandshakeComplete) evt;
if (!handshake.requestHeaders().contains("Host")) {
ctx.close();
return;
}
this.host = HostAndPort.fromString(handshake.requestHeaders().get("Host")).withDefaultPort(80);
}
super.userEventTriggered(ctx, evt);
}
public enum State {
PRE_HANDSHAKE,
HANDSHAKE,
HANDSHAKE_COMPLETE,
LOGIN,
LOGIN_COMPLETE,
}
}

View File

@ -0,0 +1,77 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2023 RK_01/RaphiMC and 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 <http://www.gnu.org/licenses/>.
*/
package net.raphimc.viaproxy.proxy.client2proxy.eaglercraft;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyChannelInitializer;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class EaglercraftInitialHandler extends ByteToMessageDecoder {
private static SslContext sslContext;
static {
final File certFolder = new File("certs");
if (certFolder.exists()) {
try {
sslContext = SslContextBuilder.forServer(new File(certFolder, "fullchain.pem"), new File(certFolder, "privkey.pem")).build();
} catch (Throwable e) {
throw new RuntimeException("Failed to load SSL context", e);
}
}
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
if (!ctx.channel().isOpen()) return;
if (!in.isReadable()) return;
if (in.readableBytes() >= 3) {
final byte[] data = new byte[3];
in.getBytes(0, data);
final String method = new String(data, StandardCharsets.UTF_8);
if (method.equals("GET")) { // Websocket request
if (sslContext != null) {
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.WEBSOCKET_SSL_HANDLER_NAME, sslContext.newHandler(ctx.alloc()));
}
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.WEBSOCKET_HTTP_CODEC_NAME, new HttpServerCodec());
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.WEBSOCKET_HTTP_AGGREGATOR_NAME, new HttpObjectAggregator(65535, true));
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.WEBSOCKET_COMPRESSION_NAME, new WebSocketServerCompressionHandler());
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.WEBSOCKET_HANDLER_NAME, new WebSocketServerProtocolHandler("/", null, true));
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.WEBSOCKET_ACTIVE_NOTIFIER_NAME, new WebSocketActiveNotifier());
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.EAGLERCRAFT_HANDLER_NAME, new EaglercraftHandler());
}
ctx.pipeline().remove(this);
ctx.pipeline().fireChannelRead(in.retain());
}
}
}

View File

@ -0,0 +1,40 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2023 RK_01/RaphiMC and 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 <http://www.gnu.org/licenses/>.
*/
package net.raphimc.viaproxy.proxy.client2proxy.eaglercraft;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
public class WebSocketActiveNotifier extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) {
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
ctx.fireChannelActive();
ctx.pipeline().remove(this);
}
super.userEventTriggered(ctx, evt);
}
}

View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package net.raphimc.viaproxy.proxy.client2proxy; package net.raphimc.viaproxy.proxy.client2proxy.passthrough;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;

View File

@ -45,6 +45,9 @@ import java.util.function.Supplier;
public class Proxy2ServerChannelInitializer extends MinecraftChannelInitializer { public class Proxy2ServerChannelInitializer extends MinecraftChannelInitializer {
public static final String VIAPROXY_PROXY_HANDLER_NAME = "viaproxy-proxy-handler";
public static final String VIAPROXY_HAPROXY_ENCODER_NAME = "viaproxy-haproxy-encoder";
public Proxy2ServerChannelInitializer(final Supplier<ChannelHandler> handlerSupplier) { public Proxy2ServerChannelInitializer(final Supplier<ChannelHandler> handlerSupplier) {
super(handlerSupplier); super(handlerSupplier);
} }
@ -62,10 +65,10 @@ public class Proxy2ServerChannelInitializer extends MinecraftChannelInitializer
proxyConnection.setUserConnection(user); proxyConnection.setUserConnection(user);
if (Options.PROXY_URL != null && !proxyConnection.getServerVersion().equals(VersionEnum.bedrockLatest)) { if (Options.PROXY_URL != null && !proxyConnection.getServerVersion().equals(VersionEnum.bedrockLatest)) {
channel.pipeline().addLast("viaproxy-proxy-handler", this.getProxyHandler()); channel.pipeline().addLast(VIAPROXY_PROXY_HANDLER_NAME, this.getProxyHandler());
} }
if (Options.SERVER_HAPROXY_PROTOCOL) { if (Options.SERVER_HAPROXY_PROTOCOL) {
channel.pipeline().addLast("viaproxy-haproxy-encoder", HAProxyMessageEncoder.INSTANCE); channel.pipeline().addLast(VIAPROXY_HAPROXY_ENCODER_NAME, HAProxyMessageEncoder.INSTANCE);
} }
super.initChannel(channel); super.initChannel(channel);

View File

@ -137,7 +137,7 @@ public class Proxy2ServerHandler extends SimpleChannelInboundHandler<IPacket> {
private void handleLoginSuccess(final S2CLoginSuccessPacket1_7 packet) throws Exception { private void handleLoginSuccess(final S2CLoginSuccessPacket1_7 packet) throws Exception {
if (this.proxyConnection.getClientVersion().isNewerThanOrEqualTo(VersionEnum.r1_8)) { if (this.proxyConnection.getClientVersion().isNewerThanOrEqualTo(VersionEnum.r1_8)) {
if (Options.COMPRESSION_THRESHOLD > -1) { if (Options.COMPRESSION_THRESHOLD > -1 && this.proxyConnection.getC2P().attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).get() == -1) {
this.proxyConnection.getC2P().writeAndFlush(new S2CLoginCompressionPacket(Options.COMPRESSION_THRESHOLD)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE).await(); this.proxyConnection.getC2P().writeAndFlush(new S2CLoginCompressionPacket(Options.COMPRESSION_THRESHOLD)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE).await();
this.proxyConnection.getC2P().attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).set(Options.COMPRESSION_THRESHOLD); this.proxyConnection.getC2P().attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).set(Options.COMPRESSION_THRESHOLD);
} }