Skip to content

Commit

Permalink
Added rust-raknet backend
Browse files Browse the repository at this point in the history
  • Loading branch information
RaphiMC committed Jan 5, 2024
1 parent 0dd3c21 commit b824d4e
Show file tree
Hide file tree
Showing 16 changed files with 300 additions and 56 deletions.
11 changes: 6 additions & 5 deletions src/main/java/net/raphimc/raknetproviders/RakNetBackend.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@

public enum RakNetBackend {

GO_RAKNET("Sandertv/go-raknet (best)"), // https://github.com/Sandertv/go-raknet
NATIVE_RAKNET("Native RakNet"), // https://github.com/extremeheat/fb-raknet
CLOUDBURSTMC_NETWORK("CloudburstMC/Network (default)"), // https://github.com/CloudburstMC/Network
RELATIVITYMC_NETTY_RAKNET("RelativityMC/netty-raknet"), // https://github.com/RelativityMC/netty-raknet
WHIRVIS_JRAKNET("whirvis/JRakNet (bad)"), // https://github.com/telecran-telecrit/JRakNet
SANDERTV_GO_RAKNET("[Go] Sandertv/go-raknet (best)"), // https://github.com/Sandertv/go-raknet
EXTREMEHEAT_FB_RAKNET("[C++] extremeheat/fb-raknet"), // https://github.com/extremeheat/fb-raknet
CLOUDBURSTMC_NETWORK("[Java] CloudburstMC/Network (default)"), // https://github.com/CloudburstMC/Network
RELATIVITYMC_NETTY_RAKNET("[Java] RelativityMC/netty-raknet"), // https://github.com/RelativityMC/netty-raknet
WHIRVIS_JRAKNET("[Java] whirvis/JRakNet (bad)"), // https://github.com/telecran-telecrit/JRakNet
B23R0_RUST_RAKNET("[Rust] b23r0/rust-raknet"), // https://github.com/b23r0/rust-raknet
;

private final String displayName;
Expand Down
37 changes: 23 additions & 14 deletions src/main/java/net/raphimc/raknetproviders/RakNetProviders.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
import net.lenni0451.lambdaevents.EventHandler;
import net.lenni0451.reflect.Objects;
import net.lenni0451.reflect.stream.RStream;
import net.raphimc.raknetproviders.go_raknet.GoRakNet;
import net.raphimc.raknetproviders.go_raknet.GoRakNetBedrockProxyConnection;
import net.raphimc.raknetproviders.native_raknet.NativeRakNet;
import net.raphimc.raknetproviders.native_raknet.NativeRakNetBedrockProxyConnection;
import net.raphimc.raknetproviders.b23r0_rust_raknet.B23R0RustRakNet;
import net.raphimc.raknetproviders.b23r0_rust_raknet.B23R0RustRakNetBedrockProxyConnection;
import net.raphimc.raknetproviders.extremeheat_fb_raknet.ExtremeheatFbRakNet;
import net.raphimc.raknetproviders.extremeheat_fb_raknet.ExtremeheatFbRakNetBedrockProxyConnection;
import net.raphimc.raknetproviders.relativitymc_netty_raknet.RelativityMcNettyRakNetBedrockProxyConnection;
import net.raphimc.raknetproviders.sandertv_go_raknet.SanderTvGoRakNet;
import net.raphimc.raknetproviders.sandertv_go_raknet.SanderTvGoRakNetBedrockProxyConnection;
import net.raphimc.raknetproviders.whirvis_jraknet.WhirvisJRakNetBedrockProxyConnection;
import net.raphimc.viabedrock.protocol.data.ProtocolConstants;
import net.raphimc.viaproxy.ViaProxy;
Expand All @@ -51,8 +53,8 @@ public class RakNetProviders extends ViaProxyPlugin {
public void onEnable() {
ViaProxy.EVENT_MANAGER.register(this);

if (NativeRakNet.isLoaded()) {
NativeRakNet.INSTANCE.RN_SetRakNetProtocolVersion(ProtocolConstants.BEDROCK_RAKNET_PROTOCOL_VERSION);
if (ExtremeheatFbRakNet.isLoaded()) {
ExtremeheatFbRakNet.INSTANCE.RN_SetRakNetProtocolVersion(ProtocolConstants.BEDROCK_RAKNET_PROTOCOL_VERSION);
}
}

Expand Down Expand Up @@ -102,11 +104,11 @@ public Component getListCellRendererComponent(JList<?> list, Object value, int i
public void onProxySessionCreation(final ProxySessionCreationEvent event) {
if (event.getProxySession() instanceof BedrockProxyConnection bedrockProxyConnection && this.rakNetBackend.getSelectedItem() instanceof RakNetBackend backend) {
switch (backend) {
case NATIVE_RAKNET -> {
if (NativeRakNet.isLoaded()) {
event.setProxySession(new NativeRakNetBedrockProxyConnection(Objects.cast(bedrockProxyConnection, NativeRakNetBedrockProxyConnection.class)));
case EXTREMEHEAT_FB_RAKNET -> {
if (ExtremeheatFbRakNet.isLoaded()) {
event.setProxySession(new ExtremeheatFbRakNetBedrockProxyConnection(Objects.cast(bedrockProxyConnection, ExtremeheatFbRakNetBedrockProxyConnection.class)));
} else {
Logger.LOGGER.warn("NATIVE_RAKNET is not supported on this system, falling back to CLOUDBURST_NETWORK");
Logger.LOGGER.warn("EXTREMEHEAT_FB_RAKNET is not supported on this system, falling back to CLOUDBURST_NETWORK");
}
}
case CLOUDBURSTMC_NETWORK -> {
Expand All @@ -118,11 +120,18 @@ public void onProxySessionCreation(final ProxySessionCreationEvent event) {
case WHIRVIS_JRAKNET -> {
event.setProxySession(new WhirvisJRakNetBedrockProxyConnection(Objects.cast(bedrockProxyConnection, WhirvisJRakNetBedrockProxyConnection.class)));
}
case GO_RAKNET -> {
if (GoRakNet.isLoaded()) {
event.setProxySession(new GoRakNetBedrockProxyConnection(Objects.cast(bedrockProxyConnection, GoRakNetBedrockProxyConnection.class)));
case SANDERTV_GO_RAKNET -> {
if (SanderTvGoRakNet.isLoaded()) {
event.setProxySession(new SanderTvGoRakNetBedrockProxyConnection(Objects.cast(bedrockProxyConnection, SanderTvGoRakNetBedrockProxyConnection.class)));
} else {
Logger.LOGGER.warn("GO_RAKNET is not supported on this system, falling back to CLOUDBURST_NETWORK");
Logger.LOGGER.warn("SANDERTV_GO_RAKNET is not supported on this system, falling back to CLOUDBURST_NETWORK");
}
}
case B23R0_RUST_RAKNET -> {
if (B23R0RustRakNet.isLoaded()) {
event.setProxySession(new B23R0RustRakNetBedrockProxyConnection(Objects.cast(bedrockProxyConnection, B23R0RustRakNetBedrockProxyConnection.class)));
} else {
Logger.LOGGER.warn("B23R0_RUST_RAKNET is not supported on this system, falling back to CLOUDBURST_NETWORK");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* This file is part of ViaProxyRakNetProviders - https://github.com/ViaVersionAddons/ViaProxyRakNetProviders
* Copyright (C) 2023-2024 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.raknetproviders.b23r0_rust_raknet;

import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;

import java.util.HashMap;
import java.util.Map;

public interface B23R0RustRakNet extends Library {

B23R0RustRakNet INSTANCE = loadNative();

private static B23R0RustRakNet loadNative() {
try {
final Map<String, Object> options = new HashMap<>();
options.put(Library.OPTION_STRING_ENCODING, "UTF-8");
return Native.load("rust-raknet", B23R0RustRakNet.class, options);
} catch (Throwable ignored) {
}
return null;
}

static boolean isLoaded() {
return INSTANCE != null;
}

String connect(final String address, final int connectTimeout, final byte raknetVersion, final PointerByReference connectionPointer);

void begin_receive_packet(final Pointer connection, final int readTimeout, final Callback readCallback);

String send_packet(final Pointer connection, final byte[] data, final int length);

String disconnect(final Pointer connection);

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* 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.raknetproviders.go_raknet;
package net.raphimc.raknetproviders.b23r0_rust_raknet;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
Expand All @@ -25,9 +25,9 @@
import net.raphimc.viaproxy.proxy.session.BedrockProxyConnection;
import net.raphimc.viaproxy.proxy.session.ProxyConnection;

public class GoRakNetBedrockProxyConnection extends BedrockProxyConnection {
public class B23R0RustRakNetBedrockProxyConnection extends BedrockProxyConnection {

public GoRakNetBedrockProxyConnection(final GoRakNetBedrockProxyConnection bedrockProxyConnection) {
public B23R0RustRakNetBedrockProxyConnection(final B23R0RustRakNetBedrockProxyConnection bedrockProxyConnection) {
super(bedrockProxyConnection.handlerSupplier, bedrockProxyConnection.channelInitializerSupplier, bedrockProxyConnection.getC2P());
}

Expand All @@ -36,7 +36,7 @@ public void initialize(ChannelType channelType, Bootstrap bootstrap) {
if (this.getC2pConnectionState() == ConnectionState.LOGIN) {
bootstrap
.group(new OioEventLoopGroup())
.channel(GoRakNetChannel.class)
.channel(B23R0RustRakNetChannel.class)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 4_000)
.attr(ProxyConnection.PROXY_CONNECTION_ATTRIBUTE_KEY, this)
.handler(this.channelInitializerSupplier.apply(this.handlerSupplier));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* This file is part of ViaProxyRakNetProviders - https://github.com/ViaVersionAddons/ViaProxyRakNetProviders
* Copyright (C) 2023-2024 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.raknetproviders.b23r0_rust_raknet;

import com.sun.jna.Callback;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelOutboundBuffer;
import io.netty.util.internal.StringUtil;
import net.raphimc.raknetproviders.SimpleOioMessageChannel;
import net.raphimc.viabedrock.protocol.data.ProtocolConstants;
import org.cloudburstmc.netty.channel.raknet.packet.RakMessage;

import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.LinkedTransferQueue;

public class B23R0RustRakNetChannel extends SimpleOioMessageChannel {

protected boolean active = false;

private Pointer connection;
private final Queue<Object> readQueue = new LinkedTransferQueue<>();
private final Callback callback = new Callback() {
public void onRead(final String readError, final Pointer data, final int length) {
if (readError != null) {
readQueue.add(readError);
} else {
readQueue.add(data.getByteArray(0, length));
}
}
};

@Override
protected void doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
super.doConnect(remoteAddress, localAddress);

final InetSocketAddress address = (InetSocketAddress) remoteAddress;
final PointerByReference connectionPointer = new PointerByReference();
final String connectError = B23R0RustRakNet.INSTANCE.connect(address.getHostString() + ":" + address.getPort(), this.config().getConnectTimeoutMillis(), (byte) ProtocolConstants.BEDROCK_RAKNET_PROTOCOL_VERSION, connectionPointer);
if (connectError != null) {
throw new ConnectException(connectError);
}
this.connection = connectionPointer.getValue();

B23R0RustRakNet.INSTANCE.begin_receive_packet(this.connection, 30_000, this.callback);

this.active = true;
}

@Override
protected int doReadMessages(List<Object> list) {
if (this.connection == null) {
return -1;
}
if (!this.readQueue.isEmpty()) {
final Object obj = this.readQueue.poll();
if (obj instanceof byte[] bytes) {
list.add(new RakMessage(this.alloc().buffer(bytes.length).writeBytes(bytes)));
return bytes.length;
} else if (obj instanceof String errorMessage) {
throw new RuntimeException(errorMessage);
}
}

return 0;
}

@Override
protected void doWrite(ChannelOutboundBuffer channelOutboundBuffer) {
while (true) {
final Object msg = channelOutboundBuffer.current();
if (msg == null) {
return;
} else if (msg instanceof RakMessage rakMessage) {
final ByteBuf buf = rakMessage.content();
final byte[] bytes = new byte[buf.readableBytes()];
buf.readBytes(bytes);

final String writeError = B23R0RustRakNet.INSTANCE.send_packet(this.connection, bytes, bytes.length);
if (writeError != null) {
throw new RuntimeException(writeError);
}

channelOutboundBuffer.remove();
} else {
channelOutboundBuffer.remove(new UnsupportedOperationException("unsupported message type: " + StringUtil.simpleClassName(msg)));
}
}
}

@Override
protected void doClose() throws Exception {
super.doClose();

if (this.connection != null) {
final String disconnectError = B23R0RustRakNet.INSTANCE.disconnect(this.connection);
this.connection = null;
if (disconnectError != null) {
throw new RuntimeException(disconnectError);
}
}
}

@Override
public boolean isActive() {
return this.active && this.open;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* 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.raknetproviders.native_raknet;
package net.raphimc.raknetproviders.extremeheat_fb_raknet;

import com.sun.jna.Library;
import com.sun.jna.Native;
Expand All @@ -25,13 +25,13 @@
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public interface NativeRakNet extends Library {
public interface ExtremeheatFbRakNet extends Library {

NativeRakNet INSTANCE = loadNative();
ExtremeheatFbRakNet INSTANCE = loadNative();

private static NativeRakNet loadNative() {
private static ExtremeheatFbRakNet loadNative() {
try {
return Native.load("raknet", NativeRakNet.class);
return Native.load("cpp-raknet", ExtremeheatFbRakNet.class);
} catch (Throwable ignored) {
}
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* This file is part of ViaProxyRakNetProviders - https://github.com/ViaVersionAddons/ViaProxyRakNetProviders
* Copyright (C) 2023-2024 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.raknetproviders.extremeheat_fb_raknet;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.oio.OioEventLoopGroup;
import net.raphimc.netminecraft.constants.ConnectionState;
import net.raphimc.netminecraft.util.ChannelType;
import net.raphimc.viaproxy.proxy.session.BedrockProxyConnection;
import net.raphimc.viaproxy.proxy.session.ProxyConnection;

public class ExtremeheatFbRakNetBedrockProxyConnection extends BedrockProxyConnection {

public ExtremeheatFbRakNetBedrockProxyConnection(final ExtremeheatFbRakNetBedrockProxyConnection bedrockProxyConnection) {
super(bedrockProxyConnection.handlerSupplier, bedrockProxyConnection.channelInitializerSupplier, bedrockProxyConnection.getC2P());
}

@Override
public void initialize(ChannelType channelType, Bootstrap bootstrap) {
if (this.getC2pConnectionState() == ConnectionState.LOGIN) {
bootstrap
.group(new OioEventLoopGroup())
.channel(ExtremeheatFbRakNetChannel.class)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 4_000)
.attr(ProxyConnection.PROXY_CONNECTION_ATTRIBUTE_KEY, this)
.handler(this.channelInitializerSupplier.apply(this.handlerSupplier));

this.channelFuture = bootstrap.register().syncUninterruptibly();
} else {
super.initialize(channelType, bootstrap);
}
}

}
Loading

0 comments on commit b824d4e

Please sign in to comment.