diff --git a/.github/workflows/manual-build.yml b/.github/workflows/manual-build.yml index e1bb543..af321e6 100644 --- a/.github/workflows/manual-build.yml +++ b/.github/workflows/manual-build.yml @@ -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 \ No newline at end of file + path: ./target/playit-minecraft-plugin.jar diff --git a/src/main/java/gg/playit/minecraft/PlayitBukkit.java b/src/main/java/gg/playit/minecraft/PlayitBukkit.java index e9757f4..9faa16e 100644 --- a/src/main/java/gg/playit/minecraft/PlayitBukkit.java +++ b/src/main/java/gg/playit/minecraft/PlayitBukkit.java @@ -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; @@ -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 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); @@ -50,7 +91,6 @@ public void onEnable() { resetConnection(secretKey); try { - PluginManager pm = Bukkit.getServer().getPluginManager(); pm.registerEvents(this, this); } catch (Exception e) { } @@ -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) { diff --git a/src/main/java/gg/playit/minecraft/PlayitKeysSetup.java b/src/main/java/gg/playit/minecraft/PlayitKeysSetup.java index 7bf5eec..92b98ca 100644 --- a/src/main/java/gg/playit/minecraft/PlayitKeysSetup.java +++ b/src/main/java/gg/playit/minecraft/PlayitKeysSetup.java @@ -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(); @@ -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; } diff --git a/src/main/java/gg/playit/minecraft/PlayitManager.java b/src/main/java/gg/playit/minecraft/PlayitManager.java index fa30346..fb58dab 100644 --- a/src/main/java/gg/playit/minecraft/PlayitManager.java +++ b/src/main/java/gg/playit/minecraft/PlayitManager.java @@ -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; diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5a3018b..58714c1 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -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: