diff --git a/src/main/java/de/nexuslobby/NexusLobby.java b/src/main/java/de/nexuslobby/NexusLobby.java index 74e8157..4777b90 100644 --- a/src/main/java/de/nexuslobby/NexusLobby.java +++ b/src/main/java/de/nexuslobby/NexusLobby.java @@ -16,8 +16,9 @@ import de.nexuslobby.modules.servers.ServerSwitcherListener; import de.nexuslobby.modules.armorstandtools.*; import de.nexuslobby.modules.gadgets.GadgetModule; import de.nexuslobby.modules.hologram.HologramModule; -import de.nexuslobby.modules.mapart.MapArtModule; // Neu -import de.nexuslobby.modules.intro.IntroModule; // Neu +import de.nexuslobby.modules.mapart.MapArtModule; +import de.nexuslobby.modules.intro.IntroModule; +import de.nexuslobby.modules.border.BorderModule; import de.nexuslobby.utils.*; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import net.md_5.bungee.api.chat.ClickEvent; @@ -26,6 +27,8 @@ import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Bukkit; import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.command.PluginCommand; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; @@ -50,8 +53,9 @@ public class NexusLobby extends JavaPlugin implements Listener { private GadgetModule gadgetModule; private HologramModule hologramModule; private DynamicArmorStandModule dynamicArmorStandModule; - private MapArtModule mapArtModule; // Neu - private IntroModule introModule; // Neu + private MapArtModule mapArtModule; + private IntroModule introModule; + private BorderModule borderModule; private File visualsFile; private FileConfiguration visualsConfig; @@ -86,7 +90,7 @@ public class NexusLobby extends JavaPlugin implements Listener { registerCommands(); checkUpdates(); - getLogger().info("NexusLobby wurde erfolgreich gestartet."); + getLogger().info("NexusLobby v" + getDescription().getVersion() + " wurde erfolgreich gestartet."); } private void checkUpdates() { @@ -116,6 +120,11 @@ public class NexusLobby extends JavaPlugin implements Listener { reloadVisualsConfig(); Config.load(); + // Border-Settings nach Config-Reload synchronisieren + if (borderModule != null) { + borderModule.reloadConfig(); + } + if (portalManager != null) { portalManager.loadPortals(); } @@ -141,28 +150,29 @@ public class NexusLobby extends JavaPlugin implements Listener { this.hologramModule = new HologramModule(); moduleManager.registerModule(this.hologramModule); - // Dynamic ArmorStand Module this.dynamicArmorStandModule = new DynamicArmorStandModule(); moduleManager.registerModule(this.dynamicArmorStandModule); - // MapArt & Intro Module this.mapArtModule = new MapArtModule(); moduleManager.registerModule(this.mapArtModule); this.introModule = new IntroModule(); moduleManager.registerModule(this.introModule); + this.borderModule = new BorderModule(); + moduleManager.registerModule(this.borderModule); + moduleManager.registerModule(new SecurityModule()); moduleManager.registerModule(new BossBarModule()); moduleManager.registerModule(new ActionBarModule()); - lobbySettingsModule = new LobbySettingsModule(); + this.lobbySettingsModule = new LobbySettingsModule(); moduleManager.registerModule(lobbySettingsModule); - tablistModule = new TablistModule(); + this.tablistModule = new TablistModule(); moduleManager.registerModule(tablistModule); - portalManager = new PortalManager(this); + this.portalManager = new PortalManager(this); moduleManager.registerModule(portalManager); } @@ -181,6 +191,9 @@ public class NexusLobby extends JavaPlugin implements Listener { Player player = event.getPlayer(); event.setJoinMessage(null); + // Teleport zum Lobby-Spawn beim Beitreten + teleportToSpawn(player); + player.getInventory().clear(); player.getInventory().setArmorContents(null); @@ -208,6 +221,25 @@ public class NexusLobby extends JavaPlugin implements Listener { } } + private void teleportToSpawn(Player player) { + FileConfiguration config = getConfig(); + if (config.contains("spawn.world")) { + String worldName = config.getString("spawn.world"); + World world = Bukkit.getWorld(worldName); + if (world != null) { + Location spawnLoc = new Location( + world, + config.getDouble("spawn.x"), + config.getDouble("spawn.y"), + config.getDouble("spawn.z"), + (float) config.getDouble("spawn.yaw"), + (float) config.getDouble("spawn.pitch") + ); + player.teleport(spawnLoc); + } + } + } + private void initCustomConfigs() { if (!getDataFolder().exists()) { getDataFolder().mkdirs(); @@ -239,13 +271,11 @@ public class NexusLobby extends JavaPlugin implements Listener { visualsFile = new File(getDataFolder(), "visuals.yml"); } visualsConfig = YamlConfiguration.loadConfiguration(visualsFile); - getLogger().info("visuals.yml erfolgreich vom Speicher geladen."); + getLogger().info("visuals.yml erfolgreich geladen."); } public FileConfiguration getVisualsConfig() { - if (visualsConfig == null) { - reloadVisualsConfig(); - } + if (visualsConfig == null) reloadVisualsConfig(); return visualsConfig; } @@ -253,11 +283,12 @@ public class NexusLobby extends JavaPlugin implements Listener { public void onDisable() { getServer().getMessenger().unregisterOutgoingPluginChannel(this, "BungeeCord"); if (moduleManager != null) moduleManager.disableAll(); - getLogger().info("NexusLobby disabled"); + getLogger().info("NexusLobby deaktiviert."); } private void registerCommands() { LobbyTabCompleter tabCompleter = new LobbyTabCompleter(portalManager, hologramModule); + NexusLobbyCommand nexusCommand = new NexusLobbyCommand(); PluginCommand portalCmd = this.getCommand("portal"); if (portalCmd != null) { @@ -291,15 +322,27 @@ public class NexusLobby extends JavaPlugin implements Listener { getCommand("nexuscmd").setTabCompleter(tabCompleter); } + // Haupt- und Spawn-Befehl Registrierung (NexusLobbyCommand verarbeitet beides) PluginCommand nexusCmd = this.getCommand("nexuslobby"); if (nexusCmd != null) { - nexusCmd.setExecutor(new NexusLobbyCommand()); + nexusCmd.setExecutor(nexusCommand); nexusCmd.setTabCompleter(tabCompleter); } - // Neue Commands im TabCompleter registrieren + PluginCommand spawnCmd = this.getCommand("spawn"); + if (spawnCmd != null) { + spawnCmd.setExecutor(nexusCommand); + spawnCmd.setTabCompleter(tabCompleter); + } + if (getCommand("mapart") != null) getCommand("mapart").setTabCompleter(tabCompleter); - if (getCommand("introtest") != null) getCommand("introtest").setTabCompleter(tabCompleter); + if (getCommand("intro") != null) getCommand("intro").setTabCompleter(tabCompleter); + + PluginCommand borderCmd = this.getCommand("border"); + if (borderCmd != null) { + borderCmd.setExecutor(new BorderCommand()); + borderCmd.setTabCompleter(tabCompleter); + } } public class NexusLobbyExpansion extends PlaceholderExpansion { diff --git a/src/main/java/de/nexuslobby/commands/LobbyTabCompleter.java b/src/main/java/de/nexuslobby/commands/LobbyTabCompleter.java index 242cf1b..86167a5 100644 --- a/src/main/java/de/nexuslobby/commands/LobbyTabCompleter.java +++ b/src/main/java/de/nexuslobby/commands/LobbyTabCompleter.java @@ -26,10 +26,14 @@ public class LobbyTabCompleter implements TabCompleter { public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { List suggestions = new ArrayList<>(); - // --- NexusLobby Hauptbefehl --- + // --- NexusLobby Hauptbefehl (/nexus) --- if (command.getName().equalsIgnoreCase("nexuslobby") || command.getName().equalsIgnoreCase("nexus")) { if (args.length == 1) { - if (sender.hasPermission("nexuslobby.admin")) suggestions.add("reload"); + // Hier fügen wir 'setspawn' hinzu + if (sender.hasPermission("nexuslobby.admin")) { + suggestions.add("reload"); + suggestions.add("setspawn"); + } suggestions.add("sb"); } else if (args.length == 2 && args[0].equalsIgnoreCase("sb")) { suggestions.add("on"); @@ -47,7 +51,9 @@ public class LobbyTabCompleter implements TabCompleter { suggestions.add("create"); suggestions.add("delete"); } else if (args.length == 2 && args[0].equalsIgnoreCase("delete")) { - suggestions.addAll(hologramModule.getHologramIds()); + if (hologramModule != null) { + suggestions.addAll(hologramModule.getHologramIds()); + } } } @@ -66,7 +72,9 @@ public class LobbyTabCompleter implements TabCompleter { suggestions.add("delete"); suggestions.add("list"); } else if (args.length == 2 && args[0].equalsIgnoreCase("delete")) { - suggestions.addAll(portalManager.getPortalNames()); + if (portalManager != null) { + suggestions.addAll(portalManager.getPortalNames()); + } } } @@ -75,50 +83,36 @@ public class LobbyTabCompleter implements TabCompleter { if (args.length == 1) { suggestions.add("https://"); } else if (args.length == 2) { - suggestions.add("1x1"); - suggestions.add("3x2"); - suggestions.add("6x4"); + suggestions.addAll(Arrays.asList("1x1", "3x2", "6x4", "8x5")); } } // --- Intro System --- else if (command.getName().equalsIgnoreCase("intro")) { if (args.length == 1) { - suggestions.add("add"); - suggestions.add("clear"); - suggestions.add("start"); - } - } - - // --- NexusTools --- - else if (command.getName().equalsIgnoreCase("nexustools") || command.getName().equalsIgnoreCase("astools") || command.getName().equalsIgnoreCase("nt")) { - if (args.length == 1) { - suggestions.add("reload"); - suggestions.add("dynamic"); - } - } - - // --- NexusCmd --- - else if (command.getName().equalsIgnoreCase("nexuscmd") || command.getName().equalsIgnoreCase("ascmd") || command.getName().equalsIgnoreCase("ncmd")) { - if (args.length == 1) { - suggestions.add("name"); - suggestions.add("list"); - suggestions.add("add"); - suggestions.add("remove"); - } - else if (args.length == 2 && args[0].equalsIgnoreCase("name")) { - suggestions.add("none"); - } - else if (args.length == 2 && args[0].equalsIgnoreCase("add")) { - suggestions.add("0"); - } - else if (args.length == 4 && args[0].equalsIgnoreCase("add")) { - suggestions.add("player"); - suggestions.add("console"); - suggestions.add("bungee"); + suggestions.addAll(Arrays.asList("add", "clear", "start")); } } + // --- WorldBorder --- + else if (command.getName().equalsIgnoreCase("border")) { + if (args.length == 1) { + suggestions.add("circle"); + suggestions.add("square"); + suggestions.add("disable"); + } else if (args.length == 2 && args[0].equalsIgnoreCase("circle")) { + suggestions.addAll(Arrays.asList("10", "25", "50", "100", "250")); + } + } + + // --- NexusCmd & Tools (Verkürzte Logik) --- + else if (command.getName().equalsIgnoreCase("nexuscmd") || command.getName().equalsIgnoreCase("ncmd")) { + if (args.length == 1) { + suggestions.addAll(Arrays.asList("name", "list", "add", "remove")); + } + } + + // Filtert die Vorschläge basierend auf dem, was der Spieler bereits getippt hat return suggestions.stream() .filter(s -> s.toLowerCase().startsWith(args[args.length - 1].toLowerCase())) .collect(Collectors.toList()); diff --git a/src/main/java/de/nexuslobby/commands/NexusLobbyCommand.java b/src/main/java/de/nexuslobby/commands/NexusLobbyCommand.java index 5e572ff..7a70ce2 100644 --- a/src/main/java/de/nexuslobby/commands/NexusLobbyCommand.java +++ b/src/main/java/de/nexuslobby/commands/NexusLobbyCommand.java @@ -2,89 +2,134 @@ package de.nexuslobby.commands; import de.nexuslobby.NexusLobby; import de.nexuslobby.modules.ScoreboardModule; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; public class NexusLobbyCommand implements CommandExecutor { @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - // Sub-Befehl: /nexus sb - if (args.length >= 2 && args[0].equalsIgnoreCase("sb")) { - if (!(sender instanceof Player)) { - sender.sendMessage("§cDieser Befehl ist nur für Spieler!"); + if (!(sender instanceof Player)) { + sender.sendMessage("§cDieser Befehl ist nur für Spieler!"); + return true; + } + Player player = (Player) sender; + + // ========================================== + // LOGIK FÜR /spawn + // ========================================== + if (command.getName().equalsIgnoreCase("spawn")) { + FileConfiguration config = NexusLobby.getInstance().getConfig(); + if (config.contains("spawn.world")) { + Location loc = getSpawnFromConfig(config); + if (loc != null) { + player.teleport(loc); + player.playSound(player.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1.0f, 1.2f); + player.sendMessage("§8[§6Nexus§8] §aDu wurdest zum Spawn teleportiert."); + } else { + player.sendMessage("§cFehler: Die Spawn-Welt existiert nicht."); + } + } else { + player.sendMessage("§cEs wurde noch kein Spawn gesetzt."); + } + return true; + } + + // ========================================== + // LOGIK FÜR /nexus (Hauptbefehl) + // ========================================== + + // Sub-Befehl: /nexus setspawn + if (args.length == 1 && args[0].equalsIgnoreCase("setspawn")) { + if (!player.hasPermission("nexuslobby.admin")) { + player.sendMessage("§cDu hast keine Berechtigung, den Spawn zu setzen."); return true; } - Player player = (Player) sender; - ScoreboardModule sbModule = (ScoreboardModule) NexusLobby.getInstance().getModuleManager().getModule(ScoreboardModule.class); + Location loc = player.getLocation(); + FileConfiguration config = NexusLobby.getInstance().getConfig(); + + config.set("spawn.world", loc.getWorld().getName()); + config.set("spawn.x", loc.getX()); + config.set("spawn.y", loc.getY()); + config.set("spawn.z", loc.getZ()); + config.set("spawn.yaw", (double) loc.getYaw()); + config.set("spawn.pitch", (double) loc.getPitch()); + + NexusLobby.getInstance().saveConfig(); + + player.sendMessage("§8[§6Nexus§8] §aLobby-Spawn erfolgreich gesetzt!"); + player.sendMessage("§7X: §f" + String.format("%.2f", loc.getX()) + " §7Y: §f" + String.format("%.2f", loc.getY()) + " §7Z: §f" + String.format("%.2f", loc.getZ())); + return true; + } + + // Sub-Befehl: /nexus sb + if (args.length >= 2 && args[0].equalsIgnoreCase("sb")) { + ScoreboardModule sbModule = (ScoreboardModule) NexusLobby.getInstance().getModuleManager().getModule(ScoreboardModule.class); if (sbModule == null) { - player.sendMessage("§cDas Scoreboard-Modul ist aktuell deaktiviert."); + player.sendMessage("§cScoreboard-Modul ist deaktiviert."); return true; } String sub = args[1].toLowerCase(); switch (sub) { - case "on": - sbModule.setVisibility(player, true); - break; - case "off": - sbModule.setVisibility(player, false); - break; + case "on": sbModule.setVisibility(player, true); break; + case "off": sbModule.setVisibility(player, false); break; case "admin": - if (!player.hasPermission("nexuslobby.scoreboard.admin")) { - player.sendMessage("§cKeine Rechte für den Admin-Modus."); - return true; - } - sbModule.setAdminMode(player, true); + if (player.hasPermission("nexuslobby.scoreboard.admin")) sbModule.setAdminMode(player, true); + else player.sendMessage("§cKeine Rechte."); break; case "spieler": - if (!player.hasPermission("nexuslobby.scoreboard.admin")) { - player.sendMessage("§cKeine Rechte für den Admin-Modus."); - return true; - } - sbModule.setAdminMode(player, false); - break; - default: - player.sendMessage("§cBenutzung: /nexus sb "); + if (player.hasPermission("nexuslobby.scoreboard.admin")) sbModule.setAdminMode(player, false); + else player.sendMessage("§cKeine Rechte."); break; + default: player.sendMessage("§cBenutzung: /nexus sb "); break; } return true; } // Sub-Befehl: /nexus reload if (args.length == 1 && args[0].equalsIgnoreCase("reload")) { - if (!sender.hasPermission("nexuslobby.admin")) { - sender.sendMessage("§cDu hast keine Berechtigung für diesen Befehl."); + if (!player.hasPermission("nexuslobby.admin")) { + player.sendMessage("§cKeine Rechte."); return true; } - - sender.sendMessage("§7[§6NexusLobby§7] §eKonfigurationen und Module werden neu geladen..."); NexusLobby.getInstance().reloadPlugin(); - sender.sendMessage("§7[§6NexusLobby§7] §aDas Plugin wurde erfolgreich neu geladen!"); + player.sendMessage("§7[§6NexusLobby§7] §aPlugin erfolgreich neu geladen!"); return true; } - // Standard-Info - String version = NexusLobby.getInstance().getDescription().getVersion(); - sender.sendMessage("§8§m--------------------------------------"); - sender.sendMessage("§6§lNexusLobby §7- Informationen"); - sender.sendMessage(""); - sender.sendMessage("§ePlugin Name: §fNexusLobby"); - sender.sendMessage("§eVersion: §f" + version); - sender.sendMessage("§eAutor: §fM_Viper"); - sender.sendMessage(""); - sender.sendMessage("§6Befehle:"); - sender.sendMessage("§f/nexus reload §7- Plugin neu laden"); - sender.sendMessage("§f/nexus sb §7- Scoreboard schalten"); - if (sender.hasPermission("nexuslobby.scoreboard.admin")) { - sender.sendMessage("§f/nexus sb §7- Modus wechseln"); - } - sender.sendMessage("§8§m--------------------------------------"); - + // Info-Screen + sendInfo(player); return true; } + + private Location getSpawnFromConfig(FileConfiguration config) { + World world = Bukkit.getWorld(config.getString("spawn.world", "world")); + if (world == null) return null; + return new Location(world, + config.getDouble("spawn.x"), config.getDouble("spawn.y"), config.getDouble("spawn.z"), + (float) config.getDouble("spawn.yaw"), (float) config.getDouble("spawn.pitch")); + } + + private void sendInfo(Player player) { + String version = NexusLobby.getInstance().getDescription().getVersion(); + player.sendMessage("§8§m--------------------------------------"); + player.sendMessage("§6§lNexusLobby §7- Informationen"); + player.sendMessage(""); + player.sendMessage("§f/spawn §7- Zum Spawn teleportieren"); + player.sendMessage("§f/nexus setspawn §7- Spawn setzen"); + player.sendMessage("§f/nexus reload §7- Konfiguration laden"); + player.sendMessage("§f/nexus sb §7- Scoreboard"); + player.sendMessage("§8§m--------------------------------------"); + } } \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/modules/border/BorderCommand.java b/src/main/java/de/nexuslobby/modules/border/BorderCommand.java new file mode 100644 index 0000000..5ede9e0 --- /dev/null +++ b/src/main/java/de/nexuslobby/modules/border/BorderCommand.java @@ -0,0 +1,86 @@ +package de.nexuslobby.commands; + +import de.nexuslobby.NexusLobby; +import de.nexuslobby.modules.portal.PortalCommand; +import de.nexuslobby.modules.border.BorderModule; +import org.bukkit.Location; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class BorderCommand implements CommandExecutor { + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (!(sender instanceof Player p)) return true; + if (!p.hasPermission("nexuslobby.admin")) { + p.sendMessage("§8[§6Nexus§8] §cKeine Rechte."); + return true; + } + + if (args.length == 0) { + p.sendMessage("§8§m------------------------------------"); + p.sendMessage("§6§lNexus WorldBorder Setup"); + p.sendMessage("§e/border circle §7- Kreis um dich herum"); + p.sendMessage("§e/border square §7- Nutzt Axt-Markierung (Viereck)"); + p.sendMessage("§e/border disable §7- Grenze deaktivieren"); + p.sendMessage("§8§m------------------------------------"); + return true; + } + + var config = NexusLobby.getInstance().getConfig(); + + switch (args[0].toLowerCase()) { + case "circle" -> { + if (args.length < 2) { + p.sendMessage("§cBitte gib einen Radius an."); + return true; + } + try { + double radius = Double.parseDouble(args[1]); + config.set("worldborder.type", "CIRCLE"); + config.set("worldborder.center", p.getLocation()); + config.set("worldborder.radius", radius); + config.set("worldborder.enabled", true); + p.sendMessage("§8[§6Nexus§8] §aKreis-Grenze (Radius: " + radius + ") gesetzt."); + } catch (NumberFormatException e) { + p.sendMessage("§cUngültige Zahl."); + return true; + } + } + case "square" -> { + Location l1 = PortalCommand.getSelection1(p); + Location l2 = PortalCommand.getSelection2(p); + if (l1 == null || l2 == null) { + p.sendMessage("§8[§6Nexus§8] §cBitte markiere erst 2 Punkte mit der Portalwand!"); + return true; + } + config.set("worldborder.type", "SQUARE"); + config.set("worldborder.pos1", l1); + config.set("worldborder.pos2", l2); + config.set("worldborder.enabled", true); + p.sendMessage("§8[§6Nexus§8] §aViereckige Grenze erfolgreich gesetzt."); + } + case "disable" -> { + config.set("worldborder.enabled", false); + p.sendMessage("§8[§6Nexus§8] §cGrenze wurde deaktiviert."); + } + default -> { + p.sendMessage("§cUnbekannter Unterbefehl."); + return true; + } + } + + NexusLobby.getInstance().saveConfig(); + + // Update das Modul direkt im RAM + BorderModule module = NexusLobby.getInstance().getModuleManager().getModule(BorderModule.class); + if (module != null) { + module.reloadConfig(); + } + + return true; + } +} \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/modules/border/BorderModule.java b/src/main/java/de/nexuslobby/modules/border/BorderModule.java new file mode 100644 index 0000000..1751a61 --- /dev/null +++ b/src/main/java/de/nexuslobby/modules/border/BorderModule.java @@ -0,0 +1,132 @@ +package de.nexuslobby.modules.border; + +import de.nexuslobby.NexusLobby; +import de.nexuslobby.api.Module; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.World; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerMoveEvent; + +/** + * Verwaltet die Lobby-Begrenzung (Kreis oder Rechteck). + * Speichert Daten in der Haupt-config.yml unter 'worldborder'. + */ +public class BorderModule implements Module, Listener { + + private String type; + private Location pos1, pos2, center; + private double radius; + private boolean enabled; + + @Override + public String getName() { return "WorldBorder"; } + + @Override + public void onEnable() { + reloadConfig(); + Bukkit.getPluginManager().registerEvents(this, NexusLobby.getInstance()); + } + + @Override + public void onDisable() { + // Aufräumarbeiten falls nötig + } + + /** + * Lädt die Border-Einstellungen aus der config.yml. + * Wird auch von NexusLobby.reloadPlugin() aufgerufen. + */ + public void reloadConfig() { + FileConfiguration config = NexusLobby.getInstance().getConfig(); + + // Pfad in der config.yml: worldborder.enabled etc. + this.enabled = config.getBoolean("worldborder.enabled", false); + this.type = config.getString("worldborder.type", "CIRCLE"); + this.radius = config.getDouble("worldborder.radius", 50.0); + + // Locations laden + this.center = config.getLocation("worldborder.center"); + this.pos1 = config.getLocation("worldborder.pos1"); + this.pos2 = config.getLocation("worldborder.pos2"); + } + + @EventHandler + public void onMove(PlayerMoveEvent event) { + if (!enabled || event.getTo() == null) return; + + // Performance: Nur prüfen, wenn sich die Block-Koordinaten ändern + if (event.getFrom().getBlockX() == event.getTo().getBlockX() && + event.getFrom().getBlockZ() == event.getTo().getBlockZ() && + event.getFrom().getBlockY() == event.getTo().getBlockY()) return; + + Player player = event.getPlayer(); + + // Admins und Spectators ignorieren + if (player.hasPermission("nexuslobby.admin") || player.getGameMode().name().equals("SPECTATOR")) return; + + Location to = event.getTo(); + boolean outside = false; + + // --- Prüfung: Kreis-Border --- + if (type.equalsIgnoreCase("CIRCLE") && center != null) { + if (to.getWorld().equals(center.getWorld())) { + double distSq = Math.pow(to.getX() - center.getX(), 2) + Math.pow(to.getZ() - center.getZ(), 2); + if (distSq > Math.pow(radius, 2)) outside = true; + } + } + // --- Prüfung: Rechteck-Border (Square) --- + else if (type.equalsIgnoreCase("SQUARE") && pos1 != null && pos2 != null) { + if (to.getWorld().equals(pos1.getWorld())) { + double minX = Math.min(pos1.getX(), pos2.getX()); + double maxX = Math.max(pos1.getX(), pos2.getX()); + double minZ = Math.min(pos1.getZ(), pos2.getZ()); + double maxZ = Math.max(pos1.getZ(), pos2.getZ()); + + if (to.getX() < minX || to.getX() > maxX || to.getZ() < minZ || to.getZ() > maxZ) { + outside = true; + } + } + } + + // --- Aktion wenn außerhalb --- + if (outside) { + Location spawnLocation = getMainSpawnLocation(); + + if (spawnLocation != null) { + // Sofortiger Teleport zum definierten Spawn + player.teleport(spawnLocation); + + // Feedback an den Spieler + player.playSound(player.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1.0f, 0.5f); + player.sendMessage("§8[§6Nexus§8] §cDu hast den Lobby-Bereich verlassen!"); + } + } + } + + /** + * Holt den zentralen Spawnpunkt aus der Config (Pfad: spawn.world, spawn.x, etc.) + */ + private Location getMainSpawnLocation() { + FileConfiguration config = NexusLobby.getInstance().getConfig(); + String worldName = config.getString("spawn.world"); + + if (worldName != null) { + World w = Bukkit.getWorld(worldName); + if (w != null) { + return new Location(w, + config.getDouble("spawn.x"), + config.getDouble("spawn.y"), + config.getDouble("spawn.z"), + (float) config.getDouble("spawn.yaw"), + (float) config.getDouble("spawn.pitch")); + } + } + // Fallback falls kein Spawn gesetzt ist + return Bukkit.getWorlds().isEmpty() ? null : Bukkit.getWorlds().get(0).getSpawnLocation(); + } +} \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/modules/hologram/HoloCommand.java b/src/main/java/de/nexuslobby/modules/hologram/HoloCommand.java index 4d11c1d..f707990 100644 --- a/src/main/java/de/nexuslobby/modules/hologram/HoloCommand.java +++ b/src/main/java/de/nexuslobby/modules/hologram/HoloCommand.java @@ -67,7 +67,7 @@ public class HoloCommand implements CommandExecutor { return true; } module.removeHologram(args[1]); - player.sendMessage("§8[§6Nexus§8] §cHologramm §e" + args[1] + " §ageloescht."); + player.sendMessage("§8[§6Nexus§8] §cHologramm §e" + args[1] + " §agelöscht."); } else { sendHelp(player); } diff --git a/src/main/java/de/nexuslobby/modules/hologram/HologramModule.java b/src/main/java/de/nexuslobby/modules/hologram/HologramModule.java index 3fed6e5..1063597 100644 --- a/src/main/java/de/nexuslobby/modules/hologram/HologramModule.java +++ b/src/main/java/de/nexuslobby/modules/hologram/HologramModule.java @@ -7,7 +7,10 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Interaction; import org.bukkit.entity.Player; +import org.bukkit.entity.TextDisplay; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerChangedWorldEvent; @@ -38,6 +41,7 @@ public class HologramModule implements Module, Listener { loadHolograms(); Bukkit.getPluginManager().registerEvents(this, NexusLobby.getInstance()); + // Render-Task: Prüft alle 5 Ticks Sichtbarkeit und Placeholder-Updates Bukkit.getScheduler().runTaskTimer(NexusLobby.getInstance(), () -> { for (Player player : Bukkit.getOnlinePlayers()) { holograms.values().forEach(h -> h.renderForPlayer(player)); @@ -51,12 +55,21 @@ public class HologramModule implements Module, Listener { } private void loadHolograms() { + // Vorherige Instanzen säubern holograms.values().forEach(NexusHologram::removeAll); holograms.clear(); + for (String id : config.getKeys(false)) { - World world = Bukkit.getWorld(config.getString(id + ".world", "world")); + String worldName = config.getString(id + ".world"); + if (worldName == null) continue; + + World world = Bukkit.getWorld(worldName); if (world == null) continue; - Location loc = new Location(world, config.getDouble(id + ".x"), config.getDouble(id + ".y"), config.getDouble(id + ".z")); + + Location loc = new Location(world, + config.getDouble(id + ".x"), + config.getDouble(id + ".y"), + config.getDouble(id + ".z")); List pages; if (config.isList(id + ".text")) { @@ -72,7 +85,9 @@ public class HologramModule implements Module, Listener { @EventHandler public void onInteract(PlayerInteractEntityEvent event) { - // Wir prüfen, ob auf ein Interaction-Entity geklickt wurde + // Nur auf Interaction-Entities reagieren (Hologramm-Hitboxen) + if (!(event.getRightClicked() instanceof Interaction)) return; + for (NexusHologram holo : holograms.values()) { if (holo.isInteractionEntity(event.getRightClicked().getUniqueId())) { holo.nextPage(event.getPlayer()); @@ -93,25 +108,32 @@ public class HologramModule implements Module, Listener { @EventHandler public void onJoin(PlayerJoinEvent event) { - // Cleanup alter Entities für den Joiner + // Cleanup alter Entity-Reste, die eventuell noch in der Welt schweben Bukkit.getScheduler().runTaskLater(NexusLobby.getInstance(), () -> { - event.getPlayer().getWorld().getEntities().forEach(entity -> { + Player p = event.getPlayer(); + for (Entity entity : p.getWorld().getEntities()) { if (entity.getCustomName() != null && entity.getCustomName().startsWith("nexus_h_")) { - if (!entity.getCustomName().endsWith("_" + event.getPlayer().getName())) { - event.getPlayer().hideEntity(NexusLobby.getInstance(), entity); + // Wenn das Hologramm nicht exakt für diesen Spieler benannt ist -> verstecken + if (!entity.getCustomName().endsWith("_" + p.getName())) { + p.hideEntity(NexusLobby.getInstance(), entity); } } - }); - }, 5L); + } + }, 10L); } public void createHologram(String id, Location loc, List pages) { + // Falls ID bereits existiert, altes Hologramm sauber entfernen + if (holograms.containsKey(id)) { + removeHologram(id); + } + config.set(id + ".world", loc.getWorld().getName()); config.set(id + ".x", loc.getX()); config.set(id + ".y", loc.getY()); config.set(id + ".z", loc.getZ()); config.set(id + ".text", pages); - try { config.save(file); } catch (IOException e) { e.printStackTrace(); } + saveHoloConfig(); NexusHologram holo = new NexusHologram(id, loc, pages); holograms.put(id, holo); @@ -119,12 +141,34 @@ public class HologramModule implements Module, Listener { public void removeHologram(String id) { NexusHologram holo = holograms.remove(id); - if (holo != null) holo.removeAll(); + if (holo != null) { + // Erst für alle Spieler visuell entfernen + for (Player player : Bukkit.getOnlinePlayers()) { + holo.removeForPlayer(player); + } + // Dann Entities serverseitig löschen + holo.removeAll(); + } config.set(id, null); - try { config.save(file); } catch (IOException e) { e.printStackTrace(); } + saveHoloConfig(); } - public Set getHologramIds() { return config.getKeys(false); } + private void saveHoloConfig() { + try { + config.save(file); + } catch (IOException e) { + NexusLobby.getInstance().getLogger().severe("Konnte holograms.yml nicht speichern!"); + e.printStackTrace(); + } + } + + /** + * WICHTIG: Diese Methode wird vom LobbyTabCompleter benötigt! + * @return Set aller registrierten Hologramm-IDs + */ + public Set getHologramIds() { + return holograms.keySet(); + } @Override public void onDisable() { diff --git a/src/main/java/de/nexuslobby/modules/hologram/NexusHologram.java b/src/main/java/de/nexuslobby/modules/hologram/NexusHologram.java index 00392aa..efd9710 100644 --- a/src/main/java/de/nexuslobby/modules/hologram/NexusHologram.java +++ b/src/main/java/de/nexuslobby/modules/hologram/NexusHologram.java @@ -45,8 +45,9 @@ public class NexusHologram { } int pageIdx = currentPage.getOrDefault(player.getUniqueId(), 0); - String rawText = pages.get(pageIdx); + if (pageIdx >= pages.size()) pageIdx = 0; + String rawText = pages.get(pageIdx); if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { rawText = PlaceholderAPI.setPlaceholders(player, rawText); } @@ -55,7 +56,8 @@ public class NexusHologram { TextDisplay display = playerEntities.get(player.getUniqueId()); if (display == null || !display.isValid()) { - // Text erstellen + // Text-Display erstellen (Hier lassen wir den Namen zur internen Identifikation, + // aber schalten ihn strikt unsichtbar) display = location.getWorld().spawn(location, TextDisplay.class, entity -> { entity.setCustomName("nexus_h_" + id + "_" + player.getName()); entity.setCustomNameVisible(false); @@ -66,20 +68,21 @@ public class NexusHologram { entity.setInvulnerable(true); }); - // Interaction Entity für Klick-Erkennung (Hitbox) + // Interaction Entity (Hitbox) erstellen + // FIX: WIR SETZEN KEINEN CUSTOM NAME MEHR. + // Das verhindert zu 100%, dass Minecraft etwas anzeigt. Interaction interact = location.getWorld().spawn(location, Interaction.class, entity -> { - entity.setInteractionWidth(2.0f); + entity.setInteractionWidth(2.5f); entity.setInteractionHeight(2.0f); + entity.setCustomNameVisible(false); entity.setPersistent(false); }); - final TextDisplay finalDisplay = display; - final Interaction finalInteract = interact; - + // Nur für den Zielspieler sichtbar machen for (Player other : Bukkit.getOnlinePlayers()) { - if (!other.equals(player)) { - other.hideEntity(NexusLobby.getInstance(), finalDisplay); - other.hideEntity(NexusLobby.getInstance(), finalInteract); + if (!other.getUniqueId().equals(player.getUniqueId())) { + other.hideEntity(NexusLobby.getInstance(), display); + other.hideEntity(NexusLobby.getInstance(), interact); } } @@ -105,11 +108,11 @@ public class NexusHologram { playerInteractions.values().forEach(Interaction::remove); playerEntities.clear(); playerInteractions.clear(); + currentPage.clear(); } public boolean isInteractionEntity(UUID entityId) { + // Da wir keinen Namen mehr nutzen, verlassen wir uns rein auf die UUID in der Map return playerInteractions.values().stream().anyMatch(i -> i.getUniqueId().equals(entityId)); } - - public String getId() { return id; } } \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/modules/portal/PortalCommand.java b/src/main/java/de/nexuslobby/modules/portal/PortalCommand.java index 9cbb1a7..0596151 100644 --- a/src/main/java/de/nexuslobby/modules/portal/PortalCommand.java +++ b/src/main/java/de/nexuslobby/modules/portal/PortalCommand.java @@ -6,14 +6,40 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + public class PortalCommand implements CommandExecutor { private final PortalManager portalManager; + // Statische Maps, damit wir von überall (z.B. BorderCommand) auf die Auswahl zugreifen können + private static final Map selection1 = new HashMap<>(); + private static final Map selection2 = new HashMap<>(); + public PortalCommand(PortalManager portalManager) { this.portalManager = portalManager; } + // Statische Hilfsmethoden für andere Klassen + public static Location getSelection1(Player player) { + return selection1.get(player.getUniqueId()); + } + + public static Location getSelection2(Player player) { + return selection2.get(player.getUniqueId()); + } + + // Methoden zum Setzen (für deinen Wand-Listener oder Befehle) + public static void setSelection1(Player player, Location loc) { + selection1.put(player.getUniqueId(), loc); + } + + public static void setSelection2(Player player, Location loc) { + selection2.put(player.getUniqueId(), loc); + } + @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (!(sender instanceof Player)) { @@ -23,13 +49,11 @@ public class PortalCommand implements CommandExecutor { Player p = (Player) sender; - // Wenn keine Argumente da sind, Hilfe zeigen if (args.length == 0) { sendHelp(p); return true; } - // Switch case für die Unterbefehle switch (args[0].toLowerCase()) { case "create": if (args.length < 3) { @@ -46,7 +70,9 @@ public class PortalCommand implements CommandExecutor { case "setpos1": if (args.length < 2) { p.sendMessage("§cBenutzung: /portal setpos1 "); return true; } - if (portalManager.setPortalPos(args[1], 1, p.getLocation())) { + Location loc1 = p.getLocation(); + if (portalManager.setPortalPos(args[1], 1, loc1)) { + setSelection1(p, loc1); // Speichert es auch in der statischen Map für die Border p.sendMessage("§aPosition 1 gesetzt für " + args[1]); } else { p.sendMessage("§cPortal nicht gefunden."); @@ -55,7 +81,9 @@ public class PortalCommand implements CommandExecutor { case "setpos2": if (args.length < 2) { p.sendMessage("§cBenutzung: /portal setpos2 "); return true; } - if (portalManager.setPortalPos(args[1], 2, p.getLocation())) { + Location loc2 = p.getLocation(); + if (portalManager.setPortalPos(args[1], 2, loc2)) { + setSelection2(p, loc2); // Speichert es auch in der statischen Map für die Border p.sendMessage("§aPosition 2 gesetzt für " + args[1]); } else { p.sendMessage("§cPortal nicht gefunden."); @@ -65,12 +93,9 @@ public class PortalCommand implements CommandExecutor { case "setdest": if (args.length < 3) { p.sendMessage("§cBenutzung: /portal setdest "); - p.sendMessage("§7Server: ServerName"); - p.sendMessage("§7Welt: Weltname;X;Y;Z;Yaw;Pitch"); return true; } String dest = args[2]; - // Falls Koordinaten getrennt mit Leerzeichen gegeben werden (z.B. /portal setdest name world 100 64 100) if (args.length > 3) dest += ";" + args[3]; if (args.length > 4) dest += ";" + args[4]; if (args.length > 5) dest += ";" + args[5]; @@ -96,20 +121,16 @@ public class PortalCommand implements CommandExecutor { break; case "setspawn": - // Neuer Befehl: /portal setspawn if (args.length < 2) { p.sendMessage("§cBenutzung: /portal setspawn "); return true; } - // Optional: Berechtigungscheck (anpassbar) if (!p.hasPermission("nexuslobby.portal")) { p.sendMessage("§cKeine Rechte!"); return true; } - - // Wir speichern die aktuelle Position leicht versetzt (2 Blöcke), damit Spieler nicht direkt wieder im Portal landen. Location spawnLoc = p.getLocation().clone(); - spawnLoc.add(0, 0, 2); // einfacher Offset als default + spawnLoc.add(0, 0, 2); if (portalManager.setPortalReturnSpawn(args[1], spawnLoc)) { p.sendMessage("§aPortal-Spawnpunkt für '" + args[1] + "' gesetzt!"); @@ -151,4 +172,4 @@ public class PortalCommand implements CommandExecutor { p.sendMessage("§e/portal delete "); p.sendMessage("§e/portal list"); } -} +} \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/modules/portal/PortalManager.java b/src/main/java/de/nexuslobby/modules/portal/PortalManager.java index a32c3ed..5dbbb5e 100644 --- a/src/main/java/de/nexuslobby/modules/portal/PortalManager.java +++ b/src/main/java/de/nexuslobby/modules/portal/PortalManager.java @@ -31,7 +31,7 @@ import java.util.UUID; import java.util.Set; /** - * PortalManager - verwaltet Portale, lädt/speichert sie, spawnt Partikel und teleporiert Spieler. + * PortalManager - Verwaltet Portale, Markierungen und den globalen Grenzschutz. */ public class PortalManager implements Module, Listener { @@ -42,6 +42,11 @@ public class PortalManager implements Module, Listener { private final NamespacedKey wandKey; private BukkitTask particleTask; + // Boundary Cache + private Location borderMin; + private Location borderMax; + private boolean borderEnabled = false; + public PortalManager(NexusLobby plugin) { this.plugin = plugin; this.wandKey = new NamespacedKey(plugin, "nexuslobby_portal_wand"); @@ -55,9 +60,10 @@ public class PortalManager implements Module, Listener { @Override public void onEnable() { loadPortals(); + loadBorderSettings(); Bukkit.getPluginManager().registerEvents(this, plugin); startParticleTask(); - plugin.getLogger().info("PortalManager geladen."); + plugin.getLogger().info("PortalManager vollständig geladen."); } @Override @@ -70,15 +76,25 @@ public class PortalManager implements Module, Listener { plugin.getLogger().info("PortalManager deaktiviert."); } - /** - * Gibt alle Namen der aktuell geladenen Portale zurück. - * Wird vom LobbyTabCompleter genutzt. - */ + public void loadBorderSettings() { + if (plugin.getConfig().contains("border.pos1") && plugin.getConfig().contains("border.pos2")) { + Location p1 = plugin.getConfig().getLocation("border.pos1"); + Location p2 = plugin.getConfig().getLocation("border.pos2"); + if (p1 != null && p2 != null) { + this.borderMin = getMinLocation(p1, p2); + this.borderMax = getMaxLocation(p1, p2); + this.borderEnabled = true; + } + } else { + this.borderEnabled = false; + } + } + public Set getPortalNames() { return portals.keySet(); } - // --- Wand / Selection --- + // --- Wand / Selection Logic --- @org.bukkit.event.EventHandler public void onPlayerInteract(PlayerInteractEvent event) { if (event.getAction() == Action.PHYSICAL) return; @@ -87,9 +103,7 @@ public class PortalManager implements Module, Listener { if (item == null || !item.hasItemMeta()) return; ItemMeta meta = item.getItemMeta(); - if (meta == null) return; - - if (!meta.getPersistentDataContainer().has(wandKey, PersistentDataType.BYTE)) return; + if (meta == null || !meta.getPersistentDataContainer().has(wandKey, PersistentDataType.BYTE)) return; Player p = event.getPlayer(); if (!p.hasPermission("nexuslobby.portal")) { @@ -98,7 +112,6 @@ public class PortalManager implements Module, Listener { } event.setCancelled(true); - if (!event.hasBlock()) { p.sendMessage("§cDu musst auf einen Block klicken!"); return; @@ -113,15 +126,34 @@ public class PortalManager implements Module, Listener { if (event.getAction() == Action.LEFT_CLICK_BLOCK) { selectionMap.get(uuid)[0] = clickedLoc; + PortalCommand.setSelection1(p, clickedLoc); + p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0f, 2.0f); p.sendMessage("§aPosition 1 gesetzt: " + clickedLoc.getBlockX() + ", " + clickedLoc.getBlockY() + ", " + clickedLoc.getBlockZ()); + } else if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { selectionMap.get(uuid)[1] = clickedLoc; + PortalCommand.setSelection2(p, clickedLoc); + p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0f, 1.0f); p.sendMessage("§bPosition 2 gesetzt: " + clickedLoc.getBlockX() + ", " + clickedLoc.getBlockY() + ", " + clickedLoc.getBlockZ()); - if (selectionMap.get(uuid)[0] != null) { - p.sendMessage("§eBenutze jetzt: /portal create "); + Location loc1 = selectionMap.get(uuid)[0]; + if (loc1 != null) { + int width = Math.abs(loc1.getBlockX() - clickedLoc.getBlockX()) + 1; + int height = Math.abs(loc1.getBlockY() - clickedLoc.getBlockY()) + 1; + int length = Math.abs(loc1.getBlockZ() - clickedLoc.getBlockZ()) + 1; + long volume = (long) width * height * length; + + p.sendMessage("§7§m----------------------------------"); + if (volume < 500) { + p.sendMessage("§e[Nexus] Kleiner Bereich erkannt (Portal-Größe)"); + p.sendMessage("§fBefehl: §b/portal create "); + } else { + p.sendMessage("§6[Nexus] Großer Bereich erkannt (WorldBorder-Größe)"); + p.sendMessage("§fBefehl: §a/border square"); + } + p.sendMessage("§7§m----------------------------------"); } } } @@ -140,14 +172,8 @@ public class PortalManager implements Module, Listener { return YamlConfiguration.loadConfiguration(file); } - /** - * Lädt alle Portale aus der Konfiguration. - * PUBLIC für den Zugriff durch NexusLobby.java beim Reload. - */ public void loadPortals() { - // Liste leeren, um Duplikate beim Reload zu vermeiden portals.clear(); - YamlConfiguration portalConfig = loadPortalConfig(); ConfigurationSection section = portalConfig.getConfigurationSection("portals"); if (section == null) return; @@ -262,31 +288,7 @@ public class PortalManager implements Module, Listener { return true; } - // --- Particles --- - private void startParticleTask() { - particleTask = Bukkit.getScheduler().runTaskTimer(plugin, () -> { - for (Portal portal : portals.values()) { - if (portal.getPos1() == null || portal.getPos2() == null) continue; - spawnParticles(portal); - } - }, 0L, 5L); - } - - private void spawnParticles(Portal portal) { - Location min = getMinLocation(portal.getPos1(), portal.getPos2()); - Location max = getMaxLocation(portal.getPos1(), portal.getPos2()); - World world = portal.getPos1().getWorld(); - if (world == null) return; - - for (int i = 0; i < 30; i++) { - double x = min.getX() + 0.5 + (Math.random() * (max.getX() - min.getX())); - double y = min.getY() + 0.5 + (Math.random() * (max.getY() - min.getY())); - double z = min.getZ() + 0.5 + (Math.random() * (max.getZ() - min.getZ())); - world.spawnParticle(portal.getParticle(), new Location(world, x, y, z), 3, 0.1, 0.1, 0.1, 0); - } - } - - // --- Teleport / Movement --- + // --- Movement / Teleport / Boundary Logic --- @org.bukkit.event.EventHandler public void onPlayerMove(PlayerMoveEvent event) { if (event.getFrom().getX() == event.getTo().getX() && @@ -296,8 +298,22 @@ public class PortalManager implements Module, Listener { } Player player = event.getPlayer(); - Location loc = player.getLocation(); + Location loc = event.getTo(); + // 1. Grenzschutz (Boundary Protection) + if (borderEnabled && !player.hasPermission("nexuslobby.border.bypass")) { + if (!isWithinBorder(loc)) { + Location spawn = getMainSpawnLocation(); + if (spawn != null) { + player.teleport(spawn); + player.playSound(player.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1.0f, 0.5f); + player.sendMessage("§c§lHEY! §7Du hast den erlaubten Bereich verlassen."); + } + return; + } + } + + // 2. Portal Logik for (Portal portal : portals.values()) { if (portal.getPos1() == null || portal.getPos2() == null) continue; if (!isInArea(loc, portal.getPos1(), portal.getPos2())) continue; @@ -313,11 +329,18 @@ public class PortalManager implements Module, Listener { } } + private boolean isWithinBorder(Location loc) { + if (borderMin == null || borderMax == null) return true; + if (!loc.getWorld().equals(borderMin.getWorld())) return true; + return loc.getX() >= borderMin.getX() && loc.getX() <= borderMax.getX() && + loc.getY() >= borderMin.getY() && loc.getY() <= borderMax.getY() && + loc.getZ() >= borderMin.getZ() && loc.getZ() <= borderMax.getZ(); + } + private void executeTeleport(Player player, Portal portal) { if ("SERVER".equalsIgnoreCase(portal.getType())) { String serverName = portal.getDestination(); player.sendMessage("§eVerbinde zum Server: " + serverName); - plugin.getLogger().info("Verbinde " + player.getName() + " -> " + serverName); Location loc = portal.getReturnSpawn(); if (loc == null) { @@ -335,7 +358,6 @@ public class PortalManager implements Module, Listener { loc.add(0,0,2); } } - player.teleport(loc); connectToServer(player, serverName); return; @@ -352,8 +374,6 @@ public class PortalManager implements Module, Listener { if (spawnLoc != null) { player.teleport(spawnLoc); player.sendMessage("§aDu wurdest zum Spawn teleportiert!"); - } else { - player.sendMessage("§cSpawn konnte nicht gefunden werden."); } return; } @@ -361,99 +381,84 @@ public class PortalManager implements Module, Listener { String[] parts = dest.split(";"); if (parts.length >= 4) { World world = Bukkit.getWorld(parts[0]); - if (world == null) { - player.sendMessage("§cZielwelt nicht gefunden: " + parts[0]); - return; - } + if (world == null) return; try { double x = Double.parseDouble(parts[1]); double y = Double.parseDouble(parts[2]); double z = Double.parseDouble(parts[3]); - float yaw = 0f, pitch = 0f; - if (parts.length >= 6) { - yaw = Float.parseFloat(parts[4]); - pitch = Float.parseFloat(parts[5]); - } - Location target = new Location(world, x, y, z, yaw, pitch); - player.teleport(target); + float yaw = parts.length >= 6 ? Float.parseFloat(parts[4]) : 0f; + float pitch = parts.length >= 6 ? Float.parseFloat(parts[5]) : 0f; + player.teleport(new Location(world, x, y, z, yaw, pitch)); player.sendMessage("§aDu wurdest teleportiert!"); - } catch (NumberFormatException e) { - player.sendMessage("§cUngültige Koordinaten im Portalziel!"); - } - } else { - player.sendMessage("§cUngültiges Portalzielformat!"); + } catch (NumberFormatException ignored) {} } } private void connectToServer(Player player, String serverName) { try { - if (!Bukkit.getMessenger().isOutgoingChannelRegistered(plugin, "BungeeCord")) { - plugin.getLogger().warning("BungeeCord outgoing channel not registered; cannot send plugin message."); - player.sendMessage("§cProxy-Verbindung nicht möglich: BungeeCord-Kanal nicht registriert."); - return; - } - ByteArrayOutputStream b = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(b); out.writeUTF("Connect"); out.writeUTF(serverName); player.sendPluginMessage(plugin, "BungeeCord", b.toByteArray()); } catch (IOException e) { - plugin.getLogger().severe("Fehler beim Senden der BungeeCord-Message: " + e.getMessage()); e.printStackTrace(); - player.sendMessage("§cFehler beim Verbinden zum Proxy."); - } catch (RuntimeException e) { - plugin.getLogger().warning("Konnte Plugin-Message nicht senden: " + e.getMessage()); - player.sendMessage("§cProxy-Verbindung nicht möglich."); } } - // --- Hilfsfunktionen --- private Location getMainSpawnLocation() { String worldName = plugin.getConfig().getString("spawn.world", null); if (worldName != null) { World w = Bukkit.getWorld(worldName); if (w != null) { - double x = plugin.getConfig().getDouble("spawn.x", w.getSpawnLocation().getX()); - double y = plugin.getConfig().getDouble("spawn.y", w.getSpawnLocation().getY()); - double z = plugin.getConfig().getDouble("spawn.z", w.getSpawnLocation().getZ()); - float yaw = (float) plugin.getConfig().getDouble("spawn.yaw", w.getSpawnLocation().getYaw()); - float pitch = (float) plugin.getConfig().getDouble("spawn.pitch", w.getSpawnLocation().getPitch()); - return new Location(w, x, y, z, yaw, pitch); + return new Location(w, + plugin.getConfig().getDouble("spawn.x"), + plugin.getConfig().getDouble("spawn.y"), + plugin.getConfig().getDouble("spawn.z"), + (float) plugin.getConfig().getDouble("spawn.yaw"), + (float) plugin.getConfig().getDouble("spawn.pitch")); } } - if (!Bukkit.getWorlds().isEmpty()) { - return Bukkit.getWorlds().get(0).getSpawnLocation(); - } - return null; + return !Bukkit.getWorlds().isEmpty() ? Bukkit.getWorlds().get(0).getSpawnLocation() : null; } + // --- Utils & Particles --- private boolean isInArea(Location loc, Location loc1, Location loc2) { - if (loc == null || loc1 == null || loc2 == null) return false; if (!loc.getWorld().equals(loc1.getWorld())) return false; - - int x = loc.getBlockX(); - int y = loc.getBlockY(); - int z = loc.getBlockZ(); - int headY = y + 1; - Location min = getMinLocation(loc1, loc2); Location max = getMaxLocation(loc1, loc2); - - boolean xMatch = (x >= min.getBlockX()) && (x <= max.getBlockX()); - boolean zMatch = (z >= min.getBlockZ()) && (z <= max.getBlockZ()); - boolean yMatch = (y >= min.getBlockY()) && (headY <= max.getBlockY()); - - return xMatch && yMatch && zMatch; + return (loc.getX() >= min.getX() && loc.getX() <= max.getX() + 1) && + (loc.getY() >= min.getY() && loc.getY() <= max.getY() + 1) && + (loc.getZ() >= min.getZ() && loc.getZ() <= max.getZ() + 1); } private Location getMinLocation(Location a, Location b) { - return new Location(a.getWorld(), Math.min(a.getX(), b.getX()), - Math.min(a.getY(), b.getY()), Math.min(a.getZ(), b.getZ())); + return new Location(a.getWorld(), Math.min(a.getX(), b.getX()), Math.min(a.getY(), b.getY()), Math.min(a.getZ(), b.getZ())); } private Location getMaxLocation(Location a, Location b) { - return new Location(a.getWorld(), Math.max(a.getX(), b.getX()), - Math.max(a.getY(), b.getY()), Math.max(a.getZ(), b.getZ())); + return new Location(a.getWorld(), Math.max(a.getX(), b.getX()), Math.max(a.getY(), b.getY()), Math.max(a.getZ(), b.getZ())); + } + + private void startParticleTask() { + particleTask = Bukkit.getScheduler().runTaskTimer(plugin, () -> { + for (Portal portal : portals.values()) { + if (portal.getPos1() != null && portal.getPos2() != null) { + spawnParticles(portal); + } + } + }, 0L, 5L); + } + + private void spawnParticles(Portal portal) { + Location min = getMinLocation(portal.getPos1(), portal.getPos2()); + Location max = getMaxLocation(portal.getPos1(), portal.getPos2()); + World world = portal.getPos1().getWorld(); + for (int i = 0; i < 15; i++) { + double x = min.getX() + Math.random() * (max.getX() - min.getX() + 1); + double y = min.getY() + Math.random() * (max.getY() - min.getY() + 1); + double z = min.getZ() + Math.random() * (max.getZ() - min.getZ() + 1); + world.spawnParticle(portal.getParticle(), x, y, z, 1, 0.1, 0.1, 0.1, 0); + } } } \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index d4dc66b..608f5db 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -11,6 +11,14 @@ spawn: yaw: 0.0 # Blickrichtung pitch: 0.0 # Blickrichtung +worldborder: + enabled: true + type: "SQUARE" # oder "CIRCLE" + radius: 50.0 + center: + pos1: + pos2: + # --- Lobby Einstellungen --- lobby: allow-fly: false # Spieler dürfen fliegen diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 83ee441..a8a4045 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -39,7 +39,7 @@ commands: permission-message: "§cDu hast keine Rechte!" nexuslobby: description: Zeigt Informationen über das Plugin an oder lädt es neu - usage: /nexuslobby [reload] + usage: /nexuslobby [reload|setspawn] aliases: [nexus] nexustools: description: Nexus ArmorStand Editor @@ -59,6 +59,13 @@ commands: description: Verwalte und teste die Cinematic Intro Tour usage: /intro permission: nexuslobby.admin + border: + description: Verwalte die unsichtbare Lobby-Begrenzung + usage: /border + permission: nexuslobby.admin + spawn: + description: Teleportiert dich zum Lobby-Spawnpunkt + usage: /spawn permissions: nexuslobby.portal: @@ -74,7 +81,7 @@ permissions: description: Zugriff auf den Server Switcher default: true nexuslobby.admin: - description: Voller Zugriff auf Lobby-Gamerules, Einstellungen, Intro und Reload + description: Voller Zugriff auf Lobby-Gamerules, Einstellungen, Intro, Border und Reload default: op nexuslobby.build: description: Erlaubt das Umgehen des Lobby-Schutzes zum Bauen