Skip to content

Commit

Permalink
Update ping logic to 3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
rtm516 committed Aug 20, 2024
1 parent 67a72fc commit 4dc760d
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 27 deletions.
1 change: 0 additions & 1 deletion bootstrap/manager/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ dependencies {
testRuntimeOnly(libs.junit.platform.launcher)

api(project(":core"))
api(libs.bedrock.common)
api(libs.guava)
}

Expand Down
1 change: 0 additions & 1 deletion bootstrap/standalone/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ plugins {
dependencies {
api(project(":core"))
api(libs.bundles.jackson)
api(libs.bedrock.common)

api(libs.terminalconsoleappender) {
exclude("org.apache.logging.log4j")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.nukkitx.protocol.bedrock.BedrockClient;
import com.nukkitx.protocol.bedrock.BedrockPong;
import com.rtm516.mcxboxbroadcast.core.BuildData;
import com.rtm516.mcxboxbroadcast.core.SessionInfo;
import com.rtm516.mcxboxbroadcast.core.SessionManager;
import com.rtm516.mcxboxbroadcast.core.configs.StandaloneConfig;
import com.rtm516.mcxboxbroadcast.core.exceptions.SessionCreationException;
import com.rtm516.mcxboxbroadcast.core.exceptions.SessionUpdateException;
import com.rtm516.mcxboxbroadcast.core.ping.PingUtil;
import com.rtm516.mcxboxbroadcast.core.storage.FileStorageManager;
import org.cloudburstmc.protocol.bedrock.BedrockPong;
import org.slf4j.LoggerFactory;

import java.io.File;
Expand Down Expand Up @@ -107,29 +107,19 @@ private static void createSession() throws SessionCreationException, SessionUpda

private static void updateSessionInfo(SessionInfo sessionInfo) {
if (config.session().queryServer()) {
BedrockClient client = null;
try {
InetSocketAddress bindAddress = new InetSocketAddress("0.0.0.0", 0);
client = new BedrockClient(bindAddress);

client.bind().join();

InetSocketAddress addressToPing = new InetSocketAddress(sessionInfo.getIp(), sessionInfo.getPort());
BedrockPong pong = client.ping(addressToPing, 1500, TimeUnit.MILLISECONDS).get();
BedrockPong pong = PingUtil.ping(addressToPing, 1500, TimeUnit.MILLISECONDS).get();

// Update the session information
sessionInfo.setHostName(pong.getMotd());
sessionInfo.setWorldName(pong.getSubMotd());
sessionInfo.setVersion(pong.getVersion());
sessionInfo.setProtocol(pong.getProtocolVersion());
sessionInfo.setPlayers(pong.getPlayerCount());
sessionInfo.setMaxPlayers(pong.getMaximumPlayerCount());
sessionInfo.setHostName(pong.motd());
sessionInfo.setWorldName(pong.subMotd());
sessionInfo.setVersion(pong.version());
sessionInfo.setProtocol(pong.protocolVersion());
sessionInfo.setPlayers(pong.playerCount());
sessionInfo.setMaxPlayers(pong.maximumPlayerCount());
} catch (InterruptedException | ExecutionException e) {
sessionManager.logger().error("Failed to ping server", e);
} finally {
if (client != null) {
client.close();
}
}
}
}
Expand Down
5 changes: 1 addition & 4 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dependencies {
api(libs.java.websocket)
api(libs.methanol)
api(libs.minecraftauth)
api(libs.bundles.protocol)

implementation("dev.onvoid.webrtc:webrtc-java:0.8.0")
implementation("dev.onvoid.webrtc", "webrtc-java", "0.8.0", classifier = "windows-x86_64")
Expand All @@ -25,10 +26,6 @@ dependencies {

// Needs https://github.com/steely-glint/srtplight and https://github.com/pipe/sctp4j to be installed locally
api("pe.pi:sctp4j:1.0.7-SNAPSHOT")

api("org.cloudburstmc.protocol:common:3.0.0.Beta3-20240814.133201-7")
api("org.cloudburstmc.protocol:bedrock-codec:3.0.0.Beta3-20240814.133201-7")
api("org.cloudburstmc.protocol:bedrock-connection:3.0.0.Beta3-20240814.133201-7")
}

sourceSets {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.rtm516.mcxboxbroadcast.core.ping;

import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.ScheduledFuture;
import org.cloudburstmc.netty.channel.raknet.RakPong;
import org.cloudburstmc.protocol.bedrock.BedrockPong;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
* Licenced under GPL-2.0
*
* https://github.com/WaterdogPE/WaterdogPE/blob/4e2b3cd1a3d5e4d3599476fd907b6bd3186783eb/src/main/java/dev/waterdog/waterdogpe/network/connection/codec/client/ClientPingHandler.java
*/
public class ClientPingHandler extends ChannelDuplexHandler {

private final Promise<BedrockPong> future;

private final long timeout;
private final TimeUnit timeUnit;
private ScheduledFuture<?> timeoutFuture;

public ClientPingHandler(Promise<BedrockPong> future, long timeout, TimeUnit timeUnit) {
this.future = future;
this.timeout = timeout;
this.timeUnit = timeUnit;
}

private void onTimeout(Channel channel) {
channel.close();
this.future.tryFailure(new TimeoutException());
}

@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
this.timeoutFuture = ctx.channel().eventLoop().schedule(() -> this.onTimeout(ctx.channel()), this.timeout, this.timeUnit);
}

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (!(msg instanceof RakPong rakPong)) {
super.channelRead(ctx, msg);
return;
}

if (this.timeoutFuture != null) {
this.timeoutFuture.cancel(false);
this.timeoutFuture = null;
}

ctx.channel().close();

this.future.trySuccess(BedrockPong.fromRakNet(rakPong.getPongData()));
}

@Override
public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
super.close(ctx, promise);

if (this.timeoutFuture != null) {
this.timeoutFuture.cancel(false);
this.timeoutFuture = null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.rtm516.mcxboxbroadcast.core.ping;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.concurrent.Promise;
import org.cloudburstmc.netty.channel.raknet.RakChannelFactory;
import org.cloudburstmc.netty.channel.raknet.RakPing;
import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption;
import org.cloudburstmc.protocol.bedrock.BedrockPong;
import org.java_websocket.util.NamedThreadFactory;

import java.net.InetSocketAddress;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
* Licenced under GPL-2.0
* Modified to fit MCXboxBroadcast
*
* https://github.com/WaterdogPE/WaterdogPE/blob/4e2b3cd1a3d5e4d3599476fd907b6bd3186783eb/src/main/java/dev/waterdog/waterdogpe/network/serverinfo/BedrockServerInfo.java
*/
public class PingUtil {
private static EventLoopGroup workerEventLoopGroup;

static {
workerEventLoopGroup = new NioEventLoopGroup(0, new NamedThreadFactory("MCXboxBroadcast Ping Thread"));
}

public static Promise<BedrockPong> ping(InetSocketAddress server, long timeout, TimeUnit timeUnit) {
EventLoop eventLoop = workerEventLoopGroup.next();
Promise<BedrockPong> promise = eventLoop.newPromise();

new Bootstrap()
.channelFactory(RakChannelFactory.client(NioDatagramChannel.class))
.group(workerEventLoopGroup)
.option(RakChannelOption.RAK_GUID, ThreadLocalRandom.current().nextLong())
.handler(new ClientPingHandler(promise, timeout, timeUnit))
.bind(ThreadLocalRandom.current().nextInt(10000, 15000))
.addListener((ChannelFuture future) -> {
if (future.cause() != null) {
promise.tryFailure(future.cause());
future.channel().close();
} else {
RakPing ping = new RakPing(System.currentTimeMillis(), server);
future.channel().writeAndFlush(ping).addListener(future1 -> {
if (future1.cause() != null) {
promise.tryFailure(future1.cause());
future.channel().close();
}
});
}
});
return promise;
}
}
12 changes: 10 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[versions]
bedrock-common = "2.9.17-SNAPSHOT"
protocol = "3.0.0.Beta3-20240814.133201-7"
geyser ="2.4.1-SNAPSHOT"
jackson = "2.14.0"
java-websocket = "1.5.3"
Expand All @@ -21,7 +21,10 @@ indra = "3.1.3"
blossom = "2.1.0"

[libraries]
bedrock-common = { group = "com.nukkitx.protocol", name = "bedrock-common", version.ref = "bedrock-common" }
protocol-common = { group = "org.cloudburstmc.protocol", name = "common", version.ref = "protocol" }
protocol-codec = { group = "org.cloudburstmc.protocol", name = "bedrock-codec", version.ref = "protocol" }
protocol-connection = { group = "org.cloudburstmc.protocol", name = "bedrock-connection", version.ref = "protocol" }

geyser-api = { group = "org.geysermc.geyser", name = "api", version.ref = "geyser" }
geyser-core = { group = "org.geysermc.geyser", name = "core", version.ref = "geyser" }

Expand Down Expand Up @@ -95,6 +98,11 @@ spring-test = [
"spring-boot-starter-test",
"spring-security-test"
]
protocol = [
"protocol-common",
"protocol-codec",
"protocol-connection"
]

[plugins]
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }
Expand Down

0 comments on commit 4dc760d

Please sign in to comment.