diff --git a/src/main/java/de/nexuslobby/NexusLobby.java b/src/main/java/de/nexuslobby/NexusLobby.java index fae2dc7..9f8aac0 100644 --- a/src/main/java/de/nexuslobby/NexusLobby.java +++ b/src/main/java/de/nexuslobby/NexusLobby.java @@ -14,6 +14,7 @@ import de.nexuslobby.modules.portal.PortalManager; import de.nexuslobby.modules.portal.PortalCommand; import de.nexuslobby.modules.servers.ServerSwitcherListener; import de.nexuslobby.modules.armorstandtools.*; +import de.nexuslobby.modules.gadgets.GadgetModule; import de.nexuslobby.utils.VoidProtection; import de.nexuslobby.utils.DoubleJump; import de.nexuslobby.utils.PlayerHider; @@ -47,6 +48,8 @@ public class NexusLobby extends JavaPlugin implements Listener { private PortalManager portalManager; private TablistModule tablistModule; private LobbySettingsModule lobbySettingsModule; + private ItemsModule itemsModule; + private GadgetModule gadgetModule; private File visualsFile; private FileConfiguration visualsConfig; @@ -62,6 +65,7 @@ public class NexusLobby extends JavaPlugin implements Listener { public void onEnable() { instance = this; + // Erst Config initialisieren initCustomConfigs(); getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); @@ -126,7 +130,13 @@ public class NexusLobby extends JavaPlugin implements Listener { private void registerModules() { moduleManager.registerModule(new ProtectionModule()); moduleManager.registerModule(new ScoreboardModule()); - moduleManager.registerModule(new ItemsModule()); + + this.itemsModule = new ItemsModule(); + moduleManager.registerModule(this.itemsModule); + + this.gadgetModule = new GadgetModule(); + moduleManager.registerModule(this.gadgetModule); + moduleManager.registerModule(new SecurityModule()); moduleManager.registerModule(new BossBarModule()); moduleManager.registerModule(new ActionBarModule()); @@ -151,15 +161,13 @@ public class NexusLobby extends JavaPlugin implements Listener { getServer().getPluginManager().registerEvents(new ASTListener(), this); } - // Priorität auf LOWEST, damit das Inventar VOR den Modulen geleert wird @EventHandler(priority = EventPriority.LOWEST) public void onJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); event.setJoinMessage(null); - // FEHLERBEHEBUNG: Inventar leeren, um doppelte Items zu vermeiden player.getInventory().clear(); - player.getInventory().setArmorContents(null); // Auch Rüstung entfernen + player.getInventory().setArmorContents(null); BuildCommand.removePlayerFromBuildMode(player); @@ -192,9 +200,14 @@ public class NexusLobby extends JavaPlugin implements Listener { File configFile = new File(getDataFolder(), "config.yml"); if (!configFile.exists()) { + // Nur speichern wenn sie fehlt saveResource("config.yml", false); + } else { + // WICHTIG: ConfigUpdater für config.yml deaktiviert, da er Sektionen nicht korrekt erkennt! + // ConfigUpdater.updateConfig("config.yml"); } - ConfigUpdater.updateConfig("config.yml"); + + // Einfaches Laden reicht völlig aus reloadConfig(); File settingsFile = new File(getDataFolder(), "settings.yml"); @@ -288,4 +301,6 @@ public class NexusLobby extends JavaPlugin implements Listener { public ModuleManager getModuleManager() { return moduleManager; } public TablistModule getTablistModule() { return tablistModule; } public LobbySettingsModule getLobbySettingsModule() { return lobbySettingsModule; } + public ItemsModule getItemsModule() { return itemsModule; } + public GadgetModule getGadgetModule() { return gadgetModule; } } \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/commands/BuildCommand.java b/src/main/java/de/nexuslobby/commands/BuildCommand.java index a955534..48a8280 100644 --- a/src/main/java/de/nexuslobby/commands/BuildCommand.java +++ b/src/main/java/de/nexuslobby/commands/BuildCommand.java @@ -12,7 +12,6 @@ import java.util.UUID; public class BuildCommand implements CommandExecutor { - // Liste der Spieler im Baumodus private static final ArrayList buildModePlayers = new ArrayList<>(); @Override @@ -30,7 +29,16 @@ public class BuildCommand implements CommandExecutor { // BAUMODUS DEAKTIVIEREN buildModePlayers.remove(uuid); - // Gamemode zurücksetzen (aus Config) + // Inventar leeren + player.getInventory().clear(); + player.getInventory().setArmorContents(null); + + // Lobby-Items über das Modul wiedergeben + if (NexusLobby.getInstance().getItemsModule() != null) { + NexusLobby.getInstance().getItemsModule().giveLobbyItems(player); + } + + // Gamemode zurücksetzen String defaultGmName = NexusLobby.getInstance().getConfig().getString("default-gamemode", "ADVENTURE"); try { GameMode gm = GameMode.valueOf(defaultGmName.toUpperCase()); @@ -43,6 +51,9 @@ public class BuildCommand implements CommandExecutor { } else { // BAUMODUS AKTIVIEREN buildModePlayers.add(uuid); + + player.getInventory().clear(); + player.getInventory().setArmorContents(null); player.setGameMode(GameMode.CREATIVE); player.sendMessage("§8» §6§lBuild §8| §7Baumodus §aaktiviert§7."); diff --git a/src/main/java/de/nexuslobby/modules/BuildModule.java b/src/main/java/de/nexuslobby/modules/BuildModule.java new file mode 100644 index 0000000..a9e439f --- /dev/null +++ b/src/main/java/de/nexuslobby/modules/BuildModule.java @@ -0,0 +1,47 @@ +package de.nexuslobby.modules; + +import de.nexuslobby.NexusLobby; +import de.nexuslobby.api.Module; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import java.util.ArrayList; +import java.util.UUID; + +public class BuildModule implements Module { + + private final ArrayList buildModePlayers = new ArrayList<>(); + + @Override + public String getName() { + return "Build"; + } + + @Override + public void onEnable() { + // Falls du hier den Command registrierst, achte darauf, + // dass er nicht doppelt in der NexusLobby.java registriert wird. + } + + public void toggleBuildMode(Player player) { + if (!player.hasPermission("nexuslobby.build")) return; + + if (buildModePlayers.contains(player.getUniqueId())) { + buildModePlayers.remove(player.getUniqueId()); + player.setGameMode(GameMode.SURVIVAL); + player.getInventory().clear(); + + // KORREKTUR: Hier muss getItemsModule() mit "s" stehen! + if (NexusLobby.getInstance().getItemsModule() != null) { + NexusLobby.getInstance().getItemsModule().giveLobbyItems(player); + } + } else { + buildModePlayers.add(player.getUniqueId()); + player.setGameMode(GameMode.CREATIVE); + player.getInventory().clear(); + } + } + + @Override + public void onDisable() {} +} \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/modules/ItemsModule.java b/src/main/java/de/nexuslobby/modules/ItemsModule.java index 87e4d2e..5db7db6 100644 --- a/src/main/java/de/nexuslobby/modules/ItemsModule.java +++ b/src/main/java/de/nexuslobby/modules/ItemsModule.java @@ -1,12 +1,18 @@ package de.nexuslobby.modules; +import de.nexuslobby.NexusLobby; import de.nexuslobby.api.Module; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; import org.bukkit.event.Listener; import org.bukkit.event.EventHandler; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; public class ItemsModule implements Module, Listener { @@ -17,14 +23,97 @@ public class ItemsModule implements Module, Listener { @Override public void onEnable() { - Bukkit.getPluginManager().registerEvents(this, Bukkit.getPluginManager().getPlugin("NexusLobby")); + Bukkit.getPluginManager().registerEvents(this, NexusLobby.getInstance()); } @EventHandler public void onJoin(PlayerJoinEvent event) { - event.getPlayer().getInventory().addItem(new ItemStack(Material.COMPASS)); + Bukkit.getScheduler().runTaskLater(NexusLobby.getInstance(), () -> { + giveLobbyItems(event.getPlayer()); + }, 2L); + } + + @EventHandler + public void onInteract(PlayerInteractEvent event) { + Player player = event.getPlayer(); + ItemStack item = event.getItem(); + + if (item == null || item.getType() == Material.AIR) return; + if (!item.hasItemMeta() || !item.getItemMeta().hasDisplayName()) return; + + if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) { + FileConfiguration config = NexusLobby.getInstance().getConfig(); + String displayName = item.getItemMeta().getDisplayName(); + + // 1. Baumodus Logik + String buildName = colorize(config.getString("items.lobby-tools.build-toggle.displayname", "&aBaumodus")); + if (displayName.equals(buildName)) { + player.performCommand("build"); + event.setCancelled(true); + return; + } + + // 2. Gadget GUI Logik + String gadgetName = colorize(config.getString("items.lobby-tools.gadget.displayname", "&bGadgets")); + if (displayName.equals(gadgetName)) { + // Öffnet die GUI aus dem GadgetModule + NexusLobby.getInstance().getGadgetModule().openGUI(player); + event.setCancelled(true); + return; + } + + // 3. Kompass / Teleporter Logik (optional, falls du den Befehl schon hast) + String compassName = colorize(config.getString("items.lobby-tools.compass.displayname", "&eTeleporter")); + if (displayName.equals(compassName)) { + // Hier könnte z.B. player.performCommand("cp"); stehen + } + } + } + + public void giveLobbyItems(Player player) { + player.getInventory().clear(); + FileConfiguration config = NexusLobby.getInstance().getConfig(); + + // 1. Kompass (Slot 4) + if (config.getBoolean("items.lobby-tools.compass.enabled", true)) { + int slot = config.getInt("items.lobby-tools.compass.slot", 4); + String name = config.getString("items.lobby-tools.compass.displayname", "&eTeleporter"); + player.getInventory().setItem(slot, createItem(Material.COMPASS, name)); + } + + // 2. Baumodus (Slot 0) + if (player.isOp() || player.hasPermission("nexuslobby.build")) { + if (config.getBoolean("items.lobby-tools.build-toggle.enabled", true)) { + int slot = config.getInt("items.lobby-tools.build-toggle.slot", 0); + String name = config.getString("items.lobby-tools.build-toggle.displayname", "&aBaumodus"); + player.getInventory().setItem(slot, createItem(Material.REDSTONE_TORCH, name)); + } + } + + // 3. Gadgets (Slot 8) + if (config.getBoolean("items.lobby-tools.gadget.enabled", true)) { // Auf true gesetzt, damit es erscheint + int slot = config.getInt("items.lobby-tools.gadget.slot", 8); + String name = config.getString("items.lobby-tools.gadget.displayname", "&bGadgets"); + player.getInventory().setItem(slot, createItem(Material.CHEST, name)); + } + + player.updateInventory(); + } + + private ItemStack createItem(Material mat, String name) { + ItemStack item = new ItemStack(mat); + ItemMeta meta = item.getItemMeta(); + if (meta != null) { + meta.setDisplayName(colorize(name)); + item.setItemMeta(meta); + } + return item; + } + + private String colorize(String s) { + return (s == null) ? "" : s.replace("&", "§"); } @Override public void onDisable() {} -} +} \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/modules/gadgets/Balloon.java b/src/main/java/de/nexuslobby/modules/gadgets/Balloon.java new file mode 100644 index 0000000..9cd221f --- /dev/null +++ b/src/main/java/de/nexuslobby/modules/gadgets/Balloon.java @@ -0,0 +1,77 @@ +package de.nexuslobby.modules.gadgets; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.UUID; + +public class Balloon { + + private final UUID playerUUID; + private final LivingEntity balloonEntity; + private final ArmorStand headStand; + + public Balloon(Player player, Material balloonMaterial) { + this.playerUUID = player.getUniqueId(); + Location loc = player.getLocation().add(0, 2, 0); + + // Das unsichtbare Träger-Entity + this.balloonEntity = (LivingEntity) loc.getWorld().spawnEntity(loc, EntityType.PIG); + this.balloonEntity.setInvisible(true); + this.balloonEntity.setSilent(true); + this.balloonEntity.setInvulnerable(true); + this.balloonEntity.setGravity(false); + this.balloonEntity.setLeashHolder(player); + + // Der ArmorStand, der den farbigen Block trägt + this.headStand = (ArmorStand) loc.getWorld().spawnEntity(loc, EntityType.ARMOR_STAND); + this.headStand.setVisible(false); + this.headStand.setGravity(false); + this.headStand.setMarker(true); + + // Hier wird das übergebene Material gesetzt (z.B. RED_WOOL, BLUE_WOOL etc.) + this.headStand.setHelmet(new ItemStack(balloonMaterial)); + } + + public void update() { + Player player = org.bukkit.Bukkit.getPlayer(playerUUID); + + if (player == null || !player.isOnline() || balloonEntity == null || !balloonEntity.isValid()) { + remove(); + return; + } + + if (!balloonEntity.isLeashed()) { + remove(); + return; + } + + Location targetLoc = player.getLocation().clone().add(0, 2.5, 0); + Vector direction = targetLoc.toVector().subtract(balloonEntity.getLocation().toVector()); + double distance = direction.length(); + + if (distance > 5) { + balloonEntity.teleport(targetLoc); + } else if (distance > 0.1) { + balloonEntity.setVelocity(direction.multiply(0.4)); + } + + headStand.teleport(balloonEntity.getLocation().clone().subtract(0, 1.5, 0)); + } + + public void remove() { + if (balloonEntity != null) { + balloonEntity.setLeashHolder(null); + balloonEntity.remove(); + } + if (headStand != null) { + headStand.remove(); + } + } +} \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/modules/gadgets/ChickenRain.java b/src/main/java/de/nexuslobby/modules/gadgets/ChickenRain.java new file mode 100644 index 0000000..887df42 --- /dev/null +++ b/src/main/java/de/nexuslobby/modules/gadgets/ChickenRain.java @@ -0,0 +1,54 @@ +package de.nexuslobby.modules.gadgets; + +import de.nexuslobby.NexusLobby; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.Sound; +import org.bukkit.entity.Chicken; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.Random; + +public class ChickenRain { + + public static void start(Player player) { + new BukkitRunnable() { + int ticks = 0; + final Random random = new Random(); + + @Override + public void run() { + if (!player.isOnline() || ticks > 100) { // 100 Ticks = 5 Sekunden + this.cancel(); + return; + } + + // Alle 2 Ticks ein Huhn spawnen + if (ticks % 2 == 0) { + Location spawnLoc = player.getLocation().add( + (random.nextDouble() - 0.5) * 4, + 4.0, + (random.nextDouble() - 0.5) * 4 + ); + + Chicken chicken = (Chicken) spawnLoc.getWorld().spawnEntity(spawnLoc, EntityType.CHICKEN); + chicken.setBaby(); + chicken.setInvulnerable(true); + + // Nach 1.5 Sekunden "ploppt" das Huhn + Bukkit.getScheduler().runTaskLater(NexusLobby.getInstance(), () -> { + if (chicken.isValid()) { + chicken.getWorld().spawnParticle(Particle.CLOUD, chicken.getLocation(), 5, 0.2, 0.2, 0.2, 0.1); + chicken.getWorld().playSound(chicken.getLocation(), Sound.ENTITY_CHICKEN_EGG, 1.0f, 1.5f); + chicken.remove(); + } + }, 30L); + } + ticks++; + } + }.runTaskTimer(NexusLobby.getInstance(), 0L, 1L); + } +} \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/modules/gadgets/GadgetModule.java b/src/main/java/de/nexuslobby/modules/gadgets/GadgetModule.java new file mode 100644 index 0000000..4a64508 --- /dev/null +++ b/src/main/java/de/nexuslobby/modules/gadgets/GadgetModule.java @@ -0,0 +1,200 @@ +package de.nexuslobby.modules.gadgets; + +import de.nexuslobby.NexusLobby; +import de.nexuslobby.api.Module; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class GadgetModule implements Module, Listener { + + private final Map activeBalloons = new HashMap<>(); + private final Map activeEffects = new HashMap<>(); + + // Titel für die verschiedenen Inventare zur Identifikation + private final String MAIN_TITLE = "§b§lGadgets §8- §7Menü"; + private final String BALLOON_TITLE = "§b§lGadgets §8- §eBallons"; + private final String PARTICLE_TITLE = "§b§lGadgets §8- §dPartikel"; + private final String FUN_TITLE = "§b§lGadgets §8- §6Lustiges"; + + @Override + public String getName() { return "Gadgets"; } + + @Override + public void onEnable() { + Bukkit.getPluginManager().registerEvents(this, NexusLobby.getInstance()); + Bukkit.getScheduler().runTaskTimer(NexusLobby.getInstance(), () -> { + activeBalloons.values().forEach(Balloon::update); + activeEffects.forEach((uuid, effect) -> { + Player p = Bukkit.getPlayer(uuid); + if (p != null && p.isOnline()) effect.update(p); + }); + }, 1L, 1L); + } + + // --- GUI ÖFFNER --- + + public void openGUI(Player player) { + Inventory gui = Bukkit.createInventory(null, 27, MAIN_TITLE); + fillEdges(gui); + + gui.setItem(10, createItem(Material.LEAD, "§e§lBallons", "§7Wähle einen fliegenden Begleiter")); + gui.setItem(13, createItem(Material.FIREWORK_ROCKET, "§6§lLustiges", "§7Witzige Effekte für zwischendurch")); + gui.setItem(16, createItem(Material.NETHER_STAR, "§d§lPartikel", "§7Wähle magische Effekte")); + + gui.setItem(22, createItem(Material.BARRIER, "§c§lStopp", "§7Alle Gadgets entfernen")); + + player.openInventory(gui); + } + + private void openBalloonGUI(Player player) { + Inventory gui = Bukkit.createInventory(null, 36, BALLOON_TITLE); + fillEdges(gui); + + Material[] wools = {Material.WHITE_WOOL, Material.ORANGE_WOOL, Material.MAGENTA_WOOL, Material.LIGHT_BLUE_WOOL, + Material.YELLOW_WOOL, Material.LIME_WOOL, Material.PINK_WOOL, Material.GRAY_WOOL, + Material.CYAN_WOOL, Material.PURPLE_WOOL, Material.BLUE_WOOL, Material.BROWN_WOOL, + Material.GREEN_WOOL, Material.RED_WOOL}; + + int slot = 10; + for (Material m : wools) { + if (slot == 17) slot = 19; + gui.setItem(slot++, createItem(m, "§fBallon: " + m.name().replace("_WOOL", ""), "§7Klicke zum Ausrüsten")); + } + gui.setItem(31, createItem(Material.ARROW, "§7Zurück", "§8Zum Hauptmenü")); + player.openInventory(gui); + } + + private void openParticleGUI(Player player) { + Inventory gui = Bukkit.createInventory(null, 27, PARTICLE_TITLE); + fillEdges(gui); + + gui.setItem(11, createItem(Material.POPPY, "§cHerzchen-Aura", "§7Verbreite Liebe")); + gui.setItem(13, createItem(Material.BLAZE_POWDER, "§6Flammen-Ring", "§7Werde feurig")); + gui.setItem(15, createItem(Material.WATER_BUCKET, "§bRegenwolke", "§7Lass es regnen")); + + gui.setItem(22, createItem(Material.ARROW, "§7Zurück", "§8Zum Hauptmenü")); + player.openInventory(gui); + } + + private void openFunGUI(Player player) { + Inventory gui = Bukkit.createInventory(null, 27, FUN_TITLE); + fillEdges(gui); + + gui.setItem(13, createItem(Material.EGG, "§f§lChicken-Rain", "§7Lass es Küken regnen!")); + + gui.setItem(22, createItem(Material.ARROW, "§7Zurück", "§8Zum Hauptmenü")); + player.openInventory(gui); + } + + // --- EVENT HANDLER --- + + @EventHandler + public void onInventoryClick(InventoryClickEvent event) { + String title = event.getView().getTitle(); + if (!title.equals(MAIN_TITLE) && !title.equals(BALLOON_TITLE) && !title.equals(PARTICLE_TITLE) && !title.equals(FUN_TITLE)) return; + + event.setCancelled(true); + Player player = (Player) event.getWhoClicked(); + ItemStack item = event.getCurrentItem(); + if (item == null || item.getType() == Material.AIR) return; + + // Zurück-Button Logik + if (item.getType() == Material.ARROW) { + openGUI(player); + return; + } + + // HAUPTMENÜ LOGIK + if (title.equals(MAIN_TITLE)) { + if (item.getType() == Material.LEAD) openBalloonGUI(player); + else if (item.getType() == Material.NETHER_STAR) openParticleGUI(player); + else if (item.getType() == Material.FIREWORK_ROCKET) openFunGUI(player); + else if (item.getType() == Material.BARRIER) { + removeGadgets(player); + player.closeInventory(); + } + } + + // BALLON MENÜ LOGIK + else if (title.equals(BALLOON_TITLE)) { + if (item.getType().toString().endsWith("_WOOL")) { + if (activeBalloons.containsKey(player.getUniqueId())) activeBalloons.get(player.getUniqueId()).remove(); + activeBalloons.put(player.getUniqueId(), new Balloon(player, item.getType())); + player.sendMessage("§8[§6Nexus§8] §aBallon ausgerüstet!"); + player.closeInventory(); + } + } + + // PARTIKEL MENÜ LOGIK + else if (title.equals(PARTICLE_TITLE)) { + if (item.getType() == Material.POPPY) activeEffects.put(player.getUniqueId(), new ParticleEffect("hearts")); + else if (item.getType() == Material.BLAZE_POWDER) activeEffects.put(player.getUniqueId(), new ParticleEffect("flames")); + else if (item.getType() == Material.WATER_BUCKET) activeEffects.put(player.getUniqueId(), new ParticleEffect("cloud")); + + if (item.getType() != Material.GRAY_STAINED_GLASS_PANE) { + player.sendMessage("§8[§6Nexus§8] §aEffekt aktiviert!"); + player.closeInventory(); + } + } + + // FUN MENÜ LOGIK + else if (title.equals(FUN_TITLE)) { + if (item.getType() == Material.EGG) { + ChickenRain.start(player); + player.sendMessage("§8[§6Nexus§8] §fEs regnet jetzt Hühner!"); + player.closeInventory(); + } + } + } + + private void removeGadgets(Player player) { + if (activeBalloons.containsKey(player.getUniqueId())) { + activeBalloons.get(player.getUniqueId()).remove(); + activeBalloons.remove(player.getUniqueId()); + } + activeEffects.remove(player.getUniqueId()); + player.sendMessage("§8[§6Nexus§8] §cAlle Gadgets wurden entfernt."); + } + + private void fillEdges(Inventory inv) { + ItemStack glass = createItem(Material.GRAY_STAINED_GLASS_PANE, " ", null); + for (int i = 0; i < inv.getSize(); i++) { + if (i < 9 || i >= inv.getSize() - 9 || i % 9 == 0 || (i + 1) % 9 == 0) { + inv.setItem(i, glass); + } + } + } + + private ItemStack createItem(Material mat, String name, String lore) { + ItemStack item = new ItemStack(mat); + ItemMeta meta = item.getItemMeta(); + if (meta != null) { + meta.setDisplayName(name); + if (lore != null) { + java.util.List l = new java.util.ArrayList<>(); + l.add(lore); + meta.setLore(l); + } + item.setItemMeta(meta); + } + return item; + } + + @Override + public void onDisable() { + activeBalloons.values().forEach(Balloon::remove); + activeBalloons.clear(); + activeEffects.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/modules/gadgets/ParticleEffect.java b/src/main/java/de/nexuslobby/modules/gadgets/ParticleEffect.java new file mode 100644 index 0000000..8212fb1 --- /dev/null +++ b/src/main/java/de/nexuslobby/modules/gadgets/ParticleEffect.java @@ -0,0 +1,31 @@ +package de.nexuslobby.modules.gadgets; + +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.entity.Player; + +public class ParticleEffect { + private final String type; + private double angle = 0; + + public ParticleEffect(String type) { this.type = type; } + + public void update(Player player) { + Location loc = player.getLocation(); + switch (type.toLowerCase()) { + case "hearts": + player.getWorld().spawnParticle(Particle.HEART, loc.clone().add(0, 2.2, 0), 1, 0.3, 0.3, 0.3, 0); + break; + case "flames": + double x = 0.6 * Math.cos(angle); + double z = 0.6 * Math.sin(angle); + player.getWorld().spawnParticle(Particle.FLAME, loc.clone().add(x, 0.1, z), 1, 0, 0, 0, 0); + angle += 0.2; + break; + case "cloud": + player.getWorld().spawnParticle(Particle.CLOUD, loc.clone().add(0, 2.5, 0), 2, 0.2, 0.05, 0.2, 0); + player.getWorld().spawnParticle(Particle.FALLING_WATER, loc.clone().add(0, 2.4, 0), 1, 0.1, 0, 0.1, 0); + break; + } + } +} \ No newline at end of file diff --git a/src/main/java/de/nexuslobby/modules/tablist/TablistModule.java b/src/main/java/de/nexuslobby/modules/tablist/TablistModule.java index 6e89e91..367590b 100644 --- a/src/main/java/de/nexuslobby/modules/tablist/TablistModule.java +++ b/src/main/java/de/nexuslobby/modules/tablist/TablistModule.java @@ -1,210 +1,311 @@ package de.nexuslobby.modules.tablist; + + import de.nexuslobby.NexusLobby; + import de.nexuslobby.api.Module; + import net.luckperms.api.LuckPerms; + import net.luckperms.api.LuckPermsProvider; -import net.luckperms.api.model.group.Group; + import net.luckperms.api.model.user.User; + import me.clip.placeholderapi.PlaceholderAPI; + import org.bukkit.Bukkit; + import org.bukkit.configuration.file.FileConfiguration; + import org.bukkit.entity.Player; + import org.bukkit.scheduler.BukkitTask; + import org.bukkit.scoreboard.Scoreboard; + import org.bukkit.scoreboard.Team; -import java.util.HashMap; + + import java.util.List; -import java.util.Map; + + public class TablistModule implements Module { + + private BukkitTask refreshTask; + private int currentHeaderIndex = 0; + private int currentFooterIndex = 0; + private LuckPerms luckPerms; + private boolean placeholderAPIEnabled; - // Pixel-Breiten Tabelle für die Standard Minecraft Schriftart - private static final Map CHAR_WIDTHS = new HashMap<>(); - private static final int TARGET_PIXEL_WIDTH = 90; // Ziel-Breite für den Namensteil vor dem Ping - static { - String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - for (char c : chars.toCharArray()) CHAR_WIDTHS.put(c, 6); - CHAR_WIDTHS.put('i', 2); CHAR_WIDTHS.put('l', 3); CHAR_WIDTHS.put('t', 4); - CHAR_WIDTHS.put('I', 4); CHAR_WIDTHS.put('f', 5); CHAR_WIDTHS.put('k', 5); - CHAR_WIDTHS.put('.', 2); CHAR_WIDTHS.put(',', 2); CHAR_WIDTHS.put('!', 2); - CHAR_WIDTHS.put('(', 5); CHAR_WIDTHS.put(')', 5); CHAR_WIDTHS.put('[', 4); - CHAR_WIDTHS.put(']', 4); CHAR_WIDTHS.put('{', 5); CHAR_WIDTHS.put('}', 5); - CHAR_WIDTHS.put('|', 2); CHAR_WIDTHS.put('*', 5); CHAR_WIDTHS.put(' ', 4); - CHAR_WIDTHS.put('_', 6); - } @Override + public String getName() { return "Tablist"; } + + @Override + public void onEnable() { + FileConfiguration vConfig = NexusLobby.getInstance().getVisualsConfig(); + if (!vConfig.getBoolean("tablist.enabled", true)) return; + + if (Bukkit.getPluginManager().getPlugin("LuckPerms") != null) luckPerms = LuckPermsProvider.get(); + placeholderAPIEnabled = Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null; + + + // Nutzt jetzt das Intervall aus der visuals.yml + long interval = vConfig.getLong("tablist.interval-ticks", 40L); + refreshTask = Bukkit.getScheduler().runTaskTimer(NexusLobby.getInstance(), this::refreshAll, 10L, interval); + } + + private void refreshAll() { + updateAnimationIndices(); + for (Player viewer : Bukkit.getOnlinePlayers()) { + viewer.setPlayerListHeader(getHeader(viewer)); + viewer.setPlayerListFooter(getFooter(viewer)); - updateTeamsAndFormatting(viewer); + + updateTeams(viewer); + } + } - private void updateTeamsAndFormatting(Player viewer) { + + + private void updateTeams(Player viewer) { + FileConfiguration vConfig = NexusLobby.getInstance().getVisualsConfig(); - boolean showPrefix = vConfig.getBoolean("tablist.show-prefix-in-playerlist", true); + + if (!vConfig.getBoolean("tablist.show-prefix-in-playerlist", true)) return; + + Scoreboard sb = viewer.getScoreboard(); + if (sb == Bukkit.getScoreboardManager().getMainScoreboard()) return; + + for (Player target : Bukkit.getOnlinePlayers()) { - String sortPriority = getSortPriority(target); - String teamName = sortPriority + target.getName(); - + + String teamName = "tab_" + target.getName(); + if (teamName.length() > 16) teamName = teamName.substring(0, 16); + + Team team = sb.getTeam(teamName); + if (team == null) team = sb.registerNewTeam(teamName); - String prefix = showPrefix ? getPlayerPrefix(target) : "§7"; + + + String prefix = getPlayerPrefix(target); + + String suffix = getPlayerSuffix(target); + + + if (!team.getPrefix().equals(prefix)) team.setPrefix(prefix); - // Hier wird der Pixel-Ausgleich berechnet, damit der Trenner | immer an der gleichen Stelle ist - String pingSuffix = getAlignedPingSuffix(target.getName(), target.getPing()); - if (!team.getSuffix().equals(pingSuffix)) team.setSuffix(pingSuffix); - + if (!team.getSuffix().equals(suffix)) team.setSuffix(suffix); + + + if (!team.hasEntry(target.getName())) { + team.addEntry(target.getName()); - } - - // Setzt den Listnamen zurück, damit Team-Prefix/Suffix greifen - if (target.getPlayerListName() != null) { - target.setPlayerListName(null); - } - } - } - private String getAlignedPingSuffix(String name, int ping) { - int currentWidth = 0; - for (char c : name.toCharArray()) { - currentWidth += CHAR_WIDTHS.getOrDefault(c, 6); + } + } - int diff = TARGET_PIXEL_WIDTH - currentWidth; - StringBuilder spacer = new StringBuilder(" "); - - // Ausgleich mit fetten (5px) und normalen (4px) Leerzeichen für maximale Präzision - while (diff > 0) { - if (diff >= 5) { - spacer.append("§l "); - diff -= 5; - } else { - spacer.append(" "); - diff -= 4; - } - } - - String pingColor = (ping < 50) ? "§a" : (ping < 100 ? "§e" : "§c"); - // §r bricht das fettgedruckte Leerzeichen ab, damit der Ping normal aussieht - return "§r" + spacer.toString() + "§8| " + pingColor + ping + "ms"; } - private String getSortPriority(Player player) { - if (luckPerms == null) return "z_"; - User user = luckPerms.getUserManager().getUser(player.getUniqueId()); - if (user == null) return "z_"; - Group group = luckPerms.getGroupManager().getGroup(user.getPrimaryGroup()); - if (group == null) return "z_"; - int weight = group.getWeight().orElse(0); - int invertedWeight = 1000 - weight; - return String.format("%03d", invertedWeight) + "_"; - } + private String getPlayerPrefix(Player player) { + String prefix = ""; + if (luckPerms != null) { + User user = luckPerms.getUserManager().getUser(player.getUniqueId()); + if (user != null && user.getCachedData().getMetaData().getPrefix() != null) { + prefix = user.getCachedData().getMetaData().getPrefix(); + } + } + if (prefix.isEmpty() && placeholderAPIEnabled) { + prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%"); + } + return colorize(prefix.isEmpty() ? "&7" : prefix + " "); + } + + + private String getPlayerSuffix(Player player) { + + // Hier könnte man später auch Suffixe aus der Config laden + + return colorize(" &8[&a" + player.getPing() + "ms&8]"); + + } + + + private void updateAnimationIndices() { + FileConfiguration vConfig = NexusLobby.getInstance().getVisualsConfig(); + List h = vConfig.getStringList("tablist.header-animations"); + List f = vConfig.getStringList("tablist.footer-animations"); + if (!h.isEmpty()) currentHeaderIndex = (currentHeaderIndex + 1) % h.size(); + if (!f.isEmpty()) currentFooterIndex = (currentFooterIndex + 1) % f.size(); + } + + private String getHeader(Player p) { + FileConfiguration vConfig = NexusLobby.getInstance().getVisualsConfig(); + List list = vConfig.getStringList("tablist.header-animations"); + if (list.isEmpty()) return "§6NexusLobby"; + return replacePlaceholders(list.get(currentHeaderIndex), p); + } + + private String getFooter(Player p) { + FileConfiguration vConfig = NexusLobby.getInstance().getVisualsConfig(); + List list = vConfig.getStringList("tablist.footer-animations"); + if (list.isEmpty()) return "§7Willkommen"; + return replacePlaceholders(list.get(currentFooterIndex), p); + } + + private String replacePlaceholders(String text, Player p) { + FileConfiguration vConfig = NexusLobby.getInstance().getVisualsConfig(); + + + text = text.replace("{server}", vConfig.getString("tablist.server-name", "NexusLobby")); + text = text.replace("{player}", p.getName()); + text = text.replace("{online}", String.valueOf(Bukkit.getOnlinePlayers().size())); + text = text.replace("{staff}", String.valueOf(getOnlineStaffCount())); + text = text.replace("{separator}", vConfig.getString("tablist.separator-line", "")); + + + text = text.replace("{website}", vConfig.getBoolean("tablist.show-website") ? vConfig.getString("tablist.website", "") : ""); + text = text.replace("{teamspeak}", vConfig.getBoolean("tablist.show-teamspeak") ? vConfig.getString("tablist.teamspeak-address", "") : ""); + text = text.replace("{discord}", vConfig.getBoolean("tablist.show-discord") ? vConfig.getString("tablist.discord-address", "") : ""); + + if (placeholderAPIEnabled) { + text = PlaceholderAPI.setPlaceholders(p, text); + } + + + return colorize(text); + } + + private int getOnlineStaffCount() { + FileConfiguration vConfig = NexusLobby.getInstance().getVisualsConfig(); + String permission = vConfig.getString("tablist.staff-permission", "nexuslobby.staff"); + int count = 0; + for (Player p : Bukkit.getOnlinePlayers()) { + if (p.hasPermission(permission)) count++; + } + return count; + } + + private String colorize(String s) { + return s == null ? "" : s.replace("&", "§"); + } - @Override - public void onDisable() { - if (refreshTask != null) refreshTask.cancel(); + + + @Override + + public void onDisable() { + + if (refreshTask != null) refreshTask.cancel(); + } + } \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index bbfd0ac..d4dc66b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -36,11 +36,11 @@ items: build-toggle: enabled: true displayname: "&aBaumodus" - slot: 1 + slot: 0 gadget: - enabled: true + enabled: false displayname: "&bGadgets" - slot: 2 + slot: 8 # --- Portal Einstellungen --- portals: diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index d8b6532..efb5f3a 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.0.1" +version: "1.0.2" api-version: "1.21" author: M_Viper description: Modular Lobby Plugin