Update from Git Manager GUI

This commit is contained in:
2026-01-23 10:43:53 +01:00
parent 9fd0690ba8
commit 5f2c05d85e
13 changed files with 984 additions and 114 deletions

View File

@@ -15,6 +15,7 @@ import de.nexuslobby.modules.portal.PortalCommand;
import de.nexuslobby.modules.servers.ServerSwitcherListener; import de.nexuslobby.modules.servers.ServerSwitcherListener;
import de.nexuslobby.modules.armorstandtools.*; import de.nexuslobby.modules.armorstandtools.*;
import de.nexuslobby.modules.gadgets.GadgetModule; import de.nexuslobby.modules.gadgets.GadgetModule;
import de.nexuslobby.modules.hologram.HologramModule;
import de.nexuslobby.utils.VoidProtection; import de.nexuslobby.utils.VoidProtection;
import de.nexuslobby.utils.DoubleJump; import de.nexuslobby.utils.DoubleJump;
import de.nexuslobby.utils.PlayerHider; import de.nexuslobby.utils.PlayerHider;
@@ -50,6 +51,8 @@ public class NexusLobby extends JavaPlugin implements Listener {
private LobbySettingsModule lobbySettingsModule; private LobbySettingsModule lobbySettingsModule;
private ItemsModule itemsModule; private ItemsModule itemsModule;
private GadgetModule gadgetModule; private GadgetModule gadgetModule;
private HologramModule hologramModule;
private DynamicArmorStandModule dynamicArmorStandModule; // Neu hinzugefügt
private File visualsFile; private File visualsFile;
private FileConfiguration visualsConfig; private FileConfiguration visualsConfig;
@@ -65,7 +68,6 @@ public class NexusLobby extends JavaPlugin implements Listener {
public void onEnable() { public void onEnable() {
instance = this; instance = this;
// Erst Config initialisieren
initCustomConfigs(); initCustomConfigs();
getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
@@ -137,6 +139,13 @@ public class NexusLobby extends JavaPlugin implements Listener {
this.gadgetModule = new GadgetModule(); this.gadgetModule = new GadgetModule();
moduleManager.registerModule(this.gadgetModule); moduleManager.registerModule(this.gadgetModule);
this.hologramModule = new HologramModule();
moduleManager.registerModule(this.hologramModule);
// Dynamic ArmorStand Module registrieren
this.dynamicArmorStandModule = new DynamicArmorStandModule();
moduleManager.registerModule(this.dynamicArmorStandModule);
moduleManager.registerModule(new SecurityModule()); moduleManager.registerModule(new SecurityModule());
moduleManager.registerModule(new BossBarModule()); moduleManager.registerModule(new BossBarModule());
moduleManager.registerModule(new ActionBarModule()); moduleManager.registerModule(new ActionBarModule());
@@ -200,14 +209,9 @@ public class NexusLobby extends JavaPlugin implements Listener {
File configFile = new File(getDataFolder(), "config.yml"); File configFile = new File(getDataFolder(), "config.yml");
if (!configFile.exists()) { if (!configFile.exists()) {
// Nur speichern wenn sie fehlt
saveResource("config.yml", false); saveResource("config.yml", false);
} else {
// WICHTIG: ConfigUpdater für config.yml deaktiviert, da er Sektionen nicht korrekt erkennt!
// ConfigUpdater.updateConfig("config.yml");
} }
// Einfaches Laden reicht völlig aus
reloadConfig(); reloadConfig();
File settingsFile = new File(getDataFolder(), "settings.yml"); File settingsFile = new File(getDataFolder(), "settings.yml");
@@ -247,7 +251,7 @@ public class NexusLobby extends JavaPlugin implements Listener {
} }
private void registerCommands() { private void registerCommands() {
LobbyTabCompleter tabCompleter = new LobbyTabCompleter(portalManager); LobbyTabCompleter tabCompleter = new LobbyTabCompleter(portalManager, hologramModule);
PluginCommand portalCmd = this.getCommand("portal"); PluginCommand portalCmd = this.getCommand("portal");
if (portalCmd != null) { if (portalCmd != null) {
@@ -255,6 +259,12 @@ public class NexusLobby extends JavaPlugin implements Listener {
portalCmd.setTabCompleter(tabCompleter); portalCmd.setTabCompleter(tabCompleter);
} }
PluginCommand holoCmd = this.getCommand("holo");
if (holoCmd != null) {
holoCmd.setExecutor(new HoloCommand(hologramModule));
holoCmd.setTabCompleter(tabCompleter);
}
PluginCommand maintenanceCmd = this.getCommand("maintenance"); PluginCommand maintenanceCmd = this.getCommand("maintenance");
if (maintenanceCmd != null) { if (maintenanceCmd != null) {
maintenanceCmd.setExecutor(new MaintenanceCommand()); maintenanceCmd.setExecutor(new MaintenanceCommand());
@@ -303,4 +313,6 @@ public class NexusLobby extends JavaPlugin implements Listener {
public LobbySettingsModule getLobbySettingsModule() { return lobbySettingsModule; } public LobbySettingsModule getLobbySettingsModule() { return lobbySettingsModule; }
public ItemsModule getItemsModule() { return itemsModule; } public ItemsModule getItemsModule() { return itemsModule; }
public GadgetModule getGadgetModule() { return gadgetModule; } public GadgetModule getGadgetModule() { return gadgetModule; }
public HologramModule getHologramModule() { return hologramModule; }
public DynamicArmorStandModule getDynamicArmorStandModule() { return dynamicArmorStandModule; } // Getter hinzugefügt
} }

View File

@@ -1,6 +1,7 @@
package de.nexuslobby.commands; package de.nexuslobby.commands;
import de.nexuslobby.modules.portal.PortalManager; import de.nexuslobby.modules.portal.PortalManager;
import de.nexuslobby.modules.hologram.HologramModule;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter; import org.bukkit.command.TabCompleter;
@@ -13,9 +14,11 @@ import java.util.stream.Collectors;
public class LobbyTabCompleter implements TabCompleter { public class LobbyTabCompleter implements TabCompleter {
private final PortalManager portalManager; private final PortalManager portalManager;
private final HologramModule hologramModule;
public LobbyTabCompleter(PortalManager portalManager) { public LobbyTabCompleter(PortalManager portalManager, HologramModule hologramModule) {
this.portalManager = portalManager; this.portalManager = portalManager;
this.hologramModule = hologramModule;
} }
@Override @Override
@@ -37,6 +40,16 @@ public class LobbyTabCompleter implements TabCompleter {
} }
} }
// --- Hologram Befehl ---
else if (command.getName().equalsIgnoreCase("holo")) {
if (args.length == 1) {
suggestions.add("create");
suggestions.add("delete");
} else if (args.length == 2 && args[0].equalsIgnoreCase("delete")) {
suggestions.addAll(hologramModule.getHologramIds());
}
}
// --- Wartungsmodus --- // --- Wartungsmodus ---
else if (command.getName().equalsIgnoreCase("maintenance")) { else if (command.getName().equalsIgnoreCase("maintenance")) {
if (args.length == 1) { if (args.length == 1) {
@@ -60,23 +73,22 @@ public class LobbyTabCompleter implements TabCompleter {
else if (command.getName().equalsIgnoreCase("nexustools") || command.getName().equalsIgnoreCase("astools") || command.getName().equalsIgnoreCase("nt")) { else if (command.getName().equalsIgnoreCase("nexustools") || command.getName().equalsIgnoreCase("astools") || command.getName().equalsIgnoreCase("nt")) {
if (args.length == 1) { if (args.length == 1) {
suggestions.add("reload"); suggestions.add("reload");
suggestions.add("dynamic"); // Neu: Vorschlag für den Dynamic-Modus
} }
} }
// --- NexusCmd (ehemals ascmd) --- // --- NexusCmd (ehemals ascmd) ---
else if (command.getName().equalsIgnoreCase("nexuscmd") || command.getName().equalsIgnoreCase("ascmd") || command.getName().equalsIgnoreCase("ncmd")) { else if (command.getName().equalsIgnoreCase("nexuscmd") || command.getName().equalsIgnoreCase("ascmd") || command.getName().equalsIgnoreCase("ncmd")) {
if (args.length == 1) { if (args.length == 1) {
suggestions.add("name"); // NEU suggestions.add("name");
suggestions.add("list"); suggestions.add("list");
suggestions.add("add"); suggestions.add("add");
suggestions.add("remove"); suggestions.add("remove");
} }
// Vorschläge für: /nexuscmd name <Text>
else if (args.length == 2 && args[0].equalsIgnoreCase("name")) { else if (args.length == 2 && args[0].equalsIgnoreCase("name")) {
suggestions.add("none"); suggestions.add("none");
suggestions.add("<Text>"); suggestions.add("<Text>");
} }
// Vorschläge für: /nexuscmd add <delay> <cooldown> <type>
else if (args.length == 2 && args[0].equalsIgnoreCase("add")) { else if (args.length == 2 && args[0].equalsIgnoreCase("add")) {
suggestions.add("0"); suggestions.add("0");
} }
@@ -93,7 +105,6 @@ public class LobbyTabCompleter implements TabCompleter {
} }
} }
// Filtert die Liste basierend auf dem, was der Spieler bereits getippt hat
return suggestions.stream() return suggestions.stream()
.filter(s -> s.toLowerCase().startsWith(args[args.length - 1].toLowerCase())) .filter(s -> s.toLowerCase().startsWith(args[args.length - 1].toLowerCase()))
.collect(Collectors.toList()); .collect(Collectors.toList());

View File

@@ -1,6 +1,8 @@
package de.nexuslobby.modules.armorstandtools; package de.nexuslobby.modules.armorstandtools;
import de.nexuslobby.NexusLobby;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Particle;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@@ -11,85 +13,143 @@ import org.jetbrains.annotations.NotNull;
import java.util.Set; import java.util.Set;
/**
* ArmorStandCommand - Vollständige Steuerung für ArmorStands.
* Inklusive Dynamic-Modus Erkennung und visueller Rückmeldung.
*/
public class ArmorStandCommand implements CommandExecutor { public class ArmorStandCommand implements CommandExecutor {
@Override @Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player p)) return true; if (!(sender instanceof Player p)) {
sender.sendMessage("Nur Spieler können diesen Befehl ausführen.");
if (!p.hasPermission("nexuslobby.armorstand.use")) {
p.sendMessage(Config.prefix() + ChatColor.RED + Config.generalNoPerm);
return true; return true;
} }
// Suche ArmorStand im Umkreis von 5 Blöcken // Fester Prefix für maximale Build-Sicherheit
ArmorStand target = getNearbyArmorStand(p); String prefix = "§8[§6Nexus§8] ";
// Fall 1: Nur /astools -> GUI öffnen if (!p.hasPermission("nexuslobby.armorstand.use")) {
p.sendMessage(prefix + ChatColor.RED + "Dazu hast du keine Rechte!");
return true;
}
// 1. Suche nach dem ArmorStand (Präzise & Umkreis)
ArmorStand target = getBestTargetArmorStand(p);
// Fall: Nur /astools oder /nt (Ohne Argumente)
if (args.length == 0) { if (args.length == 0) {
if (target != null) { if (target != null) {
AST.selectedArmorStand.put(p.getUniqueId(), target); AST.selectedArmorStand.put(p.getUniqueId(), target);
new ArmorStandGUI(target, p); new ArmorStandGUI(target, p);
p.sendMessage(prefix + "§aEditor für ArmorStand geöffnet.");
} else { } else {
p.sendMessage(Config.prefix() + ChatColor.RED + "Kein ArmorStand in der Nähe gefunden!"); p.sendMessage(prefix + ChatColor.RED + "Kein ArmorStand in der Nähe gefunden!");
} }
return true; return true;
} }
// Fall 2: Unterbefehle (add, remove, list)
String sub = args[0].toLowerCase(); String sub = args[0].toLowerCase();
// Globaler Reload
if (sub.equals("reload")) {
NexusLobby.getInstance().reloadPlugin();
p.sendMessage(prefix + "§aKonfiguration und Module wurden neu geladen.");
return true;
}
// Für alle anderen Aktionen ist ein ArmorStand zwingend erforderlich
if (target == null) { if (target == null) {
p.sendMessage(Config.prefix() + ChatColor.RED + "Du musst nah an einem ArmorStand stehen!"); p.sendMessage(prefix + ChatColor.RED + "Du musst einen ArmorStand anschauen oder direkt davor stehen!");
return true; return true;
} }
switch (sub) { switch (sub) {
case "addplayer": // /astools addplayer <command> case "dynamic":
if (args.length < 2) return sendHelp(p); if (!p.hasPermission("nexuslobby.armorstand.dynamic")) {
p.sendMessage(prefix + ChatColor.RED + "Keine Rechte für Dynamic-NPCs!");
return true;
}
if (NexusLobby.getInstance().getDynamicArmorStandModule() != null) {
// Toggle Logik
if (target.getScoreboardTags().contains("as_dynamic")) {
target.removeScoreboardTag("as_dynamic");
p.sendMessage(prefix + "§c§l[-] §7Dynamic-Modus §cdeaktiviert§7.");
p.spawnParticle(Particle.SMOKE, target.getLocation().add(0, 1, 0), 15, 0.3, 0.3, 0.3, 0.05);
} else {
target.addScoreboardTag("as_dynamic");
p.sendMessage(prefix + "§a§l[+] §7Dynamic-Modus §aaktiviert§7 (Wetter/Zeit).");
// Visueller Erfolgseffekt (Grüne Sternchen)
p.spawnParticle(Particle.HAPPY_VILLAGER, target.getLocation().add(0, 1, 0), 25, 0.5, 0.5, 0.5, 0.1);
}
// Internes Update sofort triggern
NexusLobby.getInstance().getDynamicArmorStandModule().toggleDynamicStatus(target);
} else {
p.sendMessage(prefix + "§cFehler: Dynamic-Modul ist nicht aktiv!");
}
break;
case "addplayer":
if (args.length < 2) return sendHelp(p, prefix);
String pCmd = buildString(args, 1); String pCmd = buildString(args, 1);
target.addScoreboardTag("ascmd:player:" + pCmd); target.addScoreboardTag("ascmd:player:" + pCmd);
p.sendMessage(Config.prefix() + "§aBefehl (Player) hinzugefügt: §e" + pCmd); p.sendMessage(prefix + "§aBefehl (Player) gespeichert: §e/" + pCmd);
break; break;
case "addconsole": // /astools addconsole <command> case "addconsole":
if (args.length < 2) return sendHelp(p); if (args.length < 2) return sendHelp(p, prefix);
String cCmd = buildString(args, 1); String cCmd = buildString(args, 1);
target.addScoreboardTag("ascmd:console:" + cCmd); target.addScoreboardTag("ascmd:console:" + cCmd);
p.sendMessage(Config.prefix() + "§aBefehl (Konsole) hinzugefügt: §e" + cCmd); p.sendMessage(prefix + "§aBefehl (Konsole) gespeichert: §e" + cCmd);
break; break;
case "addbungee": // /astools addbungee <server> case "remove":
if (args.length < 2) return sendHelp(p); target.getScoreboardTags().removeIf(tag -> tag.startsWith("ascmd:"));
String server = args[1]; p.sendMessage(prefix + "§cAlle Befehls-Tags wurden entfernt.");
target.addScoreboardTag("ascmd:bungee:" + server);
p.sendMessage(Config.prefix() + "§aBefehl (Bungee) hinzugefügt: §eConnect zu " + server);
break;
case "remove": // /astools remove (Löscht alle ascmd Tags)
Set<String> tags = target.getScoreboardTags();
tags.removeIf(tag -> tag.startsWith("ascmd:"));
p.sendMessage(Config.prefix() + "§cAlle Befehle von diesem ArmorStand entfernt.");
break;
case "reload":
Config.load();
p.sendMessage(Config.prefix() + "§aKonfiguration neu geladen.");
break; break;
default: default:
sendHelp(p); sendHelp(p, prefix);
break; break;
} }
return true; return true;
} }
private ArmorStand getNearbyArmorStand(Player p) { /**
for (Entity e : p.getNearbyEntities(5, 5, 5)) { * Sucht den am besten passenden ArmorStand.
if (e instanceof ArmorStand as) return as; * Priorität 1: Der ArmorStand, den der Spieler direkt ansieht.
* Priorität 2: Der absolut nächste ArmorStand im Umkreis.
*/
private ArmorStand getBestTargetArmorStand(Player p) {
ArmorStand best = null;
double bestDot = 0.95; // Schwellenwert für das "Anschauen"
for (Entity e : p.getNearbyEntities(8, 8, 8)) {
if (e instanceof ArmorStand as) {
// Berechne, ob der Spieler in Richtung des ArmorStands schaut
double dot = p.getLocation().getDirection().dot(
as.getLocation().toVector().subtract(p.getLocation().toVector()).normalize()
);
if (dot > bestDot) {
bestDot = dot;
best = as;
}
}
} }
return null;
// Falls nichts aktiv angeschaut wird, nimm einfach den nächsten im 4-Block-Radius
if (best == null) {
for (Entity e : p.getNearbyEntities(4, 4, 4)) {
if (e instanceof ArmorStand as) {
return as;
}
}
}
return best;
} }
private String buildString(String[] args, int start) { private String buildString(String[] args, int start) {
@@ -100,14 +160,16 @@ public class ArmorStandCommand implements CommandExecutor {
return sb.toString(); return sb.toString();
} }
private boolean sendHelp(Player p) { private boolean sendHelp(Player p, String prefix) {
p.sendMessage("§6§lArmorStandTools Hilfe:"); p.sendMessage(" ");
p.sendMessage("§e/astools §7- Öffnet Editor"); p.sendMessage("§8§m-----------§r " + prefix + "§8§m-----------");
p.sendMessage("§e/astools addplayer <cmd> §7- Befehl als Spieler ausführen"); p.sendMessage("§e/astools §7- Editor öffnen");
p.sendMessage("§e/astools addconsole <cmd> §7- Befehl als Konsole ausführen"); p.sendMessage("§b/astools dynamic §7- Wetter/Zeit Logik umschalten");
p.sendMessage("§e/astools addbungee <server> §7- Serverwechsel"); p.sendMessage("§e/astools addplayer <cmd> §7- Befehl als Spieler");
p.sendMessage("§e/astools remove §7- Entfernt alle Befehle"); p.sendMessage("§e/astools addconsole <cmd> §7- Befehl via Konsole");
p.sendMessage("§e/astools reload §7- Lädt Config neu"); p.sendMessage("§e/astools remove §7- Befehle löschen");
p.sendMessage("§e/astools reload §7- Konfig neu laden");
p.sendMessage("§8§m---------------------------------------");
return true; return true;
} }
} }

View File

@@ -0,0 +1,119 @@
package de.nexuslobby.modules.armorstandtools;
import de.nexuslobby.NexusLobby;
import de.nexuslobby.api.Module;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataType;
import java.time.LocalTime;
/**
* DynamicArmorStandModule
* Reagiert auf Uhrzeit und Wetter.
* Nutzt PersistentData, damit die Einstellung auch nach einem Server-Neustart bleibt.
*/
public class DynamicArmorStandModule implements Module {
// Der Key muss mit dem Command übereinstimmen oder das Modul nutzt Tags.
// Wir nutzen hier PersistentData, da es sicherer ist als Tags.
private final NamespacedKey npcKey = new NamespacedKey(NexusLobby.getInstance(), "dynamic_npc");
@Override
public String getName() {
return "DynamicArmorStands";
}
@Override
public void onEnable() {
startUpdateTask();
Bukkit.getLogger().info("[NexusLobby] DynamicArmorStandModule wurde aktiviert.");
}
/**
* Startet einen Timer, der alle 5 Sekunden (100 Ticks) prüft.
*/
private void startUpdateTask() {
Bukkit.getScheduler().runTaskTimer(NexusLobby.getInstance(), () -> {
updateAllArmorStands();
}, 100L, 100L); // Alle 5 Sekunden statt 2 Minuten
}
public void updateAllArmorStands() {
int hour = LocalTime.now().getHour();
for (World world : Bukkit.getWorlds()) {
boolean isRaining = world.hasStorm();
for (Entity entity : world.getEntities()) {
if (entity instanceof ArmorStand armorStand) {
// PRÜFUNG: Entweder PersistentData ODER Scoreboard-Tag "as_dynamic"
if (armorStand.getPersistentDataContainer().has(npcKey, PersistentDataType.BYTE) ||
armorStand.getScoreboardTags().contains("as_dynamic")) {
applyDynamicChanges(armorStand, hour, isRaining);
}
}
}
}
}
private void applyDynamicChanges(ArmorStand as, int hour, boolean isRaining) {
// --- ZEIT-LOGIK (Nacht: 20:00 - 06:00) ---
if (hour >= 20 || hour <= 6) {
if (as.getEquipment().getItemInOffHand().getType() != Material.TORCH) {
as.getEquipment().setItemInOffHand(new ItemStack(Material.TORCH));
}
} else {
if (as.getEquipment().getItemInOffHand().getType() == Material.TORCH) {
as.getEquipment().setItemInOffHand(null);
}
}
// --- WETTER-LOGIK (Regen) ---
if (isRaining) {
if (as.getEquipment().getHelmet() == null || as.getEquipment().getHelmet().getType() != Material.LEATHER_HELMET) {
as.getEquipment().setHelmet(new ItemStack(Material.LEATHER_HELMET));
}
} else {
// Nur ausziehen, wenn es hellwach ist und nicht regnet
if (hour < 20 && hour > 6) {
if (as.getEquipment().getHelmet() != null && as.getEquipment().getHelmet().getType() == Material.LEATHER_HELMET) {
as.getEquipment().setHelmet(null);
}
}
}
}
/**
* Schaltet den Status um. Wird vom ArmorStandCommand aufgerufen.
*/
public void toggleDynamicStatus(ArmorStand as) {
if (as.getPersistentDataContainer().has(npcKey, PersistentDataType.BYTE)) {
// Deaktivieren
as.getPersistentDataContainer().remove(npcKey);
as.removeScoreboardTag("as_dynamic"); // Zur Sicherheit beides entfernen
as.getEquipment().setItemInOffHand(null);
as.getEquipment().setHelmet(null);
} else {
// Aktivieren
as.getPersistentDataContainer().set(npcKey, PersistentDataType.BYTE, (byte) 1);
as.addScoreboardTag("as_dynamic");
// Sofortige visuelle Rückmeldung
int hour = LocalTime.now().getHour();
boolean isRaining = as.getWorld().hasStorm();
applyDynamicChanges(as, hour, isRaining);
}
}
@Override
public void onDisable() {
// Nichts zu tun
}
}

View File

@@ -4,28 +4,37 @@ import de.nexuslobby.NexusLobby;
import de.nexuslobby.api.Module; import de.nexuslobby.api.Module;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
public class GadgetModule implements Module, Listener { public class GadgetModule implements Module, Listener {
private final Map<UUID, Balloon> activeBalloons = new HashMap<>(); private final Map<UUID, Balloon> activeBalloons = new HashMap<>();
private final Map<UUID, ParticleEffect> activeEffects = new HashMap<>(); private final Map<UUID, ParticleEffect> activeEffects = new HashMap<>();
private final Set<UUID> activeShields = new HashSet<>();
// Titel für die verschiedenen Inventare zur Identifikation
private final String MAIN_TITLE = "§b§lGadgets §8- §7Menü"; private final String MAIN_TITLE = "§b§lGadgets §8- §7Menü";
private final String BALLOON_TITLE = "§b§lGadgets §8- §eBallons"; private final String BALLOON_TITLE = "§b§lGadgets §8- §eBallons";
private final String PARTICLE_TITLE = "§b§lGadgets §8- §dPartikel"; private final String PARTICLE_TITLE = "§b§lGadgets §8- §dPartikel";
private final String FUN_TITLE = "§b§lGadgets §8- §6Lustiges"; private final String FUN_TITLE = "§b§lGadgets §8- §6Lustiges";
private final String HAT_TITLE = "§b§lGadgets §8- §aHüte & Köpfe";
private final String PET_TITLE = "§b§lGadgets §8- §dBegleiter";
@Override @Override
public String getName() { return "Gadgets"; } public String getName() { return "Gadgets"; }
@@ -33,39 +42,104 @@ public class GadgetModule implements Module, Listener {
@Override @Override
public void onEnable() { public void onEnable() {
Bukkit.getPluginManager().registerEvents(this, NexusLobby.getInstance()); Bukkit.getPluginManager().registerEvents(this, NexusLobby.getInstance());
Bukkit.getScheduler().runTaskTimer(NexusLobby.getInstance(), () -> { Bukkit.getScheduler().runTaskTimer(NexusLobby.getInstance(), () -> {
PetManager.updatePets();
activeBalloons.values().forEach(Balloon::update); activeBalloons.values().forEach(Balloon::update);
activeEffects.forEach((uuid, effect) -> {
Player p = Bukkit.getPlayer(uuid); for (Player p : Bukkit.getOnlinePlayers()) {
if (p != null && p.isOnline()) effect.update(p); UUID uuid = p.getUniqueId();
}); handleSpecialHatEffects(p);
if (activeEffects.containsKey(uuid)) activeEffects.get(uuid).update(p);
if (activeShields.contains(uuid)) ShieldTask.handleShield(p);
}
}, 1L, 1L); }, 1L, 1L);
} }
// --- GUI ÖFFNER --- private void handleSpecialHatEffects(Player p) {
ItemStack hat = p.getInventory().getHelmet();
if (hat == null || hat.getType() == Material.AIR) return;
switch (hat.getType()) {
case CAMPFIRE:
p.getWorld().spawnParticle(Particle.CAMPFIRE_COSY_SMOKE, p.getLocation().add(0, 2.2, 0), 1, 0.05, 0.05, 0.05, 0.02);
break;
case SPAWNER:
p.getWorld().spawnParticle(Particle.FLAME, p.getLocation().add(0, 2.1, 0), 1, 0.12, 0.12, 0.12, 0.02);
break;
case SEA_LANTERN:
case BEACON:
p.getWorld().spawnParticle(Particle.END_ROD, p.getLocation().add(0, 2.1, 0), 1, 0.1, 0.1, 0.1, 0.03);
break;
case ENCHANTING_TABLE:
p.getWorld().spawnParticle(Particle.ENCHANT, p.getLocation().add(0, 2.3, 0), 1, 0.2, 0.2, 0.2, 0.5);
break;
}
}
public void openGUI(Player player) { public void openGUI(Player player) {
Inventory gui = Bukkit.createInventory(null, 27, MAIN_TITLE); Inventory gui = Bukkit.createInventory(null, 27, MAIN_TITLE);
fillEdges(gui); fillEdges(gui);
gui.setItem(10, createItem(Material.LEAD, "§e§lBallons", "§7Wähle einen fliegenden Begleiter")); 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(11, createItem(Material.GOLDEN_HELMET, "§a§lHüte", "§7Setze dir etwas auf den Kopf"));
gui.setItem(16, createItem(Material.NETHER_STAR, "§d§lPartikel", "§7Wähle magische Effekte")); gui.setItem(13, createItem(Material.BONE, "§d§lBegleiter", "§7Echte Tiere, die dir folgen"));
gui.setItem(15, createItem(Material.FIREWORK_ROCKET, "§6§lLustiges", "§7Witzige Effekte"));
gui.setItem(16, createItem(Material.NETHER_STAR, "§d§lPartikel", "§7Magische Auren & Effekte"));
gui.setItem(22, createItem(Material.BARRIER, "§c§lStopp", "§7Alle Gadgets entfernen")); gui.setItem(22, createItem(Material.BARRIER, "§c§lStopp", "§7Alle Gadgets entfernen"));
player.openInventory(gui);
}
private void openHatGUI(Player player) {
Inventory gui = Bukkit.createInventory(null, 45, HAT_TITLE);
fillEdges(gui);
gui.setItem(10, createItem(Material.JACK_O_LANTERN, "§6Kürbis-Hut", "§7Es ist immer Halloween!"));
gui.setItem(11, createItem(Material.SEA_LANTERN, "§bMeeres-Leuchten", "§7§oEffekt: Glitzern"));
gui.setItem(12, createItem(Material.GLOWSTONE, "§eGlowstone-Kopf", "§7Werde zur Lampe"));
gui.setItem(13, createItem(Material.TNT, "§cExplosiv-Hut", "§7Vorsicht, heiß!"));
gui.setItem(14, createItem(Material.GLASS, "§fAstronaut", "§7Bereit für den Mond?"));
gui.setItem(15, createItem(Material.DRAGON_HEAD, "§5Enderdrache", "§7Der König der Lüfte"));
gui.setItem(16, createItem(Material.CAKE, "§dKuchen-Kopf", "§7Jeder mag Kuchen!"));
gui.setItem(19, createItem(Material.SLIME_BLOCK, "§aGlibber-Block", "§7Ziemlich klebrig..."));
gui.setItem(20, createItem(Material.MELON, "§aMelonen-Helm", "§7Frisch und saftig"));
gui.setItem(21, createItem(Material.HAY_BLOCK, "§eStrohhut", "§7Sommer auf dem Land"));
gui.setItem(22, createItem(Material.SPAWNER, "§8Monster-Käfig", "§7§oEffekt: Flammen"));
gui.setItem(23, createItem(Material.CRAFTING_TABLE, "§6Werkbank", "§7Immer am Basteln"));
gui.setItem(24, createItem(Material.BOOKSHELF, "§fBücherregal", "§7Ein wahrer Schlaukopf"));
gui.setItem(25, createItem(Material.HONEY_BLOCK, "§6Honig-Hut", "§7Süß und klebrig"));
gui.setItem(28, createItem(Material.GOLD_BLOCK, "§6Gold-Bonze", "§7Zeig was du hast"));
gui.setItem(29, createItem(Material.DIAMOND_ORE, "§bDiamant-Erz", "§7Bau mich bloß nicht ab!"));
gui.setItem(30, createItem(Material.BEACON, "§fLeuchtfeuer", "§7§oEffekt: Glitzern"));
gui.setItem(31, createItem(Material.CONDUIT, "§3Auge des Meeres", "§7Die Macht von Atlantis"));
gui.setItem(32, createItem(Material.ENCHANTING_TABLE, "§dMagier", "§7§oEffekt: Runen"));
gui.setItem(33, createItem(Material.CAMPFIRE, "§cHeißer Kopf", "§7§oEffekt: Rauch"));
gui.setItem(34, createItem(Material.SKELETON_SKULL, "§7Skelett", "§7Ein wenig gruselig"));
gui.setItem(40, createItem(Material.ARROW, "§7Zurück", "§8Zum Hauptmenü"));
player.openInventory(gui);
}
private void openPetGUI(Player player) {
Inventory gui = Bukkit.createInventory(null, 27, PET_TITLE);
fillEdges(gui);
gui.setItem(11, createItem(Material.BONE, "§fWolf", "§7Ein treuer Begleiter"));
gui.setItem(13, createItem(Material.CAT_SPAWN_EGG, "§6Katze", "§7Ein verschmuster Freund"));
gui.setItem(15, createItem(Material.PANDA_SPAWN_EGG, "§aPanda", "§7Ein gemütlicher Zeitgenosse"));
gui.setItem(22, createItem(Material.ARROW, "§7Zurück", "§8Zum Hauptmenü"));
player.openInventory(gui); player.openInventory(gui);
} }
private void openBalloonGUI(Player player) { private void openBalloonGUI(Player player) {
Inventory gui = Bukkit.createInventory(null, 36, BALLOON_TITLE); Inventory gui = Bukkit.createInventory(null, 36, BALLOON_TITLE);
fillEdges(gui); fillEdges(gui);
Material[] wools = {Material.WHITE_WOOL, Material.ORANGE_WOOL, Material.MAGENTA_WOOL, Material.LIGHT_BLUE_WOOL, 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.YELLOW_WOOL, Material.LIME_WOOL, Material.PINK_WOOL, Material.GRAY_WOOL,
Material.CYAN_WOOL, Material.PURPLE_WOOL, Material.BLUE_WOOL, Material.BROWN_WOOL, Material.CYAN_WOOL, Material.PURPLE_WOOL, Material.BLUE_WOOL, Material.BROWN_WOOL,
Material.GREEN_WOOL, Material.RED_WOOL}; Material.GREEN_WOOL, Material.RED_WOOL};
int slot = 10; int slot = 10;
for (Material m : wools) { for (Material m : wools) {
if (slot == 17) slot = 19; if (slot == 17) slot = 19;
@@ -78,11 +152,9 @@ public class GadgetModule implements Module, Listener {
private void openParticleGUI(Player player) { private void openParticleGUI(Player player) {
Inventory gui = Bukkit.createInventory(null, 27, PARTICLE_TITLE); Inventory gui = Bukkit.createInventory(null, 27, PARTICLE_TITLE);
fillEdges(gui); fillEdges(gui);
gui.setItem(11, createItem(Material.POPPY, "§cHerzchen-Aura", "§7Verbreite Liebe in der Lobby"));
gui.setItem(11, createItem(Material.POPPY, "§cHerzchen-Aura", "§7Verbreite Liebe")); gui.setItem(13, createItem(Material.BLAZE_POWDER, "§6Flammen-Ring", "§7Lass es brennen!"));
gui.setItem(13, createItem(Material.BLAZE_POWDER, "§6Flammen-Ring", "§7Werde feurig")); gui.setItem(15, createItem(Material.WATER_BUCKET, "§bRegenwolke", "§7Deine persönliche Abkühlung"));
gui.setItem(15, createItem(Material.WATER_BUCKET, "§bRegenwolke", "§7Lass es regnen"));
gui.setItem(22, createItem(Material.ARROW, "§7Zurück", "§8Zum Hauptmenü")); gui.setItem(22, createItem(Material.ARROW, "§7Zurück", "§8Zum Hauptmenü"));
player.openInventory(gui); player.openInventory(gui);
} }
@@ -90,70 +162,91 @@ public class GadgetModule implements Module, Listener {
private void openFunGUI(Player player) { private void openFunGUI(Player player) {
Inventory gui = Bukkit.createInventory(null, 27, FUN_TITLE); Inventory gui = Bukkit.createInventory(null, 27, FUN_TITLE);
fillEdges(gui); fillEdges(gui);
gui.setItem(11, createItem(Material.FISHING_ROD, "§b§lEnterhaken", "§7Zieh dich durch die Luft!"));
gui.setItem(13, createItem(Material.EGG, "§f§lChicken-Rain", "§7Lass es Küken regnen!")); gui.setItem(13, createItem(Material.SHIELD, "§5§lSchutzzone", "§7Halte andere auf Distanz"));
gui.setItem(15, createItem(Material.EGG, "§f§lChicken-Rain", "§7Gack-Gack! Hühner überall!"));
gui.setItem(22, createItem(Material.ARROW, "§7Zurück", "§8Zum Hauptmenü")); gui.setItem(22, createItem(Material.ARROW, "§7Zurück", "§8Zum Hauptmenü"));
player.openInventory(gui); player.openInventory(gui);
} }
// --- EVENT HANDLER ---
@EventHandler @EventHandler
public void onInventoryClick(InventoryClickEvent event) { public void onInventoryClick(InventoryClickEvent event) {
String title = event.getView().getTitle(); String title = event.getView().getTitle();
if (!title.equals(MAIN_TITLE) && !title.equals(BALLOON_TITLE) && !title.equals(PARTICLE_TITLE) && !title.equals(FUN_TITLE)) return; if (!title.startsWith("§b§lGadgets")) return;
event.setCancelled(true); event.setCancelled(true);
Player player = (Player) event.getWhoClicked(); Player player = (Player) event.getWhoClicked();
ItemStack item = event.getCurrentItem(); ItemStack item = event.getCurrentItem();
if (item == null || item.getType() == Material.AIR) return; if (item == null || item.getType() == Material.AIR) return;
// Zurück-Button Logik if (item.getType() == Material.ARROW) { openGUI(player); return; }
if (item.getType() == Material.ARROW) {
openGUI(player);
return;
}
// HAUPTMENÜ LOGIK
if (title.equals(MAIN_TITLE)) { if (title.equals(MAIN_TITLE)) {
if (item.getType() == Material.LEAD) openBalloonGUI(player); if (item.getType() == Material.LEAD) openBalloonGUI(player);
else if (item.getType() == Material.GOLDEN_HELMET) openHatGUI(player);
else if (item.getType() == Material.BONE) openPetGUI(player);
else if (item.getType() == Material.NETHER_STAR) openParticleGUI(player); else if (item.getType() == Material.NETHER_STAR) openParticleGUI(player);
else if (item.getType() == Material.FIREWORK_ROCKET) openFunGUI(player); else if (item.getType() == Material.FIREWORK_ROCKET) openFunGUI(player);
else if (item.getType() == Material.BARRIER) { else if (item.getType() == Material.BARRIER) { removeGadgets(player); player.closeInventory(); }
removeGadgets(player); }
else if (title.equals(HAT_TITLE)) {
if (item.getType() != Material.GRAY_STAINED_GLASS_PANE) {
HatManager.setHat(player, item.getType(), item.getItemMeta().getDisplayName());
player.playSound(player.getLocation(), Sound.ITEM_ARMOR_EQUIP_GENERIC, 1, 1);
player.closeInventory(); player.closeInventory();
} }
} }
else if (title.equals(PET_TITLE)) {
// BALLON MENÜ LOGIK if (item.getType() == Material.BONE) PetManager.spawnEntityPet(player, "WOLF");
else if (item.getType() == Material.CAT_SPAWN_EGG) PetManager.spawnEntityPet(player, "CAT");
else if (item.getType() == Material.PANDA_SPAWN_EGG) PetManager.spawnEntityPet(player, "PANDA");
player.sendMessage("§8[§6Nexus§8] §dDein Pet wurde gerufen!");
player.closeInventory();
}
else if (title.equals(BALLOON_TITLE)) { else if (title.equals(BALLOON_TITLE)) {
if (item.getType().toString().endsWith("_WOOL")) { if (item.getType().toString().endsWith("_WOOL")) {
if (activeBalloons.containsKey(player.getUniqueId())) activeBalloons.get(player.getUniqueId()).remove(); if (activeBalloons.containsKey(player.getUniqueId())) activeBalloons.get(player.getUniqueId()).remove();
activeBalloons.put(player.getUniqueId(), new Balloon(player, item.getType())); activeBalloons.put(player.getUniqueId(), new Balloon(player, item.getType()));
player.sendMessage("§8[§6Nexus§8] §aBallon ausgerüstet!"); player.sendMessage("§8[§6Nexus§8] §aBallon aktiviert!");
player.closeInventory(); player.closeInventory();
} }
} }
// PARTIKEL MENÜ LOGIK
else if (title.equals(PARTICLE_TITLE)) { else if (title.equals(PARTICLE_TITLE)) {
if (item.getType() == Material.POPPY) activeEffects.put(player.getUniqueId(), new ParticleEffect("hearts")); 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.BLAZE_POWDER) activeEffects.put(player.getUniqueId(), new ParticleEffect("flames"));
else if (item.getType() == Material.WATER_BUCKET) activeEffects.put(player.getUniqueId(), new ParticleEffect("cloud")); else if (item.getType() == Material.WATER_BUCKET) activeEffects.put(player.getUniqueId(), new ParticleEffect("cloud"));
player.sendMessage("§8[§6Nexus§8] §aPartikel aktiviert!");
if (item.getType() != Material.GRAY_STAINED_GLASS_PANE) { player.closeInventory();
player.sendMessage("§8[§6Nexus§8] §aEffekt aktiviert!");
player.closeInventory();
}
} }
// FUN MENÜ LOGIK
else if (title.equals(FUN_TITLE)) { else if (title.equals(FUN_TITLE)) {
if (item.getType() == Material.EGG) { if (item.getType() == Material.EGG) {
ChickenRain.start(player); ChickenRain.start(player);
player.sendMessage("§8[§6Nexus§8] §fEs regnet jetzt Hühner!"); player.sendMessage("§8[§6Nexus§8] §fHühnerregen gestartet!");
player.closeInventory(); player.closeInventory();
} else if (item.getType() == Material.FISHING_ROD) {
player.getInventory().addItem(createItem(Material.FISHING_ROD, "§b§lEnterhaken", "§7Rechtsklick zum Katapultieren"));
player.closeInventory();
} else if (item.getType() == Material.SHIELD) {
if (activeShields.contains(player.getUniqueId())) {
activeShields.remove(player.getUniqueId());
player.sendMessage("§8[§6Nexus§8] §cSchutzzone deaktiviert.");
} else {
activeShields.add(player.getUniqueId());
player.sendMessage("§8[§6Nexus§8] §5Schutzzone aktiviert!");
}
player.closeInventory();
}
}
}
@EventHandler
public void onFish(PlayerFishEvent event) {
Player player = event.getPlayer();
ItemStack item = player.getInventory().getItemInMainHand();
if (item != null && item.getType() == Material.FISHING_ROD && item.hasItemMeta() && item.getItemMeta().getDisplayName().equals("§b§lEnterhaken")) {
if (event.getState() == PlayerFishEvent.State.IN_GROUND || event.getState() == PlayerFishEvent.State.REEL_IN || event.getState() == PlayerFishEvent.State.CAUGHT_ENTITY) {
if (event.getHook() != null) {
GrapplingHook.pullPlayer(player, event.getHook().getLocation());
}
} }
} }
} }
@@ -164,15 +257,17 @@ public class GadgetModule implements Module, Listener {
activeBalloons.remove(player.getUniqueId()); activeBalloons.remove(player.getUniqueId());
} }
activeEffects.remove(player.getUniqueId()); activeEffects.remove(player.getUniqueId());
player.sendMessage("§8[§6Nexus§8] §cAlle Gadgets wurden entfernt."); activeShields.remove(player.getUniqueId());
PetManager.removePet(player);
HatManager.removeHat(player);
player.getInventory().remove(Material.FISHING_ROD);
player.sendMessage("§8[§6Nexus§8] §cAlle Gadgets abgelegt.");
} }
private void fillEdges(Inventory inv) { private void fillEdges(Inventory inv) {
ItemStack glass = createItem(Material.GRAY_STAINED_GLASS_PANE, " ", null); ItemStack glass = createItem(Material.GRAY_STAINED_GLASS_PANE, " ", null);
for (int i = 0; i < inv.getSize(); i++) { for (int i = 0; i < inv.getSize(); i++) {
if (i < 9 || i >= inv.getSize() - 9 || i % 9 == 0 || (i + 1) % 9 == 0) { if (i < 9 || i >= inv.getSize() - 9 || i % 9 == 0 || (i + 1) % 9 == 0) inv.setItem(i, glass);
inv.setItem(i, glass);
}
} }
} }
@@ -182,7 +277,7 @@ public class GadgetModule implements Module, Listener {
if (meta != null) { if (meta != null) {
meta.setDisplayName(name); meta.setDisplayName(name);
if (lore != null) { if (lore != null) {
java.util.List<String> l = new java.util.ArrayList<>(); List<String> l = new ArrayList<>();
l.add(lore); l.add(lore);
meta.setLore(l); meta.setLore(l);
} }
@@ -193,8 +288,10 @@ public class GadgetModule implements Module, Listener {
@Override @Override
public void onDisable() { public void onDisable() {
PetManager.clearAll();
activeBalloons.values().forEach(Balloon::remove); activeBalloons.values().forEach(Balloon::remove);
activeBalloons.clear(); activeBalloons.clear();
activeEffects.clear(); activeEffects.clear();
activeShields.clear();
} }
} }

View File

@@ -0,0 +1,37 @@
package de.nexuslobby.modules.gadgets;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
public class GrapplingHook {
public static void pullPlayer(Player player, Location target) {
Location playerLoc = player.getLocation();
// Vektor vom Spieler zum Ziel berechnen
double distance = target.distance(playerLoc);
// Wenn das Ziel zu nah oder zu weit weg ist, nichts tun
if (distance < 2 || distance > 50) return;
// Berechnung des Wurfs (Vektor)
Vector v = target.toVector().subtract(playerLoc.toVector());
// Den Vektor normalisieren und skalieren (Stärke des Zugs)
v.multiply(0.3); // Basis-Geschwindigkeit
v.setY(v.getY() * 0.6 + 0.5); // Etwas mehr Höhe für den Bogen-Effekt
// Geschwindigkeit begrenzen, damit man nicht aus der Map schießt
if (v.length() > 2.5) {
v.normalize().multiply(2.5);
}
player.setVelocity(v);
// Sound-Effekt für das "Ziehen"
player.playSound(playerLoc, Sound.ENTITY_WIND_CHARGE_WIND_BURST, 1.0f, 1.2f);
player.playSound(playerLoc, Sound.ITEM_TRIDENT_RIPTIDE_1, 0.5f, 1.5f);
}
}

View File

@@ -0,0 +1,26 @@
package de.nexuslobby.modules.gadgets;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class HatManager {
public static void setHat(Player player, Material material, String name) {
ItemStack hat = new ItemStack(material);
ItemMeta meta = hat.getItemMeta();
if (meta != null) {
meta.setDisplayName("§6Hut: " + name);
hat.setItemMeta(meta);
}
// Den Gegenstand auf den Kopf setzen
player.getInventory().setHelmet(hat);
player.sendMessage("§8[§6Nexus§8] §aDu trägst nun: " + name);
}
public static void removeHat(Player player) {
player.getInventory().setHelmet(null);
}
}

View File

@@ -0,0 +1,138 @@
package de.nexuslobby.modules.gadgets;
import de.nexuslobby.NexusLobby;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Tameable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class PetManager implements Listener {
private static final Map<UUID, Entity> activePets = new HashMap<>();
public PetManager() {
Bukkit.getPluginManager().registerEvents(this, NexusLobby.getInstance());
}
/**
* Spawnt ein echtes Tier-Entity für den Spieler.
*/
public static void spawnEntityPet(Player player, String type) {
removePet(player);
EntityType entityType;
try {
entityType = EntityType.valueOf(type);
} catch (IllegalArgumentException e) {
player.sendMessage("§cFehler: Tier-Typ nicht gefunden.");
return;
}
Location loc = player.getLocation();
Entity pet = player.getWorld().spawnEntity(loc, entityType);
pet.setCustomName("§d" + player.getName() + "'s " + capitalize(type.toLowerCase()));
pet.setCustomNameVisible(true);
pet.setInvulnerable(true);
pet.setPersistent(false);
if (pet instanceof LivingEntity) {
LivingEntity le = (LivingEntity) pet;
le.setRemoveWhenFarAway(false);
// Verhindert, dass das Pet andere angreift
if (le instanceof Tameable) {
((Tameable) le).setTamed(true);
((Tameable) le).setOwner(player);
}
}
activePets.put(player.getUniqueId(), pet);
}
/**
* Steuert das Folgen der Tiere. Wird vom GadgetModule-Timer aufgerufen.
*/
public static void updatePets() {
for (Map.Entry<UUID, Entity> entry : activePets.entrySet()) {
Player owner = Bukkit.getPlayer(entry.getKey());
Entity pet = entry.getValue();
if (owner == null || !owner.isOnline() || pet.isDead()) {
continue;
}
// Wenn das Pet in einer anderen Welt ist oder zu weit weg, teleportiere es
if (!pet.getWorld().equals(owner.getWorld()) || pet.getLocation().distance(owner.getLocation()) > 10) {
pet.teleport(owner.getLocation());
continue;
}
// Sanftes Folgen: Wenn das Pet weiter als 3 Blöcke weg ist
if (pet.getLocation().distance(owner.getLocation()) > 3) {
Location target = owner.getLocation().clone().add(owner.getLocation().getDirection().multiply(-1.5));
target.setY(owner.getLocation().getY());
// Teleportiert das Pet leicht zum Ziel (simuliert Laufen)
pet.teleport(pet.getLocation().add(target.toVector().subtract(pet.getLocation().toVector()).normalize().multiply(0.2)));
// Blickrichtung anpassen
Location lookAt = pet.getLocation();
lookAt.setDirection(owner.getLocation().toVector().subtract(pet.getLocation().toVector()));
pet.teleport(lookAt);
}
}
}
public static void removePet(Player player) {
if (activePets.containsKey(player.getUniqueId())) {
activePets.get(player.getUniqueId()).remove();
activePets.remove(player.getUniqueId());
}
}
public static void clearAll() {
for (Entity pet : activePets.values()) {
pet.remove();
}
activePets.clear();
}
private static String capitalize(String str) {
if (str == null || str.isEmpty()) return str;
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
// --- Events um die Pets zu schützen ---
@EventHandler
public void onPetDamage(EntityDamageEvent event) {
if (activePets.containsValue(event.getEntity())) {
event.setCancelled(true);
}
}
@EventHandler
public void onPetTarget(EntityTargetEvent event) {
if (activePets.containsValue(event.getEntity())) {
event.setCancelled(true);
}
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
removePet(event.getPlayer());
}
}

View File

@@ -0,0 +1,32 @@
package de.nexuslobby.modules.gadgets;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
public class ShieldTask {
public static void handleShield(Player owner) {
// Erzeuge einen Partikel-Ring um den Spieler
for (double i = 0; i < Math.PI * 2; i += Math.PI / 8) {
double x = Math.cos(i) * 2.2;
double z = Math.sin(i) * 2.2;
owner.getWorld().spawnParticle(Particle.WITCH, owner.getLocation().add(x, 0.5, z), 1, 0, 0, 0, 0);
}
// Stoße andere Spieler weg
for (Entity entity : owner.getNearbyEntities(2.2, 2.0, 2.2)) {
if (entity instanceof Player && entity != owner) {
Player target = (Player) entity;
Vector direction = target.getLocation().toVector().subtract(owner.getLocation().toVector()).normalize();
direction.multiply(0.4).setY(0.2);
target.setVelocity(direction);
target.playSound(target.getLocation(), Sound.ENTITY_CHICKEN_EGG, 0.5f, 0.5f);
}
}
}
}

View File

@@ -0,0 +1,85 @@
package de.nexuslobby.commands;
import de.nexuslobby.modules.hologram.HologramModule;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class HoloCommand implements CommandExecutor {
private final HologramModule module;
public HoloCommand(HologramModule module) {
this.module = module;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) return true;
if (!player.hasPermission("nexuslobby.hologram")) {
player.sendMessage("§8[§6Nexus§8] §cKeine Rechte.");
return true;
}
if (args.length < 1) {
sendHelp(player);
return true;
}
if (args[0].equalsIgnoreCase("create")) {
// Wir brauchen id, typ und mindestens ein Wort Text
if (args.length < 4) {
player.sendMessage("§cNutze: /holo create <id> <NONE|FAST|SLOW> <text>");
return true;
}
String id = args[1];
// Der Typ (args[2]) wird im neuen System ignoriert, da wir Seiten nutzen
StringBuilder sb = new StringBuilder();
for (int i = 3; i < args.length; i++) {
sb.append(args[i]).append(i == args.length - 1 ? "" : " ");
}
String fullText = sb.toString().trim();
List<String> pages = new ArrayList<>();
// Support für mehrere Seiten via ";"
if (fullText.contains(";")) {
pages.addAll(Arrays.asList(fullText.split(";")));
} else {
pages.add(fullText);
}
// Aufruf der neuen Methode mit List<String>
module.createHologram(id, player.getLocation(), pages);
player.sendMessage("§8[§6Nexus§8] §aHologramm §e" + id + " §aerstellt (" + pages.size() + " Seiten).");
}
else if (args[0].equalsIgnoreCase("delete")) {
if (args.length < 2) {
player.sendMessage("§cBitte gib eine ID an: /holo delete <id>");
return true;
}
module.removeHologram(args[1]);
player.sendMessage("§8[§6Nexus§8] §cHologramm §e" + args[1] + " §ageloescht.");
} else {
sendHelp(player);
}
return true;
}
private void sendHelp(Player player) {
player.sendMessage("§8§m-----------§r §6Hologramme §8§m-----------");
player.sendMessage("§e/holo create <id> <NONE|FAST|SLOW> <text>");
player.sendMessage("§e/holo delete <id>");
player.sendMessage("§7Nutze §b; §7für neue Seiten.");
player.sendMessage("§7Nutze §b\\n §7für Zeilenumbruch.");
}
}

View File

@@ -0,0 +1,134 @@
package de.nexuslobby.modules.hologram;
import de.nexuslobby.NexusLobby;
import de.nexuslobby.api.Module;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class HologramModule implements Module, Listener {
private final Map<String, NexusHologram> holograms = new ConcurrentHashMap<>();
private File file;
private FileConfiguration config;
@Override
public String getName() { return "Holograms"; }
@Override
public void onEnable() {
loadConfig();
loadHolograms();
Bukkit.getPluginManager().registerEvents(this, NexusLobby.getInstance());
Bukkit.getScheduler().runTaskTimer(NexusLobby.getInstance(), () -> {
for (Player player : Bukkit.getOnlinePlayers()) {
holograms.values().forEach(h -> h.renderForPlayer(player));
}
}, 20L, 5L);
}
private void loadConfig() {
file = new File(NexusLobby.getInstance().getDataFolder(), "holograms.yml");
config = YamlConfiguration.loadConfiguration(file);
}
private void loadHolograms() {
holograms.values().forEach(NexusHologram::removeAll);
holograms.clear();
for (String id : config.getKeys(false)) {
World world = Bukkit.getWorld(config.getString(id + ".world", "world"));
if (world == null) continue;
Location loc = new Location(world, config.getDouble(id + ".x"), config.getDouble(id + ".y"), config.getDouble(id + ".z"));
List<String> pages;
if (config.isList(id + ".text")) {
pages = config.getStringList(id + ".text");
} else {
pages = new ArrayList<>();
pages.add(config.getString(id + ".text", "No Text"));
}
holograms.put(id, new NexusHologram(id, loc, pages));
}
}
@EventHandler
public void onInteract(PlayerInteractEntityEvent event) {
// Wir prüfen, ob auf ein Interaction-Entity geklickt wurde
for (NexusHologram holo : holograms.values()) {
if (holo.isInteractionEntity(event.getRightClicked().getUniqueId())) {
holo.nextPage(event.getPlayer());
break;
}
}
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
holograms.values().forEach(h -> h.removeForPlayer(event.getPlayer()));
}
@EventHandler
public void onWorldChange(PlayerChangedWorldEvent event) {
holograms.values().forEach(h -> h.removeForPlayer(event.getPlayer()));
}
@EventHandler
public void onJoin(PlayerJoinEvent event) {
// Cleanup alter Entities für den Joiner
Bukkit.getScheduler().runTaskLater(NexusLobby.getInstance(), () -> {
event.getPlayer().getWorld().getEntities().forEach(entity -> {
if (entity.getCustomName() != null && entity.getCustomName().startsWith("nexus_h_")) {
if (!entity.getCustomName().endsWith("_" + event.getPlayer().getName())) {
event.getPlayer().hideEntity(NexusLobby.getInstance(), entity);
}
}
});
}, 5L);
}
public void createHologram(String id, Location loc, List<String> pages) {
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(); }
NexusHologram holo = new NexusHologram(id, loc, pages);
holograms.put(id, holo);
}
public void removeHologram(String id) {
NexusHologram holo = holograms.remove(id);
if (holo != null) holo.removeAll();
config.set(id, null);
try { config.save(file); } catch (IOException e) { e.printStackTrace(); }
}
public Set<String> getHologramIds() { return config.getKeys(false); }
@Override
public void onDisable() {
holograms.values().forEach(NexusHologram::removeAll);
holograms.clear();
}
}

View File

@@ -0,0 +1,115 @@
package de.nexuslobby.modules.hologram;
import de.nexuslobby.NexusLobby;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.entity.Display;
import org.bukkit.entity.Interaction;
import org.bukkit.entity.Player;
import org.bukkit.entity.TextDisplay;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class NexusHologram {
private final String id;
private final Location location;
private final List<String> pages;
private final Map<UUID, TextDisplay> playerEntities = new ConcurrentHashMap<>();
private final Map<UUID, Interaction> playerInteractions = new ConcurrentHashMap<>();
private final Map<UUID, Integer> currentPage = new ConcurrentHashMap<>();
public NexusHologram(String id, Location location, List<String> pages) {
this.id = id;
this.location = location;
this.pages = pages;
}
public void nextPage(Player player) {
if (pages.size() <= 1) return;
int next = (currentPage.getOrDefault(player.getUniqueId(), 0) + 1) % pages.size();
currentPage.put(player.getUniqueId(), next);
renderForPlayer(player);
}
public void renderForPlayer(Player player) {
if (!player.getWorld().equals(location.getWorld()) || player.getLocation().distanceSquared(location) > 2304) {
removeForPlayer(player);
return;
}
int pageIdx = currentPage.getOrDefault(player.getUniqueId(), 0);
String rawText = pages.get(pageIdx);
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
rawText = PlaceholderAPI.setPlaceholders(player, rawText);
}
final String finalText = rawText.replace("&", "§").replace("\\n", "\n");
TextDisplay display = playerEntities.get(player.getUniqueId());
if (display == null || !display.isValid()) {
// Text erstellen
display = location.getWorld().spawn(location, TextDisplay.class, entity -> {
entity.setCustomName("nexus_h_" + id + "_" + player.getName());
entity.setCustomNameVisible(false);
entity.setPersistent(false);
entity.setBillboard(Display.Billboard.CENTER);
entity.setBackgroundColor(Color.fromARGB(0, 0, 0, 0));
entity.setText(finalText);
entity.setInvulnerable(true);
});
// Interaction Entity für Klick-Erkennung (Hitbox)
Interaction interact = location.getWorld().spawn(location, Interaction.class, entity -> {
entity.setInteractionWidth(2.0f);
entity.setInteractionHeight(2.0f);
entity.setPersistent(false);
});
final TextDisplay finalDisplay = display;
final Interaction finalInteract = interact;
for (Player other : Bukkit.getOnlinePlayers()) {
if (!other.equals(player)) {
other.hideEntity(NexusLobby.getInstance(), finalDisplay);
other.hideEntity(NexusLobby.getInstance(), finalInteract);
}
}
playerEntities.put(player.getUniqueId(), display);
playerInteractions.put(player.getUniqueId(), interact);
} else {
if (!display.getText().equals(finalText)) {
display.setText(finalText);
}
}
}
public void removeForPlayer(Player player) {
TextDisplay display = playerEntities.remove(player.getUniqueId());
if (display != null) display.remove();
Interaction interact = playerInteractions.remove(player.getUniqueId());
if (interact != null) interact.remove();
}
public void removeAll() {
playerEntities.values().forEach(TextDisplay::remove);
playerInteractions.values().forEach(Interaction::remove);
playerEntities.clear();
playerInteractions.clear();
}
public boolean isInteractionEntity(UUID entityId) {
return playerInteractions.values().stream().anyMatch(i -> i.getUniqueId().equals(entityId));
}
public String getId() { return id; }
}

View File

@@ -1,6 +1,6 @@
name: NexusLobby name: NexusLobby
main: de.nexuslobby.NexusLobby main: de.nexuslobby.NexusLobby
version: "1.0.2" version: "1.0.3"
api-version: "1.21" api-version: "1.21"
author: M_Viper author: M_Viper
description: Modular Lobby Plugin description: Modular Lobby Plugin
@@ -12,49 +12,45 @@ commands:
usage: /portal <args> usage: /portal <args>
permission: nexuslobby.portal permission: nexuslobby.portal
permission-message: "§cKeine Rechte!" permission-message: "§cKeine Rechte!"
giveportalwand: giveportalwand:
description: Gibt das Portal-Werkzeug description: Gibt das Portal-Werkzeug
usage: /giveportalwand usage: /giveportalwand
permission: nexuslobby.portal.give permission: nexuslobby.portal.give
permission-message: "§cDu hast keine Berechtigung dafür." permission-message: "§cDu hast keine Berechtigung dafür."
maintenance: maintenance:
description: Aktiviert oder deaktiviert den Wartungsmodus description: Aktiviert oder deaktiviert den Wartungsmodus
usage: /maintenance <on|off> usage: /maintenance <on|off>
permission: nexuslobby.maintenance permission: nexuslobby.maintenance
permission-message: "§cDu hast keine Rechte!" permission-message: "§cDu hast keine Rechte!"
serverswitcher: serverswitcher:
description: Öffnet die Server Switcher GUI description: Öffnet die Server Switcher GUI
usage: /serverswitcher usage: /serverswitcher
permission: nexuslobby.serverswitcher permission: nexuslobby.serverswitcher
permission-message: "§cDu hast keine Rechte!" permission-message: "§cDu hast keine Rechte!"
settings: settings:
description: Öffnet das Lobby-Einstellungsmenü (Gamerules) description: Öffnet das Lobby-Einstellungsmenü (Gamerules)
usage: /settings usage: /settings
permission: nexuslobby.admin permission: nexuslobby.admin
permission-message: "§cDu hast keine Rechte für die Admin-Einstellungen!" permission-message: "§cDu hast keine Rechte für die Admin-Einstellungen!"
build: build:
description: Aktiviert oder deaktiviert den Baumodus description: Aktiviert oder deaktiviert den Baumodus
usage: /build usage: /build
permission: nexuslobby.build permission: nexuslobby.build
permission-message: "§cDu hast keine Rechte!" permission-message: "§cDu hast keine Rechte!"
nexuslobby: nexuslobby:
description: Zeigt Informationen über das Plugin an oder lädt es neu description: Zeigt Informationen über das Plugin an oder lädt es neu
usage: /nexuslobby [reload] usage: /nexuslobby [reload]
aliases: [nexus] aliases: [nexus]
# --- ArmorStandTools Sektion ---
nexustools: nexustools:
description: Nexus ArmorStand Editor description: Nexus ArmorStand Editor
aliases: [nt, ntools, astools] aliases: [nt, ntools, astools]
nexuscmd: nexuscmd:
description: Nexus Command Binder description: Nexus Command Binder
aliases: [ncmd, ascmd] aliases: [ncmd, ascmd]
holo:
description: Verwalte Lobby Hologramme (Text-Displays)
usage: /holo <create|delete> <id> [text]
permission: nexuslobby.hologram
permissions: permissions:
nexuslobby.portal: nexuslobby.portal:
@@ -81,3 +77,9 @@ permissions:
nexuslobby.armorstand.cmd: nexuslobby.armorstand.cmd:
description: Erlaubt das Binden von Commands via NexusCmd description: Erlaubt das Binden von Commands via NexusCmd
default: op default: op
nexuslobby.armorstand.dynamic:
description: Erlaubt das Markieren von dynamischen NPCs
default: op
nexuslobby.hologram:
description: Erlaubt das Erstellen von Text-Display Hologrammen
default: op