Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/manual-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Build Package
run: mvn --batch-mode package
- name: Upload jar
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: playit-minecraft-plugin.jar
path: ./target/playit-minecraft-plugin.jar
path: ./target/playit-minecraft-plugin.jar
44 changes: 42 additions & 2 deletions src/main/java/gg/playit/minecraft/PlayitBukkit.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.Plugin;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.FileInputStream;
import java.util.Map;

import java.io.IOException;
import java.util.List;
Expand All @@ -31,10 +36,46 @@ public final class PlayitBukkit extends JavaPlugin implements Listener {

Server server;

private boolean isGeyserPresent = false;
private int geyserPort = 19132;

@Override
public void onEnable() {
server = Bukkit.getServer();

// Detect Geyser plugin
PluginManager pm = Bukkit.getServer().getPluginManager();
Plugin geyser = pm.getPlugin("Geyser-Spigot");
if (geyser != null && geyser.isEnabled()) {
isGeyserPresent = true;
// Try to read the port from Geyser config
try {
File geyserConfig = new File("plugins/Geyser-Spigot/config.yml");
if (geyserConfig.exists()) {
Yaml yaml = new Yaml();
try (FileInputStream fis = new FileInputStream(geyserConfig)) {
Map<String, Object> config = yaml.load(fis);
if (config != null && config.containsKey("bedrock")) {
Object bedrockSection = config.get("bedrock");
if (bedrockSection instanceof Map) {
Object portObj = ((Map<?, ?>) bedrockSection).get("port");
if (portObj instanceof Number) {
geyserPort = ((Number) portObj).intValue();
} else if (portObj instanceof String) {
try {
geyserPort = Integer.parseInt((String) portObj);
} catch (NumberFormatException ignore) {}
}
}
}
}
}
} catch (Exception e) {
log.warning("Failed to read Geyser config: " + e.getMessage());
}
log.info("Geyser detected, Bedrock port: " + geyserPort);
}

var command = getCommand("playit");
if (command != null) {
command.setExecutor(this);
Expand All @@ -50,7 +91,6 @@ public void onEnable() {
resetConnection(secretKey);

try {
PluginManager pm = Bukkit.getServer().getPluginManager();
pm.registerEvents(this, this);
} catch (Exception e) {
}
Expand Down Expand Up @@ -261,7 +301,7 @@ private void resetConnection(String secretKey) {
playitManager.shutdown();
}

playitManager = new PlayitManager(this);
playitManager = new PlayitManager(this, isGeyserPresent, geyserPort);
try {
int waitSeconds = getConfig().getInt(CFG_CONNECTION_TIMEOUT_SECONDS);
if (waitSeconds != 0) {
Expand Down
54 changes: 44 additions & 10 deletions src/main/java/gg/playit/minecraft/PlayitKeysSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ public class PlayitKeysSetup {
public static final int STATE_ERROR = 5;
public static final int STATE_SHUTDOWN = 0;
private final ApiClient openClient = new ApiClient(null);
private final boolean isGeyserPresent;
private final int geyserPort;

public PlayitKeysSetup(String secretKey, AtomicInteger state) {
public PlayitKeysSetup(String secretKey, AtomicInteger state, boolean isGeyserPresent, int geyserPort) {
keys.secretKey = secretKey;
this.state = state;
this.isGeyserPresent = isGeyserPresent;
this.geyserPort = geyserPort;
}

private final PlayitKeys keys = new PlayitKeys();
Expand Down Expand Up @@ -113,24 +117,54 @@ public PlayitKeys progress() throws IOException {
var tunnels = api.listTunnels();
keys.tunnelAddress = null;

boolean haveJava = false;
boolean haveBedrock = !isGeyserPresent;

for (AccountTunnel tunnel : tunnels.tunnels) {
if (tunnel.tunnelType == TunnelType.MinecraftJava) {
keys.tunnelAddress = tunnel.displayAddress;
haveJava = true;
log.info("found minecraft java tunnel: " + keys.tunnelAddress);
return keys;
}
if (isGeyserPresent && tunnel.tunnelType == TunnelType.MinecraftBedrock) {
haveBedrock = true;
log.info("found minecraft bedrock tunnel: " + tunnel.displayAddress);
}
}

log.info("create new minecraft java tunnel");
// Always create Java tunnel if not found
if (!haveJava) {
log.info("create new minecraft java tunnel");

var create = new CreateTunnel();
create.localIp = "127.0.0.1";
create.portCount = 1;
create.portType = PortType.TCP;
create.tunnelType = TunnelType.MinecraftJava;
create.agentId = keys.agentId;
var create = new CreateTunnel();
create.localIp = "127.0.0.1";
create.portCount = 1;
create.portType = PortType.TCP;
create.tunnelType = TunnelType.MinecraftJava;
create.agentId = keys.agentId;

api.createTunnel(create);
return null; // Wait for tunnel to appear
}

api.createTunnel(create);
// If Geyser is present, ensure a Bedrock UDP tunnel exists
if (isGeyserPresent && !haveBedrock) {
log.info("create new minecraft bedrock UDP tunnel on port " + geyserPort);
var create = new CreateTunnel();
create.localIp = "127.0.0.1";
create.localPort = geyserPort;
create.portCount = 1;
create.portType = PortType.UDP;
create.tunnelType = TunnelType.MinecraftBedrock;
create.agentId = keys.agentId;
api.createTunnel(create);
return null; // Wait for tunnel to appear
}

// If we have both required tunnels, setup is done
if (haveJava && haveBedrock) {
return keys;
}

return null;
}
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/gg/playit/minecraft/PlayitManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,20 @@ public class PlayitManager implements Runnable {
private final PlayitConnectionTracker tracker = new PlayitConnectionTracker();

private final PlayitBukkit plugin;
private final boolean isGeyserPresent;
private final int geyserPort;

public PlayitManager(PlayitBukkit plugin) {
public PlayitManager(PlayitBukkit plugin, boolean isGeyserPresent, int geyserPort) {
this.plugin = plugin;
this.isGeyserPresent = isGeyserPresent;
this.geyserPort = geyserPort;

var secret = plugin.getConfig().getString(PlayitBukkit.CFG_AGENT_SECRET_KEY);
if (secret != null && secret.length() < 32) {
secret = null;
}

setup = new PlayitKeysSetup(secret, state);
setup = new PlayitKeysSetup(secret, state, isGeyserPresent, geyserPort);
}

private final PlayitKeysSetup setup;
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ main: gg.playit.minecraft.PlayitBukkit
author: https://playit.gg
description: Makes your server public so friends can connect
api-version: 1.18
softdepend: [Geyser-Spigot]

commands:
playit:
Expand Down