|
17 | 17 | */ |
18 | 18 | package net.raphimc.viaproxy.proxy.session; |
19 | 19 |
|
| 20 | +import com.viaversion.vialoader.netty.VLPipeline; |
| 21 | +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; |
| 22 | +import dev.kastle.netty.channel.nethernet.NetherNetChannelFactory; |
| 23 | +import dev.kastle.netty.channel.nethernet.config.NetherChannelOption; |
| 24 | +import dev.kastle.netty.channel.nethernet.config.NetherNetAddress; |
| 25 | +import dev.kastle.netty.channel.nethernet.signaling.NetherNetClientSignaling; |
| 26 | +import dev.kastle.netty.channel.nethernet.signaling.NetherNetDiscoverySignaling; |
| 27 | +import dev.kastle.netty.channel.nethernet.signaling.NetherNetXboxSignaling; |
| 28 | +import dev.kastle.webrtc.PeerConnectionFactory; |
20 | 29 | import io.netty.bootstrap.Bootstrap; |
21 | | -import io.netty.channel.Channel; |
22 | | -import io.netty.channel.ChannelInitializer; |
23 | | -import io.netty.channel.ChannelOption; |
| 30 | +import io.netty.channel.*; |
24 | 31 | import io.netty.channel.socket.DatagramChannel; |
| 32 | +import net.raphimc.netminecraft.constants.ConnectionState; |
25 | 33 | import net.raphimc.netminecraft.util.EventLoops; |
26 | 34 | import net.raphimc.netminecraft.util.TransportType; |
27 | 35 | import net.raphimc.viabedrock.protocol.data.ProtocolConstants; |
28 | 36 | import net.raphimc.viaproxy.ViaProxy; |
| 37 | +import net.raphimc.viaproxy.saves.impl.accounts.BedrockAccount; |
| 38 | +import net.raphimc.viaproxy.util.NetherNetInetSocketAddress; |
29 | 39 | import org.cloudburstmc.netty.channel.raknet.RakChannelFactory; |
| 40 | +import org.cloudburstmc.netty.channel.raknet.RakClientChannel; |
30 | 41 | import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption; |
31 | 42 |
|
| 43 | +import java.net.SocketAddress; |
32 | 44 | import java.util.concurrent.ThreadLocalRandom; |
33 | 45 |
|
34 | 46 | public class BedrockProxyConnection extends ProxyConnection { |
35 | 47 |
|
| 48 | + private boolean useNetherNetDiscovery; |
| 49 | + private boolean useNetherNetXbox; |
| 50 | + |
36 | 51 | public BedrockProxyConnection(final ChannelInitializer<Channel> channelInitializer, final Channel c2p) { |
37 | 52 | super(channelInitializer, c2p); |
38 | 53 | } |
39 | 54 |
|
40 | 55 | @Override |
41 | | - public void initialize(TransportType transportType, final Bootstrap bootstrap) { |
| 56 | + public void initialize(final TransportType transportType, final Bootstrap bootstrap) { |
| 57 | + bootstrap |
| 58 | + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, ViaProxy.getConfig().getConnectTimeout()) |
| 59 | + .attr(ProxyConnection.PROXY_CONNECTION_ATTRIBUTE_KEY, this) |
| 60 | + .handler(this.channelInitializer); |
| 61 | + |
| 62 | + if (this.getC2pConnectionState() == ConnectionState.STATUS) { |
| 63 | + this.initializeRaw(transportType, bootstrap); |
| 64 | + } else if (this.useNetherNetDiscovery || this.useNetherNetXbox) { |
| 65 | + this.initializeNetherNet(transportType, bootstrap); |
| 66 | + } else { |
| 67 | + this.initializeRakNet(transportType, bootstrap); |
| 68 | + } |
| 69 | + |
| 70 | + this.channelFuture = bootstrap.register().syncUninterruptibly(); |
| 71 | + } |
| 72 | + |
| 73 | + @Override |
| 74 | + public ChannelFuture connectToServer(final SocketAddress serverAddress, final ProtocolVersion targetVersion) { |
| 75 | + this.useNetherNetDiscovery = serverAddress instanceof NetherNetInetSocketAddress; |
| 76 | + this.useNetherNetXbox = serverAddress instanceof NetherNetAddress; |
| 77 | + return super.connectToServer(serverAddress, targetVersion); |
| 78 | + } |
| 79 | + |
| 80 | + protected void initializeRakNet(TransportType transportType, final Bootstrap bootstrap) { |
42 | 81 | if (!DatagramChannel.class.isAssignableFrom(transportType.udpClientChannelClass())) { |
43 | 82 | throw new IllegalArgumentException("Channel type must be a DatagramChannel"); |
44 | 83 | } |
45 | 84 | if (transportType == TransportType.KQUEUE) { |
46 | 85 | transportType = TransportType.NIO; // KQueue doesn't work for some reason |
47 | 86 | } |
48 | 87 |
|
| 88 | + final RakChannelFactory<RakClientChannel> channelFactory = RakChannelFactory.client((Class<? extends DatagramChannel>) transportType.udpClientChannelClass()); |
49 | 89 | bootstrap |
50 | 90 | .group(EventLoops.getClientEventLoop(transportType)) |
51 | | - .channelFactory(RakChannelFactory.client((Class<? extends DatagramChannel>) transportType.udpClientChannelClass())) |
52 | | - .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, ViaProxy.getConfig().getConnectTimeout()) |
| 91 | + .channelFactory(() -> { |
| 92 | + final Channel channel = channelFactory.newChannel(); |
| 93 | + if (channel.config().setOption(RakChannelOption.RAK_IP_DONT_FRAGMENT, true)) { |
| 94 | + channel.config().setOption(RakChannelOption.RAK_MTU_SIZES, new Integer[]{1492, 1200, 576}); |
| 95 | + } |
| 96 | + return channel; |
| 97 | + }) |
53 | 98 | .option(RakChannelOption.RAK_PROTOCOL_VERSION, ProtocolConstants.BEDROCK_RAKNET_PROTOCOL_VERSION) |
54 | 99 | .option(RakChannelOption.RAK_COMPATIBILITY_MODE, true) |
55 | 100 | .option(RakChannelOption.RAK_CLIENT_INTERNAL_ADDRESSES, 20) |
56 | 101 | .option(RakChannelOption.RAK_TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS, 500) |
57 | 102 | .option(RakChannelOption.RAK_CONNECT_TIMEOUT, (long) ViaProxy.getConfig().getConnectTimeout()) |
58 | 103 | .option(RakChannelOption.RAK_SESSION_TIMEOUT, 30_000L) |
59 | | - .option(RakChannelOption.RAK_GUID, ThreadLocalRandom.current().nextLong()) |
60 | | - .attr(ProxyConnection.PROXY_CONNECTION_ATTRIBUTE_KEY, this) |
61 | | - .handler(this.channelInitializer); |
| 104 | + .option(RakChannelOption.RAK_GUID, ThreadLocalRandom.current().nextLong()); |
| 105 | + } |
62 | 106 |
|
63 | | - this.channelFuture = bootstrap.register().syncUninterruptibly(); |
| 107 | + protected void initializeNetherNet(final TransportType transportType, final Bootstrap bootstrap) { |
| 108 | + final NetherNetClientSignaling netherNetSignaling; |
| 109 | + if (this.useNetherNetDiscovery) { |
| 110 | + netherNetSignaling = new NetherNetDiscoverySignaling(); |
| 111 | + } else { |
| 112 | + if (this.getUserOptions().account() instanceof BedrockAccount bedrockAccount) { |
| 113 | + netherNetSignaling = new NetherNetXboxSignaling(bedrockAccount.getAuthManager().getMinecraftSession().getUpToDateUnchecked().getAuthorizationHeader()); |
| 114 | + } else { |
| 115 | + this.kickClient("§cThe configured target server requires Xbox signaling, but no Minecraft: Bedrock Edition account is selected."); |
| 116 | + return; |
| 117 | + } |
| 118 | + } |
| 119 | + final ChannelHandler channelHandler = bootstrap.config().handler(); |
| 120 | + bootstrap |
| 121 | + .group(EventLoops.getClientEventLoop(TransportType.NIO)) |
| 122 | + .channelFactory(NetherNetChannelFactory.client(new PeerConnectionFactory(), netherNetSignaling)) |
| 123 | + .option(NetherChannelOption.NETHER_CLIENT_HANDSHAKE_TIMEOUT_MS, ViaProxy.getConfig().getConnectTimeout()) |
| 124 | + .handler(new ChannelInitializer<>() { |
| 125 | + @Override |
| 126 | + protected void initChannel(final Channel channel) { |
| 127 | + channel.pipeline().addLast(channelHandler); |
| 128 | + channel.pipeline().remove(VLPipeline.VIABEDROCK_RAKNET_MESSAGE_CODEC_NAME); |
| 129 | + } |
| 130 | + }); |
| 131 | + } |
64 | 132 |
|
65 | | - /*if (this.getChannel().config().setOption(RakChannelOption.RAK_IP_DONT_FRAGMENT, true)) { |
66 | | - this.getChannel().config().setOption(RakChannelOption.RAK_MTU_SIZES, new Integer[]{1492, 1200, 576}); |
67 | | - }*/ |
| 133 | + protected void initializeRaw(TransportType transportType, final Bootstrap bootstrap) { |
| 134 | + if (transportType == TransportType.KQUEUE) { |
| 135 | + transportType = TransportType.NIO; // KQueue doesn't work for some reason |
| 136 | + } |
| 137 | + |
| 138 | + bootstrap |
| 139 | + .group(EventLoops.getClientEventLoop(transportType)) |
| 140 | + .channel(transportType.udpClientChannelClass()); |
68 | 141 | } |
69 | 142 |
|
70 | 143 | } |
0 commit comments