diff --git a/pom.xml b/pom.xml
index 9ca7469..0278905 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
de.nexuslobby
NexusLobby
- 1.9
+ 2.0
jar
NexusLobby
diff --git a/src/main/java/de/nexuslobby/modules/ScoreboardModule.java b/src/main/java/de/nexuslobby/modules/ScoreboardModule.java
index 903a9b2..3757fb4 100644
--- a/src/main/java/de/nexuslobby/modules/ScoreboardModule.java
+++ b/src/main/java/de/nexuslobby/modules/ScoreboardModule.java
@@ -173,22 +173,22 @@ public class ScoreboardModule implements Module, Listener {
playerBoards.put(player.getUniqueId(), Bukkit.getScoreboardManager().getNewScoreboard());
}
player.setScoreboard(playerBoards.get(player.getUniqueId()));
- player.sendMessage("§7[§6Nexus§7] §aScoreboard eingeschaltet.");
+ player.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§aScoreboard eingeschaltet.");
updateSidebar(player); // Sofort aktualisieren
} else {
hiddenPlayers.add(player.getUniqueId());
player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard());
- player.sendMessage("§7[§6Nexus§7] §cScoreboard ausgeschaltet.");
+ player.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§cScoreboard ausgeschaltet.");
}
}
public void setAdminMode(Player player, boolean admin) {
if (admin) {
adminModePlayers.add(player.getUniqueId());
- player.sendMessage("§7[§6Nexus§7] §eModus: §cAdmin-Scoreboard §7(Owner-Sektion)");
+ player.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§eModus: §cAdmin-Scoreboard §7(Owner-Sektion)");
} else {
adminModePlayers.remove(player.getUniqueId());
- player.sendMessage("§7[§6Nexus§7] §eModus: §6Spieler-Scoreboard §7(Default-Sektion)");
+ player.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§eModus: §6Spieler-Scoreboard §7(Default-Sektion)");
}
updateSidebar(player);
}
diff --git a/src/main/java/de/nexuslobby/modules/player/PlayerInspectModule.java b/src/main/java/de/nexuslobby/modules/player/PlayerInspectModule.java
index 4a93140..45c46b6 100644
--- a/src/main/java/de/nexuslobby/modules/player/PlayerInspectModule.java
+++ b/src/main/java/de/nexuslobby/modules/player/PlayerInspectModule.java
@@ -1,196 +1,196 @@
-package de.nexuslobby.modules.player;
-
-import de.nexuslobby.NexusLobby;
-import de.nexuslobby.api.Module;
-import me.clip.placeholderapi.PlaceholderAPI;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.Material;
-import org.bukkit.Statistic;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.player.PlayerInteractEntityEvent;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.inventory.meta.SkullMeta;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Modul zur Inspektion von Spielern in der Lobby.
- * Zeigt detaillierte Statistiken in einer interaktiven GUI an.
- */
-public class PlayerInspectModule implements Module, Listener {
-
- @Override
- public String getName() {
- return "PlayerInspect";
- }
-
- @Override
- public void onEnable() {
- Bukkit.getPluginManager().registerEvents(this, NexusLobby.getInstance());
- }
-
- @Override
- public void onDisable() {
- org.bukkit.event.HandlerList.unregisterAll(this);
- }
-
- @EventHandler
- public void onPlayerInteract(PlayerInteractEntityEvent event) {
- // Prüfen, ob ein Spieler rechtsgeklickt wurde
- if (event.getRightClicked() instanceof Player target) {
- Player viewer = event.getPlayer();
-
- // GUI nur öffnen, wenn die Hand leer ist (verhindert Konflikte mit Items)
- if (viewer.getInventory().getItemInMainHand().getType() == Material.AIR) {
- openDetailedInspectGUI(viewer, target);
- }
- }
- }
-
- @EventHandler
- public void onInventoryClick(InventoryClickEvent event) {
- // Sicherstellen, dass es unser Statistik-Inventar ist anhand des Titels
- if (event.getView().getTitle().contains("Statistiken")) {
- event.setCancelled(true); // Verhindert, dass Items herausgenommen werden
-
- ItemStack clickedItem = event.getCurrentItem();
- if (clickedItem == null || clickedItem.getType() == Material.AIR) return;
-
- // Logik für den Schließen-Button (Barriere)
- if (clickedItem.getType() == Material.BARRIER) {
- event.getWhoClicked().closeInventory();
- }
- }
- }
-
- public void openDetailedInspectGUI(Player viewer, Player target) {
- // Titel mit Farbcodes
- String title = "§8» §3Statistiken: §b" + target.getName();
- Inventory gui = Bukkit.createInventory(null, 45, title);
-
- // --- Design: Hintergrund mit Glasscheiben füllen ---
- ItemStack separator = createSimpleItem(Material.GRAY_STAINED_GLASS_PANE, " ");
- int[] borderSlots = {
- 0,1,2,3,4,5,6,7,8,
- 9,17,
- 18,26,
- 27,35,
- 36,37,38,39,41,42,43,44
- };
- for (int slot : borderSlots) gui.setItem(slot, separator);
-
- // --- Kopf des Spielers mit LuckPerms Prefix via PAPI ---
- ItemStack head = new ItemStack(Material.PLAYER_HEAD);
- SkullMeta headMeta = (SkullMeta) head.getItemMeta();
- if (headMeta != null) {
- headMeta.setOwningPlayer(target);
- headMeta.setDisplayName("§e§l" + target.getName());
-
- List lore = new ArrayList<>();
- lore.add("§8§m-----------------------");
-
- // LuckPerms Prefix über PlaceholderAPI auslesen (falls vorhanden)
- String prefix = "%luckperms_prefix%";
- if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
- try {
- prefix = PlaceholderAPI.setPlaceholders(target, prefix);
- } catch (NoClassDefFoundError ignored) {
- // PlaceholderAPI fehlt zur Laufzeit
- }
- }
-
- // KORREKTUR: Farbcodes (&) in echte Minecraft-Farben (§) umwandeln
- prefix = ChatColor.translateAlternateColorCodes('&', prefix);
-
- lore.add("§7Rang: " + (prefix.isEmpty() ? "§fSpieler" : prefix));
- lore.add("§7Level: §a" + target.getLevel());
- lore.add("§7Status: §aOnline");
- lore.add("§8§m-----------------------");
-
- headMeta.setLore(lore);
- head.setItemMeta(headMeta);
- }
- gui.setItem(4, head);
-
- // --- Statistik Kategorie: KAMPF (Slot 19) ---
- gui.setItem(19, createStatsItem(Material.DIAMOND_SWORD, "§c§lKampf-Statistiken",
- "§8» §7Spieler-Kills: §f" + target.getStatistic(Statistic.PLAYER_KILLS),
- "§8» §7Mob-Kills: §f" + target.getStatistic(Statistic.MOB_KILLS),
- "§8» §7Tode gesamt: §f" + target.getStatistic(Statistic.DEATHS),
- "§8» §7Schaden verursacht: §f" + (target.getStatistic(Statistic.DAMAGE_DEALT) / 10) + " ❤"));
-
- // --- Statistik Kategorie: ARBEIT (Slot 21) ---
- // Optimierte Abfrage für wichtige Blöcke
- int totalBlocks = target.getStatistic(Statistic.MINE_BLOCK, Material.STONE) +
- target.getStatistic(Statistic.MINE_BLOCK, Material.DIRT) +
- target.getStatistic(Statistic.MINE_BLOCK, Material.COBBLESTONE);
-
- gui.setItem(21, createStatsItem(Material.IRON_PICKAXE, "§e§lHandwerk & Fleiß",
- "§8» §7Blöcke (S/D/C): §f" + totalBlocks,
- "§8» §7Items gedroppt: §f" + target.getStatistic(Statistic.DROP_COUNT),
- "§8» §7Fische gefangen: §f" + target.getStatistic(Statistic.FISH_CAUGHT),
- "§8» §7Glocken geläutet: §f" + target.getStatistic(Statistic.BELL_RING)));
-
- // --- Statistik Kategorie: BEWEGUNG (Slot 23) ---
- double walkKm = target.getStatistic(Statistic.WALK_ONE_CM) / 100000.0;
- double flyKm = target.getStatistic(Statistic.FLY_ONE_CM) / 100000.0;
- gui.setItem(23, createStatsItem(Material.GOLDEN_BOOTS, "§b§lReise-Statistiken",
- "§8» §7Gelaufen: §f" + String.format("%.2f", walkKm) + " km",
- "§8» §7Geflogen: §f" + String.format("%.2f", flyKm) + " km",
- "§8» §7Sprünge: §f" + target.getStatistic(Statistic.JUMP)));
-
- // --- Statistik Kategorie: ZEIT (Slot 25) ---
- long ticks = target.getStatistic(Statistic.PLAY_ONE_MINUTE);
- long hours = ticks / 72000;
- long mins = (ticks % 72000) / 1200;
- gui.setItem(25, createStatsItem(Material.CLOCK, "§a§lZeit-Statistiken",
- "§8» §7Spielzeit: §f" + hours + " Std. " + mins + " Min.",
- "§8» §7Letzter Tod vor: §f" + (target.getStatistic(Statistic.TIME_SINCE_DEATH) / 1200) + " Min.",
- "§8» §7Tage auf Server: §f" + (target.getStatistic(Statistic.PLAY_ONE_MINUTE) / 1728000)));
-
- // --- Schließen Button (Slot 40) ---
- gui.setItem(40, createSimpleItem(Material.BARRIER, "§c§lMenü schließen"));
-
- // Inventar für den Zuschauer öffnen
- viewer.openInventory(gui);
- }
-
- /**
- * Erstellt ein ItemStack mit Name und Lore-Zeilen inklusive einer Leerzeile am Anfang.
- */
- private ItemStack createStatsItem(Material material, String displayName, String... loreLines) {
- ItemStack item = new ItemStack(material);
- ItemMeta meta = item.getItemMeta();
- if (meta != null) {
- meta.setDisplayName(displayName);
- List lore = new ArrayList<>();
- lore.add(" "); // Leerzeile für sauberes Design
- for (String line : loreLines) {
- lore.add(line);
- }
- meta.setLore(lore);
- item.setItemMeta(meta);
- }
- return item;
- }
-
- /**
- * Erstellt ein einfaches ItemStack ohne Lore für Designzwecke.
- */
- private ItemStack createSimpleItem(Material material, String displayName) {
- ItemStack item = new ItemStack(material);
- ItemMeta meta = item.getItemMeta();
- if (meta != null) {
- meta.setDisplayName(displayName);
- item.setItemMeta(meta);
- }
- return item;
- }
+package de.nexuslobby.modules.player;
+
+import de.nexuslobby.NexusLobby;
+import de.nexuslobby.api.Module;
+import me.clip.placeholderapi.PlaceholderAPI;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Material;
+import org.bukkit.Statistic;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerInteractEntityEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.meta.SkullMeta;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Modul zur Inspektion von Spielern in der Lobby.
+ * Zeigt detaillierte Statistiken in einer interaktiven GUI an.
+ */
+public class PlayerInspectModule implements Module, Listener {
+
+ @Override
+ public String getName() {
+ return "PlayerInspect";
+ }
+
+ @Override
+ public void onEnable() {
+ Bukkit.getPluginManager().registerEvents(this, NexusLobby.getInstance());
+ }
+
+ @Override
+ public void onDisable() {
+ org.bukkit.event.HandlerList.unregisterAll(this);
+ }
+
+ @EventHandler
+ public void onPlayerInteract(PlayerInteractEntityEvent event) {
+ // Prüfen, ob ein Spieler rechtsgeklickt wurde
+ if (event.getRightClicked() instanceof Player target) {
+ Player viewer = event.getPlayer();
+
+ // GUI nur öffnen, wenn die Hand leer ist (verhindert Konflikte mit Items)
+ if (viewer.getInventory().getItemInMainHand().getType() == Material.AIR) {
+ openDetailedInspectGUI(viewer, target);
+ }
+ }
+ }
+
+ @EventHandler
+ public void onInventoryClick(InventoryClickEvent event) {
+ // Sicherstellen, dass es unser Statistik-Inventar ist anhand des Titels
+ if (event.getView().getTitle().contains("Statistiken")) {
+ event.setCancelled(true); // Verhindert, dass Items herausgenommen werden
+
+ ItemStack clickedItem = event.getCurrentItem();
+ if (clickedItem == null || clickedItem.getType() == Material.AIR) return;
+
+ // Logik für den Schließen-Button (Barriere)
+ if (clickedItem.getType() == Material.BARRIER) {
+ event.getWhoClicked().closeInventory();
+ }
+ }
+ }
+
+ public void openDetailedInspectGUI(Player viewer, Player target) {
+ // Titel mit Farbcodes
+ String title = "§8» §3Statistiken: §b" + target.getName();
+ Inventory gui = Bukkit.createInventory(null, 45, title);
+
+ // --- Design: Hintergrund mit Glasscheiben füllen ---
+ ItemStack separator = createSimpleItem(Material.GRAY_STAINED_GLASS_PANE, " ");
+ int[] borderSlots = {
+ 0,1,2,3,4,5,6,7,8,
+ 9,17,
+ 18,26,
+ 27,35,
+ 36,37,38,39,41,42,43,44
+ };
+ for (int slot : borderSlots) gui.setItem(slot, separator);
+
+ // --- Kopf des Spielers mit LuckPerms Prefix via PAPI ---
+ ItemStack head = new ItemStack(Material.PLAYER_HEAD);
+ SkullMeta headMeta = (SkullMeta) head.getItemMeta();
+ if (headMeta != null) {
+ headMeta.setOwningPlayer(target);
+ headMeta.setDisplayName("§e§l" + target.getName());
+
+ List lore = new ArrayList<>();
+ lore.add("§8§m-----------------------");
+
+ // LuckPerms Prefix über PlaceholderAPI auslesen (falls vorhanden)
+ String prefix = "%luckperms_prefix%";
+ if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
+ try {
+ prefix = PlaceholderAPI.setPlaceholders(target, prefix);
+ } catch (NoClassDefFoundError ignored) {
+ // PlaceholderAPI fehlt zur Laufzeit
+ }
+ }
+
+ // KORREKTUR: Farbcodes (&) in echte Minecraft-Farben (§) umwandeln
+ prefix = ChatColor.translateAlternateColorCodes('&', prefix);
+
+ lore.add("§7Rang: " + (prefix.isEmpty() ? "§fSpieler" : prefix));
+ lore.add("§7Level: §a" + target.getLevel());
+ lore.add("§7Status: §aOnline");
+ lore.add("§8§m-----------------------");
+
+ headMeta.setLore(lore);
+ head.setItemMeta(headMeta);
+ }
+ gui.setItem(4, head);
+
+ // --- Statistik Kategorie: KAMPF (Slot 19) ---
+ gui.setItem(19, createStatsItem(Material.DIAMOND_SWORD, "§c§lKampf-Statistiken",
+ "§8» §7Spieler-Kills: §f" + target.getStatistic(Statistic.PLAYER_KILLS),
+ "§8» §7Mob-Kills: §f" + target.getStatistic(Statistic.MOB_KILLS),
+ "§8» §7Tode gesamt: §f" + target.getStatistic(Statistic.DEATHS),
+ "§8» §7Schaden verursacht: §f" + (target.getStatistic(Statistic.DAMAGE_DEALT) / 10) + " ❤"));
+
+ // --- Statistik Kategorie: ARBEIT (Slot 21) ---
+ // Optimierte Abfrage für wichtige Blöcke
+ int totalBlocks = target.getStatistic(Statistic.MINE_BLOCK, Material.STONE) +
+ target.getStatistic(Statistic.MINE_BLOCK, Material.DIRT) +
+ target.getStatistic(Statistic.MINE_BLOCK, Material.COBBLESTONE);
+
+ gui.setItem(21, createStatsItem(Material.IRON_PICKAXE, "§e§lHandwerk & Fleiß",
+ "§8» §7Blöcke (S/D/C): §f" + totalBlocks,
+ "§8» §7Items gedroppt: §f" + target.getStatistic(Statistic.DROP_COUNT),
+ "§8» §7Fische gefangen: §f" + target.getStatistic(Statistic.FISH_CAUGHT),
+ "§8» §7Glocken geläutet: §f" + target.getStatistic(Statistic.BELL_RING)));
+
+ // --- Statistik Kategorie: BEWEGUNG (Slot 23) ---
+ double walkKm = target.getStatistic(Statistic.WALK_ONE_CM) / 100000.0;
+ double flyKm = target.getStatistic(Statistic.FLY_ONE_CM) / 100000.0;
+ gui.setItem(23, createStatsItem(Material.GOLDEN_BOOTS, "§b§lReise-Statistiken",
+ "§8» §7Gelaufen: §f" + String.format("%.2f", walkKm) + " km",
+ "§8» §7Geflogen: §f" + String.format("%.2f", flyKm) + " km",
+ "§8» §7Sprünge: §f" + target.getStatistic(Statistic.JUMP)));
+
+ // --- Statistik Kategorie: ZEIT (Slot 25) ---
+ long ticks = target.getStatistic(Statistic.PLAY_ONE_MINUTE);
+ long hours = ticks / 72000;
+ long mins = (ticks % 72000) / 1200;
+ gui.setItem(25, createStatsItem(Material.CLOCK, "§a§lZeit-Statistiken",
+ "§8» §7Spielzeit: §f" + hours + " Std. " + mins + " Min.",
+ "§8» §7Letzter Tod vor: §f" + (target.getStatistic(Statistic.TIME_SINCE_DEATH) / 1200) + " Min.",
+ "§8» §7Tage auf Server: §f" + (target.getStatistic(Statistic.PLAY_ONE_MINUTE) / 1728000)));
+
+ // --- Schließen Button (Slot 40) ---
+ gui.setItem(40, createSimpleItem(Material.BARRIER, "§c§lMenü schließen"));
+
+ // Inventar für den Zuschauer öffnen
+ viewer.openInventory(gui);
+ }
+
+ /**
+ * Erstellt ein ItemStack mit Name und Lore-Zeilen inklusive einer Leerzeile am Anfang.
+ */
+ private ItemStack createStatsItem(Material material, String displayName, String... loreLines) {
+ ItemStack item = new ItemStack(material);
+ ItemMeta meta = item.getItemMeta();
+ if (meta != null) {
+ meta.setDisplayName(displayName);
+ List lore = new ArrayList<>();
+ lore.add(" "); // Leerzeile für sauberes Design
+ for (String line : loreLines) {
+ lore.add(line);
+ }
+ meta.setLore(lore);
+ item.setItemMeta(meta);
+ }
+ return item;
+ }
+
+ /**
+ * Erstellt ein einfaches ItemStack ohne Lore für Designzwecke.
+ */
+ private ItemStack createSimpleItem(Material material, String displayName) {
+ ItemStack item = new ItemStack(material);
+ ItemMeta meta = item.getItemMeta();
+ if (meta != null) {
+ meta.setDisplayName(displayName);
+ item.setItemMeta(meta);
+ }
+ return item;
+ }
}
\ 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 c9ff6b2..86b5d10 100644
--- a/src/main/java/de/nexuslobby/modules/portal/PortalManager.java
+++ b/src/main/java/de/nexuslobby/modules/portal/PortalManager.java
@@ -131,10 +131,10 @@ public class PortalManager implements Module, Listener {
p.sendMessage("§7§m----------------------------------");
if (volume < 500) {
- p.sendMessage("§e[Nexus] Kleiner Bereich erkannt (Portal-Größe)");
+ p.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§eKleiner 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(de.nexuslobby.utils.LangManager.getPrefix() + "§6Großer Bereich erkannt (WorldBorder-Größe)");
p.sendMessage("§fBefehl: §a/border square");
}
p.sendMessage("§7§m----------------------------------");
diff --git a/src/main/java/de/nexuslobby/modules/servers/ServerChecker.java b/src/main/java/de/nexuslobby/modules/servers/ServerChecker.java
index 2a2fcde..25f4e2a 100644
--- a/src/main/java/de/nexuslobby/modules/servers/ServerChecker.java
+++ b/src/main/java/de/nexuslobby/modules/servers/ServerChecker.java
@@ -1,135 +1,135 @@
-package de.nexuslobby.modules.servers;
-
-import de.nexuslobby.NexusLobby;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.World;
-import org.bukkit.entity.ArmorStand;
-import org.bukkit.scheduler.BukkitTask;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.concurrent.CompletableFuture;
-
-public class ServerChecker {
-
- private static BukkitTask globalCheckerTask = null;
-
- /**
- * Prüft asynchron, ob ein Server unter der angegebenen IP und Port erreichbar ist.
- */
- public static CompletableFuture isOnline(String ip, int port) {
- return CompletableFuture.supplyAsync(() -> {
- try (Socket socket = new Socket()) {
- // 500ms Timeout für stabilere Erkennung
- socket.connect(new InetSocketAddress(ip, port), 500);
- return true;
- } catch (IOException e) {
- return false;
- }
- });
- }
-
- /**
- * Startet den Scheduler, der alle ArmorStands in allen Welten regelmäßig prüft.
- */
- public static void startGlobalChecker() {
- // Cancel alten Task falls vorhanden
- stopGlobalChecker();
-
- // WICHTIG: runTaskTimer (synchron), um den Main-Thread für getEntitiesByClass zu nutzen
- globalCheckerTask = Bukkit.getScheduler().runTaskTimer(NexusLobby.getInstance(), () -> {
- for (World world : Bukkit.getWorlds()) {
- // Das Abrufen der Entities muss auf dem Main-Thread passieren
- for (ArmorStand as : world.getEntitiesByClass(ArmorStand.class)) {
- checkAndUpdateArmorStand(as);
- }
- }
- }, 100L, 200L);
- }
-
- /**
- * Stoppt den Server-Checker Task
- */
- public static void stopGlobalChecker() {
- if (globalCheckerTask != null && !globalCheckerTask.isCancelled()) {
- globalCheckerTask.cancel();
- globalCheckerTask = null;
- }
- }
-
- /**
- * Analysiert die Tags eines ArmorStands und aktualisiert den Namen basierend auf dem Serverstatus.
- */
- private static void checkAndUpdateArmorStand(ArmorStand as) {
- for (String tag : as.getScoreboardTags()) {
- // Erwartetes Format: ascmd:slot1:slot2:type:command
- if (tag.startsWith("ascmd:")) {
- String[] parts = tag.split(":");
- if (parts.length < 5) continue;
-
- String type = parts[3].toLowerCase();
- if (!type.equals("bungee")) continue;
-
- String serverName = parts[4];
-
- // Suche den passenden Key in der Config
- String configKey = null;
- if (NexusLobby.getInstance().getConfig().getConfigurationSection("servers") != null) {
- for (String key : NexusLobby.getInstance().getConfig().getConfigurationSection("servers").getKeys(false)) {
- if (key.equalsIgnoreCase(serverName)) {
- configKey = key;
- break;
- }
- }
- }
-
- if (configKey == null) continue;
-
- String ip = NexusLobby.getInstance().getConfig().getString("servers." + configKey + ".ip");
- int port = NexusLobby.getInstance().getConfig().getInt("servers." + configKey + ".port");
-
- if (ip == null) continue;
-
- // Der Ping selbst läuft asynchron weg vom Main-Thread
- isOnline(ip, port).thenAccept(online -> {
- // Zurück zum Main-Thread für die Änderung des ArmorStands
- Bukkit.getScheduler().runTask(NexusLobby.getInstance(), () -> {
- if (!as.isValid()) return; // Sicherheitscheck falls AS gelöscht wurde
-
- if (online) {
- restoreName(as);
- } else {
- String offlineText = "§c● §lOFFLINE §c●";
- if (!offlineText.equals(as.getCustomName())) {
- as.setCustomName(offlineText);
- as.setCustomNameVisible(true);
- }
- }
- });
- });
- break;
- }
- }
- }
-
- /**
- * Stellt den ursprünglichen Namen des ArmorStands wieder her.
- * Nutzt den Tag "asname:NAME" als Backup.
- */
- private static void restoreName(ArmorStand as) {
- for (String t : as.getScoreboardTags()) {
- if (t.startsWith("asname:")) {
- String originalName = t.substring(7);
- String translatedName = ChatColor.translateAlternateColorCodes('&', originalName);
-
- if (!translatedName.equals(as.getCustomName())) {
- as.setCustomName(translatedName);
- as.setCustomNameVisible(true);
- }
- return;
- }
- }
- }
+package de.nexuslobby.modules.servers;
+
+import de.nexuslobby.NexusLobby;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.World;
+import org.bukkit.entity.ArmorStand;
+import org.bukkit.scheduler.BukkitTask;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.concurrent.CompletableFuture;
+
+public class ServerChecker {
+
+ private static BukkitTask globalCheckerTask = null;
+
+ /**
+ * Prüft asynchron, ob ein Server unter der angegebenen IP und Port erreichbar ist.
+ */
+ public static CompletableFuture isOnline(String ip, int port) {
+ return CompletableFuture.supplyAsync(() -> {
+ try (Socket socket = new Socket()) {
+ // 500ms Timeout für stabilere Erkennung
+ socket.connect(new InetSocketAddress(ip, port), 500);
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ });
+ }
+
+ /**
+ * Startet den Scheduler, der alle ArmorStands in allen Welten regelmäßig prüft.
+ */
+ public static void startGlobalChecker() {
+ // Cancel alten Task falls vorhanden
+ stopGlobalChecker();
+
+ // WICHTIG: runTaskTimer (synchron), um den Main-Thread für getEntitiesByClass zu nutzen
+ globalCheckerTask = Bukkit.getScheduler().runTaskTimer(NexusLobby.getInstance(), () -> {
+ for (World world : Bukkit.getWorlds()) {
+ // Das Abrufen der Entities muss auf dem Main-Thread passieren
+ for (ArmorStand as : world.getEntitiesByClass(ArmorStand.class)) {
+ checkAndUpdateArmorStand(as);
+ }
+ }
+ }, 100L, 200L);
+ }
+
+ /**
+ * Stoppt den Server-Checker Task
+ */
+ public static void stopGlobalChecker() {
+ if (globalCheckerTask != null && !globalCheckerTask.isCancelled()) {
+ globalCheckerTask.cancel();
+ globalCheckerTask = null;
+ }
+ }
+
+ /**
+ * Analysiert die Tags eines ArmorStands und aktualisiert den Namen basierend auf dem Serverstatus.
+ */
+ private static void checkAndUpdateArmorStand(ArmorStand as) {
+ for (String tag : as.getScoreboardTags()) {
+ // Erwartetes Format: ascmd:slot1:slot2:type:command
+ if (tag.startsWith("ascmd:")) {
+ String[] parts = tag.split(":");
+ if (parts.length < 5) continue;
+
+ String type = parts[3].toLowerCase();
+ if (!type.equals("bungee")) continue;
+
+ String serverName = parts[4];
+
+ // Suche den passenden Key in der Config
+ String configKey = null;
+ if (NexusLobby.getInstance().getConfig().getConfigurationSection("servers") != null) {
+ for (String key : NexusLobby.getInstance().getConfig().getConfigurationSection("servers").getKeys(false)) {
+ if (key.equalsIgnoreCase(serverName)) {
+ configKey = key;
+ break;
+ }
+ }
+ }
+
+ if (configKey == null) continue;
+
+ String ip = NexusLobby.getInstance().getConfig().getString("servers." + configKey + ".ip");
+ int port = NexusLobby.getInstance().getConfig().getInt("servers." + configKey + ".port");
+
+ if (ip == null) continue;
+
+ // Der Ping selbst läuft asynchron weg vom Main-Thread
+ isOnline(ip, port).thenAccept(online -> {
+ // Zurück zum Main-Thread für die Änderung des ArmorStands
+ Bukkit.getScheduler().runTask(NexusLobby.getInstance(), () -> {
+ if (!as.isValid()) return; // Sicherheitscheck falls AS gelöscht wurde
+
+ if (online) {
+ restoreName(as);
+ } else {
+ String offlineText = "§c● §lOFFLINE §c●";
+ if (!offlineText.equals(as.getCustomName())) {
+ as.setCustomName(offlineText);
+ as.setCustomNameVisible(true);
+ }
+ }
+ });
+ });
+ break;
+ }
+ }
+ }
+
+ /**
+ * Stellt den ursprünglichen Namen des ArmorStands wieder her.
+ * Nutzt den Tag "asname:NAME" als Backup.
+ */
+ private static void restoreName(ArmorStand as) {
+ for (String t : as.getScoreboardTags()) {
+ if (t.startsWith("asname:")) {
+ String originalName = t.substring(7);
+ String translatedName = ChatColor.translateAlternateColorCodes('&', originalName);
+
+ if (!translatedName.equals(as.getCustomName())) {
+ as.setCustomName(translatedName);
+ as.setCustomNameVisible(true);
+ }
+ return;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/de/nexuslobby/modules/servers/ServerSwitcherListener.java b/src/main/java/de/nexuslobby/modules/servers/ServerSwitcherListener.java
index 241f5c6..04261b8 100644
--- a/src/main/java/de/nexuslobby/modules/servers/ServerSwitcherListener.java
+++ b/src/main/java/de/nexuslobby/modules/servers/ServerSwitcherListener.java
@@ -178,7 +178,7 @@ public class ServerSwitcherListener implements Listener, CommandExecutor {
private void connectBungee(Player player, String serverName) {
if (!Bukkit.getMessenger().isOutgoingChannelRegistered(
NexusLobby.getInstance(), "BungeeCord")) {
- player.sendMessage("§8[§6Nexus§8] §cKein BungeeCord-Kanal registriert.");
+ player.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§cKein BungeeCord-Kanal registriert.");
return;
}
try {
@@ -187,9 +187,9 @@ public class ServerSwitcherListener implements Listener, CommandExecutor {
out.writeUTF("Connect");
out.writeUTF(serverName);
player.sendPluginMessage(NexusLobby.getInstance(), "BungeeCord", b.toByteArray());
- player.sendMessage("§8[§6Nexus§8] §7Verbinde mit §e" + serverName + "§7...");
+ player.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§7Verbinde mit §e" + serverName + "§7...");
} catch (java.io.IOException ex) {
- player.sendMessage("§8[§6Nexus§8] §cFehler beim Verbinden: " + ex.getMessage());
+ player.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§cFehler beim Verbinden: " + ex.getMessage());
}
}
}
\ No newline at end of file
diff --git a/src/main/java/de/nexuslobby/utils/ConfigValidator.java b/src/main/java/de/nexuslobby/utils/ConfigValidator.java
index 4470523..ed71357 100644
--- a/src/main/java/de/nexuslobby/utils/ConfigValidator.java
+++ b/src/main/java/de/nexuslobby/utils/ConfigValidator.java
@@ -1,155 +1,156 @@
-package de.nexuslobby.utils;
-
-import org.bukkit.configuration.file.FileConfiguration;
-import org.bukkit.plugin.java.JavaPlugin;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Validiert Config-Werte und setzt Default-Werte wenn nötig
- */
-public class ConfigValidator {
-
- private final JavaPlugin plugin;
- private final FileConfiguration config;
- private final List warnings = new ArrayList<>();
- private boolean modified = false;
-
- public ConfigValidator(JavaPlugin plugin, FileConfiguration config) {
- this.plugin = plugin;
- this.config = config;
- }
-
- /**
- * Validiert alle Config-Werte und gibt Warnings aus
- */
- public void validate() {
- validateSpawn();
- validateLobbySettings();
- validateTablist();
- validateBall();
- validateModules();
-
- // Warnings ausgeben
- if (!warnings.isEmpty()) {
- plugin.getLogger().warning("=== Config-Validierung ===");
- warnings.forEach(msg -> plugin.getLogger().warning(" " + msg));
- plugin.getLogger().warning("=========================");
- }
-
- // Config speichern wenn Änderungen vorgenommen wurden
- if (modified) {
- plugin.saveConfig();
- plugin.getLogger().info("Config wurde mit Default-Werten aktualisiert.");
- }
- }
-
- private void validateSpawn() {
- ensureDefault("spawn.world", "world");
- ensureDefault("spawn.x", 0.5);
- ensureDefault("spawn.y", 64.0);
- ensureDefault("spawn.z", 0.5);
- ensureDefault("spawn.yaw", 0.0);
- ensureDefault("spawn.pitch", 0.0);
-
- // Validiere Y-Koordinate
- double y = config.getDouble("spawn.y", 64.0);
- if (y < -64 || y > 320) {
- warnings.add("spawn.y (" + y + ") außerhalb des gültigen Bereichs (-64 bis 320)");
- }
- }
-
- private void validateLobbySettings() {
- ensureDefault("lobby.allow-fly", false);
- ensureDefault("lobby.pvp-enabled", false);
- ensureDefault("lobby.build-enabled", false);
- ensureDefault("lobby.default-gamemode", "Adventure");
- ensureDefault("lobby.clear-inventory-on-join", true);
-
- // Validiere GameMode
- String gamemode = config.getString("lobby.default-gamemode", "Adventure");
- if (!isValidGameMode(gamemode)) {
- warnings.add("lobby.default-gamemode '" + gamemode + "' ist ungültig. Nutze: Survival, Creative, Adventure oder Spectator");
- }
- }
-
- private void validateTablist() {
- ensureDefault("tablist.enabled", true);
- ensureDefault("tablist.header", "&6Willkommen auf &eNexusLobby");
- ensureDefault("tablist.footer", "&7Viel Spaß!");
- ensureDefault("tablist.refresh-interval", 40);
-
- // Validiere Refresh-Interval
- int interval = config.getInt("tablist.refresh-interval", 40);
- if (interval < 1) {
- warnings.add("tablist.refresh-interval (" + interval + ") ist zu klein. Minimum ist 1 Tick.");
- config.set("tablist.refresh-interval", 1);
- modified = true;
- } else if (interval > 200) {
- warnings.add("tablist.refresh-interval (" + interval + ") ist sehr hoch. Empfohlen: 20-100 Ticks.");
- }
- }
-
- private void validateBall() {
- ensureDefault("ball.respawn_delay", 60);
-
- // Validiere Respawn-Delay
- long delay = config.getLong("ball.respawn_delay", 60);
- if (delay < 5) {
- warnings.add("ball.respawn_delay (" + delay + "s) ist zu kurz. Minimum empfohlen: 5 Sekunden.");
- } else if (delay > 600) {
- warnings.add("ball.respawn_delay (" + delay + "s) ist sehr lang. Empfohlen: 30-120 Sekunden.");
- }
-
- // Prüfe ob Spawn gesetzt ist
- if (!config.contains("ball.spawn")) {
- warnings.add("ball.spawn nicht gesetzt. Nutze /nexuslobby ball setspawn");
- }
- }
-
- private void validateModules() {
- // Worldborder
- if (config.contains("worldborder.enabled")) {
- ensureDefault("worldborder.type", "SQUARE");
- ensureDefault("worldborder.radius", 50.0);
-
- double radius = config.getDouble("worldborder.radius", 50.0);
- if (radius < 10) {
- warnings.add("worldborder.radius (" + radius + ") ist sehr klein. Minimum empfohlen: 10 Blöcke.");
- } else if (radius > 10000) {
- warnings.add("worldborder.radius (" + radius + ") ist extrem groß. Performance-Warnung!");
- }
-
- String type = config.getString("worldborder.type", "SQUARE");
- if (!type.equalsIgnoreCase("SQUARE") && !type.equalsIgnoreCase("CIRCLE")) {
- warnings.add("worldborder.type '" + type + "' ist ungültig. Nutze: SQUARE oder CIRCLE");
- }
- }
-
- // Items Modul
- if (config.contains("items.lobby-tools")) {
- // Prüfe ob Slot-Nummern gültig sind (0-8)
- for (String toolKey : config.getConfigurationSection("items.lobby-tools").getKeys(false)) {
- int slot = config.getInt("items.lobby-tools." + toolKey + ".slot", -1);
- if (slot < 0 || slot > 8) {
- warnings.add("items.lobby-tools." + toolKey + ".slot (" + slot + ") ist ungültig (0-8)");
- }
- }
- }
- }
-
- private void ensureDefault(String path, Object defaultValue) {
- if (!config.contains(path)) {
- config.set(path, defaultValue);
- modified = true;
- }
- }
-
- private boolean isValidGameMode(String mode) {
- return mode.equalsIgnoreCase("Survival") ||
- mode.equalsIgnoreCase("Creative") ||
- mode.equalsIgnoreCase("Adventure") ||
- mode.equalsIgnoreCase("Spectator");
- }
-}
+package de.nexuslobby.utils;
+
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Validiert Config-Werte und setzt Default-Werte wenn nötig
+ */
+public class ConfigValidator {
+
+ private final JavaPlugin plugin;
+ private final FileConfiguration config;
+ private final List warnings = new ArrayList<>();
+ private boolean modified = false;
+
+ public ConfigValidator(JavaPlugin plugin, FileConfiguration config) {
+ this.plugin = plugin;
+ this.config = config;
+ }
+
+ /**
+ * Validiert alle Config-Werte und gibt Warnings aus
+ */
+ public void validate() {
+ ensureDefault("prefix", "&8[&6Nexus&8] ");
+ validateSpawn();
+ validateLobbySettings();
+ validateTablist();
+ validateBall();
+ validateModules();
+
+ // Warnings ausgeben
+ if (!warnings.isEmpty()) {
+ plugin.getLogger().warning("=== Config-Validierung ===");
+ warnings.forEach(msg -> plugin.getLogger().warning(" " + msg));
+ plugin.getLogger().warning("=========================");
+ }
+
+ // Config speichern wenn Änderungen vorgenommen wurden
+ if (modified) {
+ plugin.saveConfig();
+ plugin.getLogger().info("Config wurde mit Default-Werten aktualisiert.");
+ }
+ }
+
+ private void validateSpawn() {
+ ensureDefault("spawn.world", "world");
+ ensureDefault("spawn.x", 0.5);
+ ensureDefault("spawn.y", 64.0);
+ ensureDefault("spawn.z", 0.5);
+ ensureDefault("spawn.yaw", 0.0);
+ ensureDefault("spawn.pitch", 0.0);
+
+ // Validiere Y-Koordinate
+ double y = config.getDouble("spawn.y", 64.0);
+ if (y < -64 || y > 320) {
+ warnings.add("spawn.y (" + y + ") außerhalb des gültigen Bereichs (-64 bis 320)");
+ }
+ }
+
+ private void validateLobbySettings() {
+ ensureDefault("lobby.allow-fly", false);
+ ensureDefault("lobby.pvp-enabled", false);
+ ensureDefault("lobby.build-enabled", false);
+ ensureDefault("lobby.default-gamemode", "Adventure");
+ ensureDefault("lobby.clear-inventory-on-join", true);
+
+ // Validiere GameMode
+ String gamemode = config.getString("lobby.default-gamemode", "Adventure");
+ if (!isValidGameMode(gamemode)) {
+ warnings.add("lobby.default-gamemode '" + gamemode + "' ist ungültig. Nutze: Survival, Creative, Adventure oder Spectator");
+ }
+ }
+
+ private void validateTablist() {
+ ensureDefault("tablist.enabled", true);
+ ensureDefault("tablist.header", "&6Willkommen auf &eNexusLobby");
+ ensureDefault("tablist.footer", "&7Viel Spaß!");
+ ensureDefault("tablist.refresh-interval", 40);
+
+ // Validiere Refresh-Interval
+ int interval = config.getInt("tablist.refresh-interval", 40);
+ if (interval < 1) {
+ warnings.add("tablist.refresh-interval (" + interval + ") ist zu klein. Minimum ist 1 Tick.");
+ config.set("tablist.refresh-interval", 1);
+ modified = true;
+ } else if (interval > 200) {
+ warnings.add("tablist.refresh-interval (" + interval + ") ist sehr hoch. Empfohlen: 20-100 Ticks.");
+ }
+ }
+
+ private void validateBall() {
+ ensureDefault("ball.respawn_delay", 60);
+
+ // Validiere Respawn-Delay
+ long delay = config.getLong("ball.respawn_delay", 60);
+ if (delay < 5) {
+ warnings.add("ball.respawn_delay (" + delay + "s) ist zu kurz. Minimum empfohlen: 5 Sekunden.");
+ } else if (delay > 600) {
+ warnings.add("ball.respawn_delay (" + delay + "s) ist sehr lang. Empfohlen: 30-120 Sekunden.");
+ }
+
+ // Prüfe ob Spawn gesetzt ist
+ if (!config.contains("ball.spawn")) {
+ warnings.add("ball.spawn nicht gesetzt. Nutze /nexuslobby ball setspawn");
+ }
+ }
+
+ private void validateModules() {
+ // Worldborder
+ if (config.contains("worldborder.enabled")) {
+ ensureDefault("worldborder.type", "SQUARE");
+ ensureDefault("worldborder.radius", 50.0);
+
+ double radius = config.getDouble("worldborder.radius", 50.0);
+ if (radius < 10) {
+ warnings.add("worldborder.radius (" + radius + ") ist sehr klein. Minimum empfohlen: 10 Blöcke.");
+ } else if (radius > 10000) {
+ warnings.add("worldborder.radius (" + radius + ") ist extrem groß. Performance-Warnung!");
+ }
+
+ String type = config.getString("worldborder.type", "SQUARE");
+ if (!type.equalsIgnoreCase("SQUARE") && !type.equalsIgnoreCase("CIRCLE")) {
+ warnings.add("worldborder.type '" + type + "' ist ungültig. Nutze: SQUARE oder CIRCLE");
+ }
+ }
+
+ // Items Modul
+ if (config.contains("items.lobby-tools")) {
+ // Prüfe ob Slot-Nummern gültig sind (0-8)
+ for (String toolKey : config.getConfigurationSection("items.lobby-tools").getKeys(false)) {
+ int slot = config.getInt("items.lobby-tools." + toolKey + ".slot", -1);
+ if (slot < 0 || slot > 8) {
+ warnings.add("items.lobby-tools." + toolKey + ".slot (" + slot + ") ist ungültig (0-8)");
+ }
+ }
+ }
+ }
+
+ private void ensureDefault(String path, Object defaultValue) {
+ if (!config.contains(path)) {
+ config.set(path, defaultValue);
+ modified = true;
+ }
+ }
+
+ private boolean isValidGameMode(String mode) {
+ return mode.equalsIgnoreCase("Survival") ||
+ mode.equalsIgnoreCase("Creative") ||
+ mode.equalsIgnoreCase("Adventure") ||
+ mode.equalsIgnoreCase("Spectator");
+ }
+}
diff --git a/src/main/java/de/nexuslobby/utils/LangManager.java b/src/main/java/de/nexuslobby/utils/LangManager.java
index 83c8b9e..53b63d9 100644
--- a/src/main/java/de/nexuslobby/utils/LangManager.java
+++ b/src/main/java/de/nexuslobby/utils/LangManager.java
@@ -1,32 +1,43 @@
-package de.nexuslobby.utils;
-
-import org.bukkit.plugin.java.JavaPlugin;
-import org.yaml.snakeyaml.Yaml;
-
-import java.io.InputStream;
-import java.util.Map;
-
-public class LangManager {
- private static Map> langMap;
- private static String currentLang = "de";
-
- public static void load(JavaPlugin plugin) {
- Yaml yaml = new Yaml();
- try (InputStream in = plugin.getResource("lang.yml")) {
- langMap = yaml.load(in);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public static void setLanguage(String lang) {
- currentLang = lang;
- }
-
- public static String get(String key) {
- if (langMap == null) return key;
- Map translations = langMap.get(key);
- if (translations == null) return key;
- return translations.getOrDefault(currentLang, key);
- }
-}
+package de.nexuslobby.utils;
+
+import de.nexuslobby.NexusLobby;
+import org.bukkit.ChatColor;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.InputStream;
+import java.util.Map;
+
+public class LangManager {
+ private static Map> langMap;
+ private static String currentLang = "de";
+
+ public static void load(JavaPlugin plugin) {
+ Yaml yaml = new Yaml();
+ try (InputStream in = plugin.getResource("lang.yml")) {
+ langMap = yaml.load(in);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void setLanguage(String lang) {
+ currentLang = lang;
+ }
+
+ public static String get(String key) {
+ if (langMap == null) return key;
+ Map translations = langMap.get(key);
+ if (translations == null) return key;
+ return translations.getOrDefault(currentLang, key)
+ .replace("§8[§6Nexus§8] ", getPrefix());
+ }
+
+ public static String getPrefix() {
+ NexusLobby plugin = NexusLobby.getInstance();
+ String prefix = plugin == null
+ ? "&8[&6Nexus&8] "
+ : plugin.getConfig().getString("prefix", "&8[&6Nexus&8] ");
+ return ChatColor.translateAlternateColorCodes('&', prefix);
+ }
+}
diff --git a/src/main/java/de/nexuslobby/utils/UpdateChecker.java b/src/main/java/de/nexuslobby/utils/UpdateChecker.java
index 56e88ca..d9e0364 100644
--- a/src/main/java/de/nexuslobby/utils/UpdateChecker.java
+++ b/src/main/java/de/nexuslobby/utils/UpdateChecker.java
@@ -1,36 +1,36 @@
-package de.nexuslobby.utils;
-
-import de.nexuslobby.NexusLobby;
-import org.bukkit.Bukkit;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Scanner;
-import java.util.function.Consumer;
-
-public class UpdateChecker {
-
- private final NexusLobby plugin;
- private static final int RESOURCE_ID = 132388;
-
- public UpdateChecker(NexusLobby plugin) {
- this.plugin = plugin;
- }
-
- public void getVersion(final Consumer consumer) {
- Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> {
- try (InputStream is = new URL(
- "https://api.spigotmc.org/legacy/update.php?resource=" + RESOURCE_ID + "/~").openStream();
- Scanner scanner = new Scanner(is)) {
-
- if (scanner.hasNext()) {
- consumer.accept(scanner.next());
- }
-
- } catch (IOException e) {
- plugin.getLogger().warning("Update-Check fehlgeschlagen: " + e.getMessage());
- }
- });
- }
+package de.nexuslobby.utils;
+
+import de.nexuslobby.NexusLobby;
+import org.bukkit.Bukkit;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Scanner;
+import java.util.function.Consumer;
+
+public class UpdateChecker {
+
+ private final NexusLobby plugin;
+ private static final int RESOURCE_ID = 132388;
+
+ public UpdateChecker(NexusLobby plugin) {
+ this.plugin = plugin;
+ }
+
+ public void getVersion(final Consumer consumer) {
+ Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> {
+ try (InputStream is = new URL(
+ "https://api.spigotmc.org/legacy/update.php?resource=" + RESOURCE_ID + "/~").openStream();
+ Scanner scanner = new Scanner(is)) {
+
+ if (scanner.hasNext()) {
+ consumer.accept(scanner.next());
+ }
+
+ } catch (IOException e) {
+ plugin.getLogger().warning("Update-Check fehlgeschlagen: " + e.getMessage());
+ }
+ });
+ }
}
\ No newline at end of file
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 3274c35..2bd981e 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -20,6 +20,9 @@
# Verfügbare Optionen: de (Deutsch), en (Englisch), fr (Französisch)
language: de
+# Prefix vor Plugin-Nachrichten im Chat (&-Farbcodes sind erlaubt)
+prefix: "&8[&6Nexus&8] "
+
# ══════════════════════════════════════════════════════════════════════════════
# SPAWN EINSTELLUNGEN
# ══════════════════════════════════════════════════════════════════════════════
diff --git a/src/main/resources/lang.yml b/src/main/resources/lang.yml
index 04adf4a..3be4246 100644
--- a/src/main/resources/lang.yml
+++ b/src/main/resources/lang.yml
@@ -1,203 +1,203 @@
-# _ __ __ __ __
-# / | / /__ _ ____ _______/ / ____ / /_ / /_ __ __
-# / |/ / _ \| |/_/ / / / ___/ / / __ \/ __ \/ __ \/ / / /
-# / /| / __/> /_/ (__ ) /___/ /_/ / /_/ / /_/ / /_/ /
-# /_/ |_/\___/_/|_|\__,_/____/_____/\____/_.___/_.___/\__, /
-# /____/
-#
-# =====================================================
-# DEFAULT Language
-# =====================================================
-
-soccer_module_not_loaded:
- de: "§cDas Fußball-Modul ist nicht geladen."
- en: "§cThe soccer module is not loaded."
-parkour_usage:
- de: "§8[§6Nexus§8] §7Nutze: §e/nexus parkour "
- en: "§8[§6Nexus§8] §7Usage: §e/nexus parkour "
-parkour_run_aborted:
- de: "§8[§6Nexus§8] §7Dein aktueller Lauf wurde abgebrochen."
- en: "§8[§6Nexus§8] §7Your current run was aborted."
-parkour_besttimes_cleared:
- de: "§8[§6Nexus§8] §aAlle Parkour-Bestzeiten wurden gelöscht!"
- en: "§8[§6Nexus§8] §aAll parkour best times have been cleared!"
-parkour_track_removed:
- de: "§8[§6Nexus§8] §cDie gesamte Strecke (Checkpoints & Ziel) wurde gelöscht!"
- en: "§8[§6Nexus§8] §cThe entire track (checkpoints & finish) has been removed!"
-unknown_subcommand:
- de: "§cUnbekannter Unterbefehl."
- en: "§cUnknown subcommand."
-parkour_npc_marked:
- de: "§8[§6Nexus§8] §aArmorStand als Parkour-NPC markiert!"
- en: "§8[§6Nexus§8] §aArmorStand marked as parkour NPC!"
-parkour_start_set:
- de: "§8[§6Nexus§8] §aParkour-Startpunkt an deiner Position gesetzt!"
- en: "§8[§6Nexus§8] §aParkour start set at your position!"
-scoreboard_usage:
- de: "§cBenutzung: /nexus sb "
- en: "§cUsage: /nexus sb "
-scoreboard_module_disabled:
- de: "§cScoreboard-Modul ist deaktiviert."
- en: "§cScoreboard module is disabled."
-info_header:
- de: "§8§m--------------------------------------"
- en: "§8§m--------------------------------------"
-info_title:
- de: "§6§lNexusLobby §7- Informationen"
- en: "§6§lNexusLobby §7- Information"
-info_spawn:
- de: "§f/spawn §7- Zum Spawn"
- en: "§f/spawn §7- To spawn"
-info_parkour:
- de: "§f/setstart §8| §f/setcheckpoint §8| §f/setfinish"
- en: "§f/setstart §8| §f/setcheckpoint §8| §f/setfinish"
-info_removeall:
- de: "§f/nexus parkour removeall §7- Strecke löschen"
- en: "§f/nexus parkour removeall §7- Remove track"
-info_ball:
- de: "§f/nexus ball setspawn §7- Fußball Spawn setzen"
- en: "§f/nexus ball setspawn §7- Set soccer spawn"
-info_setspawn:
- de: "§f/nexus setspawn §7- Spawn setzen"
- en: "§f/nexus setspawn §7- Set spawn"
-info_scoreboard:
- de: "§f/nexus sb §7- Scoreboard"
- en: "§f/nexus sb §7- Scoreboard"
-info_reload:
- de: "§f/nexus reload §7- Config laden"
- en: "§f/nexus reload §7- Reload config"
-info_footer:
- de: "§8§m--------------------------------------"
- en: "§8§m--------------------------------------"
-parkour_trainer_greeting:
- de: "§6§lTrainer §8» §aViel Erfolg beim Parkour! Gib dein Bestes!"
- en: "§6§lTrainer §8» §aGood luck with the parkour! Give it your best!"
-update_available:
- de: "§8[§6Nexus§8] §aEin neues §6Update §afür §eNexusLobby §aist verfügbar!"
- en: "§8[§6Nexus§8] §aA new §6update §afor §eNexusLobby §ais available!"
-update_version:
- de: "§8» §7Version: §c{old} §8-> §a{new}"
- en: "§8» §7Version: §c{old} §8-> §a{new}"
-update_download_link:
- de: "§8» §6Klicke §e§l[HIER] §6zum Herunterladen."
- en: "§8» §6Click §e§l[HERE] §6to download."
-update_download_hover:
- de: "§7Öffnet die Release-Seite"
- en: "§7Opens the release page"
-hider_all:
- de: "§aAlle Spieler"
- en: "§aAll players"
-hider_none:
- de: "§cKeine Spieler"
- en: "§cNo players"
-void_protection_message:
- de: "§cDu wurdest vor dem Void gerettet!"
- en: "§cYou were saved from the void!"
-proxy_not_registered:
- de: "§cProxy-Verbindung nicht möglich (BungeeCord Kanal nicht registriert)."
- en: "§cProxy connection not possible (BungeeCord channel not registered)."
-connecting_to_server:
- de: "§eVerbinde zu: §f{server}"
- en: "§eConnecting to: §f{server}"
-server_connect_error:
- de: "§cFehler beim Verbinden zum Server."
- en: "§cError connecting to server."
-proxy_connect_error:
- de: "§cProxy-Verbindung nicht möglich."
- en: "§cProxy connection not possible."
-armorstand_lookat_required:
- de: "§cDu musst einen ArmorStand direkt anschauen (Fadenkreuz)!"
- en: "§cYou must look directly at an ArmorStand (crosshair)!"
-conv_link_usage:
- de: "§cNutze: /nexuscmd conv link "
- en: "§cUsage: /nexuscmd conv link "
-conv_mark_npcs:
- de: "§cBitte markiere mindestens die ersten beiden NPCs (select1 & select2)!"
- en: "§cPlease mark at least the first two NPCs (select1 & select2)!"
-conv_link_created:
- de: "§a§lDauerhafte Verknüpfung erstellt!"
- en: "§a§lPermanent link created!"
-conv_link_npcs:
- de: "§7Beteiligte NPCs: §e{count}"
- en: "§7Linked NPCs: §e{count}"
-conv_speaker_not_found:
- de: "§cFehler: Sprecher 1 nicht gefunden."
- en: "§cError: Speaker 1 not found."
-conv_unlink_lookat:
- de: "§cSchau den NPC an, dessen Verknüpfung du lösen willst!"
- en: "§cLook at the NPC you want to unlink!"
-conv_unlinked:
- de: "§eNPC-Verknüpfung wurde aufgehoben."
- en: "§eNPC link has been removed."
-conv_start_usage:
- de: "§cNutze: /nexuscmd conv start "
- en: "§cUsage: /nexuscmd conv start "
-conv_mark_two_npcs:
- de: "§cBitte markiere mindestens zwei NPCs!"
- en: "§cPlease mark at least two NPCs!"
-npc_bubble_sent:
- de: "§aNPC-Sprechblase gesendet."
- en: "§aNPC speech bubble sent."
-lookat_off:
- de: "§cBlickkontakt aus."
- en: "§cLook-at disabled."
-lookat_on:
- de: "§aBlickkontakt an."
- en: "§aLook-at enabled."
-name_removed:
- de: "§eName entfernt."
- en: "§eName removed."
-name_set:
- de: "§7Name gesetzt: {name}"
- en: "§7Name set: {name}"
-status_backup_saved:
- de: "§8(Status-Backup wurde gespeichert)"
- en: "§8(Status backup saved)"
-command_bound:
- de: "§aBefehl gebunden."
- en: "§aCommand bound."
-no_target:
- de: "§cKein Ziel!"
- en: "§cNo target!"
-commands_and_tags:
- de: "§6§lBefehle & Tags:"
- en: "§6§lCommands & Tags:"
-commands_removed:
- de: "§eAlle Befehle gelöscht."
- en: "§eAll commands removed."
-welcome:
- de: "Willkommen auf dem Server!"
- en: "Welcome to the server!"
-no_permission:
- de: "§cKeine Berechtigung."
- en: "§cNo permission."
-only_player:
- de: "§cDieser Befehl ist nur für Spieler!"
- en: "§cThis command is for players only!"
-parkour_checkpoint_set:
- de: "§8[§6Nexus§8] §aParkour-Checkpoint gesetzt!"
- en: "§8[§6Nexus§8] §aParkour checkpoint set!"
-parkour_finish_set:
- de: "§8[§6Nexus§8] §aParkour-Zielpunkt gesetzt!"
- en: "§8[§6Nexus§8] §aParkour finish set!"
-teleport_spawn:
- de: "§8[§6Nexus§8] §aDu wurdest zum Spawn teleportiert."
- en: "§8[§6Nexus§8] §aYou have been teleported to spawn."
-spawn_world_missing:
- de: "§cFehler: Die Spawn-Welt existiert nicht."
- en: "§cError: The spawn world does not exist."
-spawn_not_set:
- de: "§cEs wurde noch kein Spawn gesetzt."
- en: "§cNo spawn has been set yet."
-plugin_reloaded:
- de: "§8[§6Nexus§8] §aPlugin erfolgreich neu geladen!"
- en: "§8[§6Nexus§8] §aPlugin successfully reloaded!"
-spawn_set:
- de: "§8[§6Nexus§8] §aLobby-Spawn erfolgreich gesetzt!"
- en: "§8[§6Nexus§8] §aLobby spawn set successfully!"
-silentjoin_on:
- de: "§8[§6Nexus§8] §7Silent Join: §aAktiviert"
- en: "§8[§6Nexus§8] §7Silent Join: §aEnabled"
-silentjoin_off:
- de: "§8[§6Nexus§8] §7Silent Join: §cDeaktiviert"
- en: "§8[§6Nexus§8] §7Silent Join: §cDisabled"
+# _ __ __ __ __
+# / | / /__ _ ____ _______/ / ____ / /_ / /_ __ __
+# / |/ / _ \| |/_/ / / / ___/ / / __ \/ __ \/ __ \/ / / /
+# / /| / __/> /_/ (__ ) /___/ /_/ / /_/ / /_/ / /_/ /
+# /_/ |_/\___/_/|_|\__,_/____/_____/\____/_.___/_.___/\__, /
+# /____/
+#
+# =====================================================
+# DEFAULT Language
+# =====================================================
+
+soccer_module_not_loaded:
+ de: "§cDas Fußball-Modul ist nicht geladen."
+ en: "§cThe soccer module is not loaded."
+parkour_usage:
+ de: "§8[§6Nexus§8] §7Nutze: §e/nexus parkour "
+ en: "§8[§6Nexus§8] §7Usage: §e/nexus parkour "
+parkour_run_aborted:
+ de: "§8[§6Nexus§8] §7Dein aktueller Lauf wurde abgebrochen."
+ en: "§8[§6Nexus§8] §7Your current run was aborted."
+parkour_besttimes_cleared:
+ de: "§8[§6Nexus§8] §aAlle Parkour-Bestzeiten wurden gelöscht!"
+ en: "§8[§6Nexus§8] §aAll parkour best times have been cleared!"
+parkour_track_removed:
+ de: "§8[§6Nexus§8] §cDie gesamte Strecke (Checkpoints & Ziel) wurde gelöscht!"
+ en: "§8[§6Nexus§8] §cThe entire track (checkpoints & finish) has been removed!"
+unknown_subcommand:
+ de: "§cUnbekannter Unterbefehl."
+ en: "§cUnknown subcommand."
+parkour_npc_marked:
+ de: "§8[§6Nexus§8] §aArmorStand als Parkour-NPC markiert!"
+ en: "§8[§6Nexus§8] §aArmorStand marked as parkour NPC!"
+parkour_start_set:
+ de: "§8[§6Nexus§8] §aParkour-Startpunkt an deiner Position gesetzt!"
+ en: "§8[§6Nexus§8] §aParkour start set at your position!"
+scoreboard_usage:
+ de: "§cBenutzung: /nexus sb "
+ en: "§cUsage: /nexus sb "
+scoreboard_module_disabled:
+ de: "§cScoreboard-Modul ist deaktiviert."
+ en: "§cScoreboard module is disabled."
+info_header:
+ de: "§8§m--------------------------------------"
+ en: "§8§m--------------------------------------"
+info_title:
+ de: "§6§lNexusLobby §7- Informationen"
+ en: "§6§lNexusLobby §7- Information"
+info_spawn:
+ de: "§f/spawn §7- Zum Spawn"
+ en: "§f/spawn §7- To spawn"
+info_parkour:
+ de: "§f/setstart §8| §f/setcheckpoint §8| §f/setfinish"
+ en: "§f/setstart §8| §f/setcheckpoint §8| §f/setfinish"
+info_removeall:
+ de: "§f/nexus parkour removeall §7- Strecke löschen"
+ en: "§f/nexus parkour removeall §7- Remove track"
+info_ball:
+ de: "§f/nexus ball setspawn §7- Fußball Spawn setzen"
+ en: "§f/nexus ball setspawn §7- Set soccer spawn"
+info_setspawn:
+ de: "§f/nexus setspawn §7- Spawn setzen"
+ en: "§f/nexus setspawn §7- Set spawn"
+info_scoreboard:
+ de: "§f/nexus sb §7- Scoreboard"
+ en: "§f/nexus sb §7- Scoreboard"
+info_reload:
+ de: "§f/nexus reload §7- Config laden"
+ en: "§f/nexus reload §7- Reload config"
+info_footer:
+ de: "§8§m--------------------------------------"
+ en: "§8§m--------------------------------------"
+parkour_trainer_greeting:
+ de: "§6§lTrainer §8» §aViel Erfolg beim Parkour! Gib dein Bestes!"
+ en: "§6§lTrainer §8» §aGood luck with the parkour! Give it your best!"
+update_available:
+ de: "§8[§6Nexus§8] §aEin neues §6Update §afür §eNexusLobby §aist verfügbar!"
+ en: "§8[§6Nexus§8] §aA new §6update §afor §eNexusLobby §ais available!"
+update_version:
+ de: "§8» §7Version: §c{old} §8-> §a{new}"
+ en: "§8» §7Version: §c{old} §8-> §a{new}"
+update_download_link:
+ de: "§8» §6Klicke §e§l[HIER] §6zum Herunterladen."
+ en: "§8» §6Click §e§l[HERE] §6to download."
+update_download_hover:
+ de: "§7Öffnet die Release-Seite"
+ en: "§7Opens the release page"
+hider_all:
+ de: "§aAlle Spieler"
+ en: "§aAll players"
+hider_none:
+ de: "§cKeine Spieler"
+ en: "§cNo players"
+void_protection_message:
+ de: "§cDu wurdest vor dem Void gerettet!"
+ en: "§cYou were saved from the void!"
+proxy_not_registered:
+ de: "§cProxy-Verbindung nicht möglich (BungeeCord Kanal nicht registriert)."
+ en: "§cProxy connection not possible (BungeeCord channel not registered)."
+connecting_to_server:
+ de: "§eVerbinde zu: §f{server}"
+ en: "§eConnecting to: §f{server}"
+server_connect_error:
+ de: "§cFehler beim Verbinden zum Server."
+ en: "§cError connecting to server."
+proxy_connect_error:
+ de: "§cProxy-Verbindung nicht möglich."
+ en: "§cProxy connection not possible."
+armorstand_lookat_required:
+ de: "§cDu musst einen ArmorStand direkt anschauen (Fadenkreuz)!"
+ en: "§cYou must look directly at an ArmorStand (crosshair)!"
+conv_link_usage:
+ de: "§cNutze: /nexuscmd conv link "
+ en: "§cUsage: /nexuscmd conv link "
+conv_mark_npcs:
+ de: "§cBitte markiere mindestens die ersten beiden NPCs (select1 & select2)!"
+ en: "§cPlease mark at least the first two NPCs (select1 & select2)!"
+conv_link_created:
+ de: "§a§lDauerhafte Verknüpfung erstellt!"
+ en: "§a§lPermanent link created!"
+conv_link_npcs:
+ de: "§7Beteiligte NPCs: §e{count}"
+ en: "§7Linked NPCs: §e{count}"
+conv_speaker_not_found:
+ de: "§cFehler: Sprecher 1 nicht gefunden."
+ en: "§cError: Speaker 1 not found."
+conv_unlink_lookat:
+ de: "§cSchau den NPC an, dessen Verknüpfung du lösen willst!"
+ en: "§cLook at the NPC you want to unlink!"
+conv_unlinked:
+ de: "§eNPC-Verknüpfung wurde aufgehoben."
+ en: "§eNPC link has been removed."
+conv_start_usage:
+ de: "§cNutze: /nexuscmd conv start "
+ en: "§cUsage: /nexuscmd conv start "
+conv_mark_two_npcs:
+ de: "§cBitte markiere mindestens zwei NPCs!"
+ en: "§cPlease mark at least two NPCs!"
+npc_bubble_sent:
+ de: "§aNPC-Sprechblase gesendet."
+ en: "§aNPC speech bubble sent."
+lookat_off:
+ de: "§cBlickkontakt aus."
+ en: "§cLook-at disabled."
+lookat_on:
+ de: "§aBlickkontakt an."
+ en: "§aLook-at enabled."
+name_removed:
+ de: "§eName entfernt."
+ en: "§eName removed."
+name_set:
+ de: "§7Name gesetzt: {name}"
+ en: "§7Name set: {name}"
+status_backup_saved:
+ de: "§8(Status-Backup wurde gespeichert)"
+ en: "§8(Status backup saved)"
+command_bound:
+ de: "§aBefehl gebunden."
+ en: "§aCommand bound."
+no_target:
+ de: "§cKein Ziel!"
+ en: "§cNo target!"
+commands_and_tags:
+ de: "§6§lBefehle & Tags:"
+ en: "§6§lCommands & Tags:"
+commands_removed:
+ de: "§eAlle Befehle gelöscht."
+ en: "§eAll commands removed."
+welcome:
+ de: "Willkommen auf dem Server!"
+ en: "Welcome to the server!"
+no_permission:
+ de: "§cKeine Berechtigung."
+ en: "§cNo permission."
+only_player:
+ de: "§cDieser Befehl ist nur für Spieler!"
+ en: "§cThis command is for players only!"
+parkour_checkpoint_set:
+ de: "§8[§6Nexus§8] §aParkour-Checkpoint gesetzt!"
+ en: "§8[§6Nexus§8] §aParkour checkpoint set!"
+parkour_finish_set:
+ de: "§8[§6Nexus§8] §aParkour-Zielpunkt gesetzt!"
+ en: "§8[§6Nexus§8] §aParkour finish set!"
+teleport_spawn:
+ de: "§8[§6Nexus§8] §aDu wurdest zum Spawn teleportiert."
+ en: "§8[§6Nexus§8] §aYou have been teleported to spawn."
+spawn_world_missing:
+ de: "§cFehler: Die Spawn-Welt existiert nicht."
+ en: "§cError: The spawn world does not exist."
+spawn_not_set:
+ de: "§cEs wurde noch kein Spawn gesetzt."
+ en: "§cNo spawn has been set yet."
+plugin_reloaded:
+ de: "§8[§6Nexus§8] §aPlugin erfolgreich neu geladen!"
+ en: "§8[§6Nexus§8] §aPlugin successfully reloaded!"
+spawn_set:
+ de: "§8[§6Nexus§8] §aLobby-Spawn erfolgreich gesetzt!"
+ en: "§8[§6Nexus§8] §aLobby spawn set successfully!"
+silentjoin_on:
+ de: "§8[§6Nexus§8] §7Silent Join: §aAktiviert"
+ en: "§8[§6Nexus§8] §7Silent Join: §aEnabled"
+silentjoin_off:
+ de: "§8[§6Nexus§8] §7Silent Join: §cDeaktiviert"
+ en: "§8[§6Nexus§8] §7Silent Join: §cDisabled"
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 28e11fe..da2f024 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -1,6 +1,6 @@
name: NexusLobby
main: de.nexuslobby.NexusLobby
-version: "1.9"
+version: "2.0"
api-version: "1.21"
author: M_Viper
description: Modular Lobby Plugin with an invisible Particle-Parkour system.