Skip to content

Commit e0a1ac2

Browse files
committed
Added Kas-tle/Network backend
1 parent d449734 commit e0a1ac2

File tree

6 files changed

+169
-1
lines changed

6 files changed

+169
-1
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ dependencies {
4747
exclude group: "org.apache.logging.log4j"
4848
exclude group: "io.netty"
4949
}
50+
include fileTree(include: ["*.jar"], dir: "dependencies")
5051
}
5152

5253
processResources {
144 KB
Binary file not shown.

src/main/java/net/raphimc/raknetproviders/RakNetBackend.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919

2020
public enum RakNetBackend {
2121

22-
SANDERTV_GO_RAKNET("[Go] Sandertv/go-raknet (best)"), // https://github.com/Sandertv/go-raknet
22+
SANDERTV_GO_RAKNET("[Go] Sandertv/go-raknet"), // https://github.com/Sandertv/go-raknet
2323
EXTREMEHEAT_FB_RAKNET("[C++] extremeheat/fb-raknet"), // https://github.com/extremeheat/fb-raknet
2424
CLOUDBURSTMC_NETWORK("[Java] CloudburstMC/Network (default)"), // https://github.com/CloudburstMC/Network
25+
KASTLE_NETWORK("[Java] Kas-tle/Network (best)"), // https://github.com/Kas-tle/Network
2526
RELATIVITYMC_NETTY_RAKNET("[Java] RelativityMC/netty-raknet"), // https://github.com/RelativityMC/netty-raknet
2627
WHIRVIS_JRAKNET("[Java] whirvis/JRakNet (bad)"), // https://github.com/telecran-telecrit/JRakNet
2728
B23R0_RUST_RAKNET("[Rust] b23r0/rust-raknet"), // https://github.com/b23r0/rust-raknet

src/main/java/net/raphimc/raknetproviders/RakNetProviders.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import net.raphimc.raknetproviders.b23r0_rust_raknet.B23R0RustRakNetBedrockProxyConnection;
2626
import net.raphimc.raknetproviders.extremeheat_fb_raknet.ExtremeheatFbRakNet;
2727
import net.raphimc.raknetproviders.extremeheat_fb_raknet.ExtremeheatFbRakNetBedrockProxyConnection;
28+
import net.raphimc.raknetproviders.kastle_network.KastleNetworkBedrockProxyConnection;
2829
import net.raphimc.raknetproviders.relativitymc_netty_raknet.RelativityMcNettyRakNetBedrockProxyConnection;
2930
import net.raphimc.raknetproviders.sandertv_go_raknet.SanderTvGoRakNet;
3031
import net.raphimc.raknetproviders.sandertv_go_raknet.SanderTvGoRakNetBedrockProxyConnection;
@@ -113,6 +114,9 @@ public void onProxySessionCreation(final ProxySessionCreationEvent event) {
113114
case CLOUDBURSTMC_NETWORK -> {
114115
// default implementation
115116
}
117+
case KASTLE_NETWORK -> {
118+
event.setProxySession(new KastleNetworkBedrockProxyConnection(Objects.cast(bedrockProxyConnection, KastleNetworkBedrockProxyConnection.class)));
119+
}
116120
case RELATIVITYMC_NETTY_RAKNET -> {
117121
event.setProxySession(new RelativityMcNettyRakNetBedrockProxyConnection(Objects.cast(bedrockProxyConnection, RelativityMcNettyRakNetBedrockProxyConnection.class)));
118122
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* This file is part of ViaProxyRakNetProviders - https://github.com/ViaVersionAddons/ViaProxyRakNetProviders
3+
* Copyright (C) 2023-2025 RK_01/RaphiMC and contributors
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package net.raphimc.raknetproviders.kastle_network;
19+
20+
import com.viaversion.vialoader.netty.VLPipeline;
21+
import dev.kastle.netty.channel.raknet.RakChannelFactory;
22+
import dev.kastle.netty.channel.raknet.RakPriority;
23+
import dev.kastle.netty.channel.raknet.RakReliability;
24+
import dev.kastle.netty.channel.raknet.config.RakChannelOption;
25+
import dev.kastle.netty.channel.raknet.packet.RakMessage;
26+
import io.netty.bootstrap.Bootstrap;
27+
import io.netty.buffer.ByteBuf;
28+
import io.netty.buffer.ByteBufUtil;
29+
import io.netty.buffer.Unpooled;
30+
import io.netty.channel.*;
31+
import io.netty.channel.socket.DatagramChannel;
32+
import io.netty.handler.codec.MessageToMessageCodec;
33+
import net.lenni0451.reflect.stream.RStream;
34+
import net.raphimc.netminecraft.constants.ConnectionState;
35+
import net.raphimc.netminecraft.util.ChannelType;
36+
import net.raphimc.viabedrock.protocol.data.ProtocolConstants;
37+
import net.raphimc.viabedrock.protocol.data.enums.bedrock.MinecraftPacketIds;
38+
import net.raphimc.viabedrock.protocol.types.BedrockTypes;
39+
import net.raphimc.viaproxy.ViaProxy;
40+
import net.raphimc.viaproxy.proxy.session.BedrockProxyConnection;
41+
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
42+
43+
import java.util.ArrayList;
44+
import java.util.List;
45+
import java.util.concurrent.ThreadLocalRandom;
46+
47+
public class KastleNetworkBedrockProxyConnection extends BedrockProxyConnection {
48+
49+
public KastleNetworkBedrockProxyConnection(final KastleNetworkBedrockProxyConnection bedrockProxyConnection) {
50+
super(bedrockProxyConnection.channelInitializer, bedrockProxyConnection.getC2P());
51+
}
52+
53+
@Override
54+
public void initialize(ChannelType channelType, Bootstrap bootstrap) {
55+
if (this.getC2pConnectionState() == ConnectionState.LOGIN) {
56+
if (!DatagramChannel.class.isAssignableFrom(channelType.udpClientChannelClass())) {
57+
throw new IllegalArgumentException("Channel type must be a DatagramChannel");
58+
}
59+
if (channelType == ChannelType.KQUEUE) channelType = ChannelType.NIO; // KQueue doesn't work for Bedrock for some reason
60+
final Class<? extends DatagramChannel> channelClass = (Class<? extends DatagramChannel>) channelType.udpClientChannelClass();
61+
62+
// Reflection to prevent inlining
63+
final int bedrockProtocolVersion = RStream.of(ProtocolConstants.class).fields().by("BEDROCK_PROTOCOL_VERSION").get();
64+
65+
bootstrap
66+
.group(channelType.clientEventLoopGroup().get())
67+
.channelFactory(RakChannelFactory.client(channelClass))
68+
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, ViaProxy.getConfig().getConnectTimeout())
69+
.option(RakChannelOption.RAK_PROTOCOL_VERSION, ProtocolConstants.BEDROCK_RAKNET_PROTOCOL_VERSION)
70+
.option(RakChannelOption.RAK_CLIENT_BEDROCK_PROTOCOL_VERSION, bedrockProtocolVersion)
71+
.option(RakChannelOption.RAK_COMPATIBILITY_MODE, true)
72+
.option(RakChannelOption.RAK_CLIENT_INTERNAL_ADDRESSES, 20)
73+
.option(RakChannelOption.RAK_TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS, 500)
74+
.option(RakChannelOption.RAK_CONNECT_TIMEOUT, (long) ViaProxy.getConfig().getConnectTimeout())
75+
.option(RakChannelOption.RAK_SESSION_TIMEOUT, 30_000L)
76+
.option(RakChannelOption.RAK_GUID, ThreadLocalRandom.current().nextLong())
77+
.attr(ProxyConnection.PROXY_CONNECTION_ATTRIBUTE_KEY, this)
78+
.handler(new ChannelInitializer<>() {
79+
80+
@Override
81+
protected void initChannel(Channel channel) {
82+
channel.pipeline().addLast(channelInitializer);
83+
84+
channel.pipeline().addBefore(VLPipeline.VIABEDROCK_FRAME_ENCAPSULATION_HANDLER_NAME, "viabedrock-frame-converter", new MessageToMessageCodec<RakMessage, org.cloudburstmc.netty.channel.raknet.packet.RakMessage>() {
85+
@Override
86+
protected void encode(ChannelHandlerContext channelHandlerContext, org.cloudburstmc.netty.channel.raknet.packet.RakMessage rakMessage, List<Object> list) {
87+
list.add(new RakMessage(
88+
rakMessage.content().retain(),
89+
RakReliability.valueOf(rakMessage.reliability().name()),
90+
RakPriority.valueOf(rakMessage.priority().name()),
91+
rakMessage.channel()
92+
));
93+
}
94+
95+
@Override
96+
protected void decode(ChannelHandlerContext channelHandlerContext, RakMessage rakMessage, List<Object> list) {
97+
list.add(new org.cloudburstmc.netty.channel.raknet.packet.RakMessage(
98+
rakMessage.content().retain(),
99+
org.cloudburstmc.netty.channel.raknet.RakReliability.valueOf(rakMessage.reliability().name()),
100+
org.cloudburstmc.netty.channel.raknet.RakPriority.valueOf(rakMessage.priority().name()),
101+
rakMessage.channel()
102+
));
103+
}
104+
});
105+
channel.pipeline().addBefore(VLPipeline.VIABEDROCK_PACKET_ENCAPSULATION_HANDLER_NAME, "viaproxy-raknetproviders-packet-buffer", new ChannelDuplexHandler() {
106+
107+
private boolean sentRequestNetworkSettings = false;
108+
private final List<byte[]> bufferedPackets = new ArrayList<>();
109+
110+
@Override
111+
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
112+
if (msg instanceof ByteBuf byteBuf && !this.sentRequestNetworkSettings) {
113+
final byte[] data = ByteBufUtil.getBytes(byteBuf);
114+
byteBuf.release();
115+
this.bufferedPackets.add(data);
116+
if (this.bufferedPackets.size() > 1000) {
117+
throw new IllegalStateException("Too many packets buffered");
118+
}
119+
} else {
120+
super.channelRead(ctx, msg);
121+
}
122+
}
123+
124+
@Override
125+
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
126+
if (msg instanceof ByteBuf byteBuf) {
127+
byteBuf.markReaderIndex();
128+
final int packetId = BedrockTypes.UNSIGNED_VAR_INT.readPrimitive(byteBuf) & 1023;
129+
byteBuf.resetReaderIndex();
130+
131+
if (packetId == MinecraftPacketIds.RequestNetworkSettings.getValue()) {
132+
this.sentRequestNetworkSettings = true;
133+
byteBuf.release();
134+
for (byte[] bufferedPacket : this.bufferedPackets) {
135+
ctx.fireChannelRead(Unpooled.wrappedBuffer(bufferedPacket));
136+
}
137+
ctx.pipeline().remove(this);
138+
} else {
139+
super.write(ctx, msg, promise);
140+
}
141+
} else {
142+
super.write(ctx, msg, promise);
143+
}
144+
}
145+
146+
});
147+
}
148+
149+
});
150+
151+
this.channelFuture = bootstrap.register().syncUninterruptibly();
152+
153+
/*if (this.getChannel().config().setOption(RakChannelOption.RAK_IP_DONT_FRAGMENT, true)) {
154+
this.getChannel().config().setOption(RakChannelOption.RAK_MTU_SIZES, new Integer[]{1492, 1200, 576});
155+
}*/
156+
} else {
157+
super.initialize(channelType, bootstrap);
158+
}
159+
}
160+
161+
}

src/main/java/net/raphimc/raknetproviders/relativitymc_netty_raknet/RelativityMcNettyRakNetBedrockProxyConnection.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ protected void decode(ChannelHandlerContext channelHandlerContext, FrameData fra
8080
}
8181
});
8282
}
83+
8384
});
8485

8586
this.channelFuture = bootstrap.register().syncUninterruptibly();

0 commit comments

Comments
 (0)