From 2c8eb8fb706a3060d65048fe9fcb53d2b82cb87c Mon Sep 17 00:00:00 2001 From: M_Viper Date: Tue, 31 Mar 2026 08:21:09 +0200 Subject: [PATCH] Update from Git Manager GUI --- .../de/mviper/elevator/DatabaseManager.java | 253 ++++++++++++++---- .../java/de/mviper/elevator/Elevator.java | 1 + .../de/mviper/elevator/ElevatorCommand.java | 227 +++++++++++----- .../de/mviper/elevator/ElevatorListener.java | 94 +++---- .../mviper/elevator/ElevatorTabCompleter.java | 129 +++++++++ src/main/resources/plugin.yml | 2 +- 6 files changed, 533 insertions(+), 173 deletions(-) create mode 100644 src/main/java/de/mviper/elevator/ElevatorTabCompleter.java diff --git a/src/main/java/de/mviper/elevator/DatabaseManager.java b/src/main/java/de/mviper/elevator/DatabaseManager.java index d8e2038..942a611 100644 --- a/src/main/java/de/mviper/elevator/DatabaseManager.java +++ b/src/main/java/de/mviper/elevator/DatabaseManager.java @@ -1,132 +1,283 @@ package de.mviper.elevator; import org.bukkit.Location; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; public class DatabaseManager { + + // Maximaler Radius (in Blöcken, horizontal, gleiche Y-Ebene) für Auto-Gruppierung + private static final int GROUP_SCAN_RADIUS = 4; + private File localFile; private FileConfiguration localConfig; - public DatabaseManager() { setupLocalFile(); } + public DatabaseManager() { + setupLocalFile(); + } private void setupLocalFile() { localFile = new File(Elevator.getInstance().getDataFolder(), "elevators.yml"); if (!localFile.exists()) { - try { + try { Elevator.getInstance().getDataFolder().mkdirs(); - localFile.createNewFile(); - } catch (IOException e) { e.printStackTrace(); } + localFile.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } } localConfig = YamlConfiguration.loadConfiguration(localFile); } + // ───────────────────────────────────────────── + // Basis-Operationen + // ───────────────────────────────────────────── + public void addElevator(Location loc, UUID owner) { String key = locToKey(loc); localConfig.set(key + ".owner", owner.toString()); - localConfig.set(key + ".name", "Etage"); localConfig.set(key + ".public", true); saveLocal(); - - // Debug-Ausgabe + + // Gruppe sofort zuweisen (Auto-Detect angrenzender Module) + getOrAssignGroupId(loc); + if (Elevator.getInstance().isDebugMode()) { - Elevator.getInstance().getLogger().info("Aufzug hinzugefügt: " + key + " | Public: true"); + Elevator.getInstance().getLogger().info( + "Aufzug registriert: " + key + " | Gruppe: " + getGroupId(loc)); } } - public void removeElevator(Location loc) { - localConfig.set(locToKey(loc), null); - saveLocal(); + public void removeElevator(Location loc) { + String key = locToKey(loc); + String groupId = localConfig.getString(key + ".group"); + + localConfig.set(key, null); + saveLocal(); + + // Gruppe aufräumen, wenn keine Mitglieder mehr + if (groupId != null && getMembersOfGroup(groupId).isEmpty()) { + localConfig.set("groups." + groupId, null); + saveLocal(); + if (Elevator.getInstance().isDebugMode()) { + Elevator.getInstance().getLogger().info("Gruppe " + groupId + " gelöscht (keine Mitglieder mehr)."); + } + } } - - public boolean isElevator(Location loc) { - return localConfig.contains(locToKey(loc)); + + public boolean isElevator(Location loc) { + return localConfig.contains(locToKey(loc)); } - - public String getFloorCustomName(Location loc) { - return localConfig.getString(locToKey(loc) + ".name", "Etage"); + + // ───────────────────────────────────────────── + // Gruppen-System + // ───────────────────────────────────────────── + + /** + * Gibt die Gruppen-ID für ein Modul zurück. + * Existiert noch keine, wird automatisch eine erstellt oder eine benachbarte übernommen. + */ + public String getOrAssignGroupId(Location loc) { + String key = locToKey(loc); + + // Existiert kein gültiger Aufzug → null + if (!localConfig.contains(key)) return null; + + // Gruppe schon gesetzt? + if (localConfig.contains(key + ".group")) { + return localConfig.getString(key + ".group"); + } + + // Migration: ältere Einträge haben .name direkt gespeichert + String oldName = localConfig.getString(key + ".name", null); + + // Benachbartes Modul mit Gruppe suchen (gleiche Y-Ebene) + String foundGroup = findAdjacentGroupId(loc); + if (foundGroup != null) { + localConfig.set(key + ".group", foundGroup); + // Alten Namen übernehmen, falls Gruppe noch Default-Name hat + if (oldName != null && !oldName.equals("Etage") + && "Etage".equals(localConfig.getString("groups." + foundGroup + ".name", "Etage"))) { + localConfig.set("groups." + foundGroup + ".name", oldName); + } + localConfig.set(key + ".name", null); // Altes Feld entfernen + saveLocal(); + return foundGroup; + } + + // Neue Gruppe erstellen + String newGroupId = UUID.randomUUID().toString().substring(0, 8); + String groupName = (oldName != null && !oldName.isEmpty()) ? oldName : "Etage"; + localConfig.set(key + ".group", newGroupId); + localConfig.set("groups." + newGroupId + ".name", groupName); + localConfig.set(key + ".name", null); // Altes Feld entfernen + saveLocal(); + + if (Elevator.getInstance().isDebugMode()) { + Elevator.getInstance().getLogger().info("Neue Gruppe erstellt: " + newGroupId + " | Name: " + groupName); + } + return newGroupId; } - - public void setFloorName(Location loc, String name) { - localConfig.set(locToKey(loc) + ".name", name); - saveLocal(); + + /** Gibt die Gruppen-ID eines Moduls zurück (mit Lazy-Init). */ + public String getGroupId(Location loc) { + return getOrAssignGroupId(loc); } - - public UUID getOwner(Location loc) { + + /** + * Weist einem Modul manuell eine Gruppen-ID zu. + * Wird vom /elevator group link Befehl genutzt. + */ + public void setGroupId(Location loc, String groupId) { + String key = locToKey(loc); + if (!localConfig.contains(key)) return; + + localConfig.set(key + ".group", groupId); + // Gruppe anlegen, falls noch nicht vorhanden + if (!localConfig.contains("groups." + groupId + ".name")) { + localConfig.set("groups." + groupId + ".name", "Etage"); + } + saveLocal(); + } + + /** Gibt den Anzeige-Namen der Gruppe zurück. */ + public String getGroupName(String groupId) { + return localConfig.getString("groups." + groupId + ".name", "Etage"); + } + + /** Setzt den Anzeige-Namen für eine Gruppe (benennt damit alle Mitglieder). */ + public void setGroupNameById(String groupId, String name) { + localConfig.set("groups." + groupId + ".name", name); + saveLocal(); + } + + /** Alle Modul-Schlüssel (ohne "data." Prefix), die zur Gruppe gehören. */ + public List getMembersOfGroup(String groupId) { + List members = new ArrayList<>(); + ConfigurationSection data = localConfig.getConfigurationSection("data"); + if (data == null) return members; + for (String locKey : data.getKeys(false)) { + if (groupId.equals(data.getString(locKey + ".group"))) { + members.add(locKey); + } + } + return members; + } + + /** Scannt benachbarte Module (horizontal, gleiche Y-Höhe) auf vorhandene Gruppen-IDs. */ + private String findAdjacentGroupId(Location loc) { + for (int dx = -GROUP_SCAN_RADIUS; dx <= GROUP_SCAN_RADIUS; dx++) { + for (int dz = -GROUP_SCAN_RADIUS; dz <= GROUP_SCAN_RADIUS; dz++) { + if (dx == 0 && dz == 0) continue; + Location adj = loc.clone().add(dx, 0, dz); + String adjKey = locToKey(adj); + if (localConfig.contains(adjKey) && localConfig.contains(adjKey + ".group")) { + return localConfig.getString(adjKey + ".group"); + } + } + } + return null; + } + + // ───────────────────────────────────────────── + // Namen (jetzt Gruppen-basiert) + // ───────────────────────────────────────────── + + /** Gibt den Etagen-Namen zurück — immer aus der Gruppe. */ + public String getFloorCustomName(Location loc) { + String groupId = getGroupId(loc); + if (groupId == null) return "Etage"; + return getGroupName(groupId); + } + + /** Setzt den Etagen-Namen für die gesamte Gruppe dieses Moduls. */ + public void setFloorName(Location loc, String name) { + String groupId = getGroupId(loc); + if (groupId == null) return; + setGroupNameById(groupId, name); + } + + // ───────────────────────────────────────────── + // Besitzer & Sichtbarkeit + // ───────────────────────────────────────────── + + public UUID getOwner(Location loc) { String s = localConfig.getString(locToKey(loc) + ".owner"); - return s != null ? UUID.fromString(s) : UUID.randomUUID(); + return s != null ? UUID.fromString(s) : UUID.randomUUID(); } - + public boolean isPublic(Location loc) { String key = locToKey(loc); String fullKey = key + ".public"; - - // Prüfe zuerst, ob der Aufzug überhaupt existiert + if (!localConfig.contains(key)) { if (Elevator.getInstance().isDebugMode()) { Elevator.getInstance().getLogger().warning("isPublic: Aufzug existiert nicht: " + key); } return true; } - - // Wenn der public-Schlüssel nicht existiert, setze ihn auf true (Standard) if (!localConfig.contains(fullKey)) { - if (Elevator.getInstance().isDebugMode()) { - Elevator.getInstance().getLogger().info("isPublic: Schlüssel nicht gefunden, setze auf true: " + fullKey); - } localConfig.set(fullKey, true); saveLocal(); return true; } - + boolean value = localConfig.getBoolean(fullKey, true); if (Elevator.getInstance().isDebugMode()) { Elevator.getInstance().getLogger().info("isPublic: " + fullKey + " = " + value); } return value; } - + public void setPublic(Location loc, boolean status) { String key = locToKey(loc); String fullKey = key + ".public"; - - // Prüfe, ob der Aufzug existiert + if (!localConfig.contains(key)) { if (Elevator.getInstance().isDebugMode()) { Elevator.getInstance().getLogger().warning("setPublic: Aufzug existiert nicht: " + key); } return; } - + localConfig.set(fullKey, status); saveLocal(); - - // Sofort nochmal laden um zu verifizieren + + // Neu laden und verifizieren localConfig = YamlConfiguration.loadConfiguration(localFile); boolean verification = localConfig.getBoolean(fullKey, true); - + if (Elevator.getInstance().isDebugMode()) { - Elevator.getInstance().getLogger().info("setPublic: " + fullKey + " auf " + status + " gesetzt (Verifiziert: " + verification + ")"); + Elevator.getInstance().getLogger().info( + "setPublic: " + fullKey + " auf " + status + " gesetzt (Verifiziert: " + verification + ")"); } } - + + // ───────────────────────────────────────────── + // Hilfsmethoden + // ───────────────────────────────────────────── + private String locToKey(Location l) { - // Wichtig: Nutze getBlockX/Y/Z für konsistente Koordinaten - String key = "data." + l.getWorld().getName() + "_" + l.getBlockX() + "_" + l.getBlockY() + "_" + l.getBlockZ(); - return key; + return "data." + l.getWorld().getName() + + "_" + l.getBlockX() + + "_" + l.getBlockY() + + "_" + l.getBlockZ(); } - - private void saveLocal() { - try { + + private void saveLocal() { + try { localConfig.save(localFile); if (Elevator.getInstance().isDebugMode()) { Elevator.getInstance().getLogger().info("Datenbank gespeichert: " + localFile.getName()); } - } catch (IOException e) { - e.printStackTrace(); - } + } catch (IOException e) { + e.printStackTrace(); + } } } \ No newline at end of file diff --git a/src/main/java/de/mviper/elevator/Elevator.java b/src/main/java/de/mviper/elevator/Elevator.java index 35923bf..95cca48 100644 --- a/src/main/java/de/mviper/elevator/Elevator.java +++ b/src/main/java/de/mviper/elevator/Elevator.java @@ -45,6 +45,7 @@ public class Elevator extends JavaPlugin implements Listener { getServer().getPluginManager().registerEvents(new ElevatorListener(), this); getServer().getPluginManager().registerEvents(this, this); getCommand("elevator").setExecutor(new ElevatorCommand()); + getCommand("elevator").setTabCompleter(new ElevatorTabCompleter()); // Rezept laden registerElevatorRecipe(); diff --git a/src/main/java/de/mviper/elevator/ElevatorCommand.java b/src/main/java/de/mviper/elevator/ElevatorCommand.java index 3292016..5307ff0 100644 --- a/src/main/java/de/mviper/elevator/ElevatorCommand.java +++ b/src/main/java/de/mviper/elevator/ElevatorCommand.java @@ -9,6 +9,8 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.List; + public class ElevatorCommand implements CommandExecutor { @Override @@ -17,32 +19,7 @@ public class ElevatorCommand implements CommandExecutor { Player p = (Player) sender; DatabaseManager db = Elevator.getInstance().getDatabaseManager(); - Block moduleBlock = null; - - // VERBESSERTE ERKENNUNG: Prüfe direkt unter den Füßen und erweiterten Radius - Location pLoc = p.getLocation(); - - // Erst direkt unter dem Spieler prüfen (häufigster Fall) - Block directBelow = pLoc.clone().subtract(0, 1, 0).getBlock(); - if (directBelow.getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(directBelow.getLocation())) { - moduleBlock = directBelow; - } - - // Wenn nicht gefunden, erweiterte Suche - if (moduleBlock == null) { - outerLoop: - for (double x = -1.0; x <= 1.0; x += 0.5) { - for (double z = -1.0; z <= 1.0; z += 0.5) { - for (double y = -2.0; y <= 0.5; y += 0.5) { - Block check = pLoc.clone().add(x, y, z).getBlock(); - if (check.getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(check.getLocation())) { - moduleBlock = check; - break outerLoop; - } - } - } - } - } + Block moduleBlock = findNearbyModule(p, db); if (moduleBlock == null) { p.sendMessage("§8[§bElevator§8] §cKein Aufzug-Modul in deiner Nähe gefunden!"); @@ -50,72 +27,182 @@ public class ElevatorCommand implements CommandExecutor { return true; } - // Debug-Ausgabe Location modLoc = moduleBlock.getLocation(); + if (Elevator.getInstance().isDebugMode()) { - Elevator.getInstance().getLogger().info("Command: Modul gefunden bei X:" + modLoc.getBlockX() + " Y:" + modLoc.getBlockY() + " Z:" + modLoc.getBlockZ()); + Elevator.getInstance().getLogger().info( + "Command: Modul gefunden bei X:" + modLoc.getBlockX() + + " Y:" + modLoc.getBlockY() + + " Z:" + modLoc.getBlockZ()); } - // Berechtigungs-Check (Besitzer oder Admin) - if (!db.getOwner(moduleBlock.getLocation()).equals(p.getUniqueId()) && !p.hasPermission("elevator.admin")) { + // Besitzer-Check (Besitzer oder Admin) + if (!db.getOwner(modLoc).equals(p.getUniqueId()) && !p.hasPermission("elevator.admin")) { p.sendMessage("§8[§bElevator§8] §cDies ist nicht dein Aufzug!"); return true; } - // Befehl: /elevator name + // ── /elevator name ────────────────────────────────────────── if (args.length >= 2 && args[0].equalsIgnoreCase("name")) { StringBuilder sb = new StringBuilder(); for (int i = 1; i < args.length; i++) sb.append(args[i]).append(" "); String newName = ChatColor.translateAlternateColorCodes('&', sb.toString().trim()); - - db.setFloorName(moduleBlock.getLocation(), newName); - p.sendMessage("§8[§bElevator§8] §aEtage benannt: " + newName); + + db.setFloorName(modLoc, newName); + + String groupId = db.getGroupId(modLoc); + List members = db.getMembersOfGroup(groupId); + + p.sendMessage("§8[§bElevator§8] §aEtage benannt: §f" + newName); + if (members.size() > 1) { + p.sendMessage("§7(Name für §e" + members.size() + " §7verknüpfte Module gesetzt)"); + } return true; } - // Befehle: /elevator private | public - if (args.length == 1) { - Location modLocation = moduleBlock.getLocation(); - - if (args[0].equalsIgnoreCase("private")) { - db.setPublic(modLocation, false); - p.sendMessage("§8[§bElevator§8] §7Status: §cPrivat"); - p.sendMessage("§7Nur du kannst diesen Aufzug nun benutzen."); - - // Verifizierung - boolean currentStatus = db.isPublic(modLocation); - if (Elevator.getInstance().isDebugMode()) { - p.sendMessage("§8[Debug] Aktueller Status nach Änderung: " + (currentStatus ? "§aÖffentlich" : "§cPrivat")); + // ── /elevator group ──────────────────────────────────────────────── + if (args.length >= 1 && args[0].equalsIgnoreCase("group")) { + + // /elevator group info + if (args.length == 1 || args[1].equalsIgnoreCase("info")) { + String groupId = db.getGroupId(modLoc); + List members = db.getMembersOfGroup(groupId); + p.sendMessage("§b--- Gruppen-Info ---"); + p.sendMessage("§7Gruppen-ID: §e" + groupId); + p.sendMessage("§7Gruppen-Name: §f" + db.getGroupName(groupId)); + p.sendMessage("§7Module in Gruppe: §e" + members.size()); + return true; + } + + // /elevator group scan + // Scannt benachbarte Module neu und verknüpft sie in eine Gruppe + if (args[1].equalsIgnoreCase("scan")) { + String myGroup = db.getGroupId(modLoc); + int linked = 0; + + // Radius 4 horizontal, gleiche Y-Ebene + for (int dx = -4; dx <= 4; dx++) { + for (int dz = -4; dz <= 4; dz++) { + if (dx == 0 && dz == 0) continue; + Location adj = modLoc.clone().add(dx, 0, dz); + if (db.isElevator(adj)) { + String adjGroup = db.getGroupId(adj); + if (!adjGroup.equals(myGroup)) { + db.setGroupId(adj, myGroup); + linked++; + } + } + } } + + p.sendMessage("§8[§bElevator§8] §aScan abgeschlossen."); + p.sendMessage("§7" + linked + " Modul(e) mit dieser Gruppe verknüpft."); + p.sendMessage("§7Gruppe §e" + myGroup + "§7 hat jetzt §e" + + db.getMembersOfGroup(myGroup).size() + "§7 Mitglieder."); return true; } - - if (args[0].equalsIgnoreCase("public")) { - db.setPublic(modLocation, true); - p.sendMessage("§8[§bElevator§8] §7Status: §aÖffentlich"); - p.sendMessage("§7Alle Spieler können diesen Aufzug nun benutzen."); - - // Verifizierung - boolean currentStatus = db.isPublic(modLocation); - if (Elevator.getInstance().isDebugMode()) { - p.sendMessage("§8[Debug] Aktueller Status nach Änderung: " + (currentStatus ? "§aÖffentlich" : "§cPrivat")); - } - return true; - } - - if (args[0].equalsIgnoreCase("status")) { - boolean isPublic = db.isPublic(modLocation); - p.sendMessage("§8[§bElevator§8] §7Aktueller Status: " + (isPublic ? "§aÖffentlich" : "§cPrivat")); + + // /elevator group unlink + // Trennt dieses Modul aus der Gruppe heraus (eigene Gruppe) + if (args[1].equalsIgnoreCase("unlink")) { + String oldGroup = db.getGroupId(modLoc); + String oldName = db.getGroupName(oldGroup); + + // Neue solo-Gruppe erstellen + String newGroupId = java.util.UUID.randomUUID().toString().substring(0, 8); + db.setGroupId(modLoc, newGroupId); + db.setGroupNameById(newGroupId, oldName); // Namen behalten + + p.sendMessage("§8[§bElevator§8] §eModul aus Gruppe getrennt."); + p.sendMessage("§7Neue Gruppen-ID: §e" + newGroupId); return true; } + + // Unbekannter Unterbefehl → Hilfe + sendGroupHelp(p); + return true; } - // Hilfe-Anzeige - p.sendMessage("§b--- Elevator Hilfe ---"); - p.sendMessage("§e/elevator name §7- Namen der Etage ändern"); - p.sendMessage("§e/elevator private §7- Zugriff nur für dich"); - p.sendMessage("§e/elevator public §7- Zugriff für alle"); - p.sendMessage("§e/elevator status §7- Zeigt den aktuellen Status"); + // ── /elevator private ────────────────────────────────────────────── + if (args.length == 1 && args[0].equalsIgnoreCase("private")) { + db.setPublic(modLoc, false); + p.sendMessage("§8[§bElevator§8] §7Status: §cPrivat"); + p.sendMessage("§7Nur du kannst diesen Aufzug nun benutzen."); + if (Elevator.getInstance().isDebugMode()) { + p.sendMessage("§8[Debug] Status nach Änderung: " + (db.isPublic(modLoc) ? "§aÖffentlich" : "§cPrivat")); + } + return true; + } + + // ── /elevator public ─────────────────────────────────────────────── + if (args.length == 1 && args[0].equalsIgnoreCase("public")) { + db.setPublic(modLoc, true); + p.sendMessage("§8[§bElevator§8] §7Status: §aÖffentlich"); + p.sendMessage("§7Alle Spieler können diesen Aufzug nun benutzen."); + if (Elevator.getInstance().isDebugMode()) { + p.sendMessage("§8[Debug] Status nach Änderung: " + (db.isPublic(modLoc) ? "§aÖffentlich" : "§cPrivat")); + } + return true; + } + + // ── /elevator status ─────────────────────────────────────────────── + if (args.length == 1 && args[0].equalsIgnoreCase("status")) { + boolean isPublic = db.isPublic(modLoc); + String groupId = db.getGroupId(modLoc); + p.sendMessage("§b--- Aufzug-Status ---"); + p.sendMessage("§7Sichtbarkeit: " + (isPublic ? "§aÖffentlich" : "§cPrivat")); + p.sendMessage("§7Etagen-Name: §f" + db.getGroupName(groupId)); + p.sendMessage("§7Gruppe: §e" + groupId + + " §7(§e" + db.getMembersOfGroup(groupId).size() + " §7Module)"); + return true; + } + + // ── Hilfe-Anzeige ────────────────────────────────────────────────── + sendHelp(p); return true; } + + // ───────────────────────────────────────────────────────────────────────── + // Modul-Suche (identisch mit alter Logik) + // ───────────────────────────────────────────────────────────────────────── + private Block findNearbyModule(Player p, DatabaseManager db) { + Location pLoc = p.getLocation(); + + // 1. Direkt unter den Füßen + Block directBelow = pLoc.clone().subtract(0, 1, 0).getBlock(); + if (directBelow.getType() == Material.DAYLIGHT_DETECTOR + && db.isElevator(directBelow.getLocation())) { + return directBelow; + } + + // 2. Erweiterter Radius + for (double x = -1.0; x <= 1.0; x += 0.5) { + for (double z = -1.0; z <= 1.0; z += 0.5) { + for (double y = -2.0; y <= 0.5; y += 0.5) { + Block check = pLoc.clone().add(x, y, z).getBlock(); + if (check.getType() == Material.DAYLIGHT_DETECTOR + && db.isElevator(check.getLocation())) { + return check; + } + } + } + } + return null; + } + + private void sendHelp(Player p) { + p.sendMessage("§b--- Elevator Hilfe ---"); + p.sendMessage("§e/elevator name §7- Etagen-Name setzen (für alle Module der Gruppe)"); + p.sendMessage("§e/elevator private §7- Zugriff nur für dich"); + p.sendMessage("§e/elevator public §7- Zugriff für alle"); + p.sendMessage("§e/elevator status §7- Aktuellen Status anzeigen"); + p.sendMessage("§e/elevator group §7- Gruppen-Info & Verwaltung"); + } + + private void sendGroupHelp(Player p) { + p.sendMessage("§b--- Gruppen-Befehle ---"); + p.sendMessage("§e/elevator group §7- Gruppen-Info anzeigen"); + p.sendMessage("§e/elevator group scan §7- Benachbarte Module automatisch verknüpfen"); + p.sendMessage("§e/elevator group unlink §7- Dieses Modul aus der Gruppe lösen"); + } } \ No newline at end of file diff --git a/src/main/java/de/mviper/elevator/ElevatorListener.java b/src/main/java/de/mviper/elevator/ElevatorListener.java index 0494db5..4268202 100644 --- a/src/main/java/de/mviper/elevator/ElevatorListener.java +++ b/src/main/java/de/mviper/elevator/ElevatorListener.java @@ -29,7 +29,7 @@ public class ElevatorListener implements Listener { "http://textures.minecraft.net/texture/be8440e9d54ec7630b3e387f84e19e15f0b09d438a6bd784305df5d7608e6903"; private final Map cooldowns = new HashMap<>(); - private final Map deniedMessageCooldown = new HashMap<>(); // NEU: Für "Privat"-Meldungen + private final Map deniedMessageCooldown = new HashMap<>(); @EventHandler @@ -54,21 +54,20 @@ public class ElevatorListener implements Listener { boolean isPublic = db.isPublic(elevatorLoc); boolean isOwner = db.getOwner(elevatorLoc).equals(player.getUniqueId()); boolean isAdmin = player.hasPermission("elevator.admin"); - - // Debug-Ausgabe + if (Elevator.getInstance().isDebugMode()) { Elevator.getInstance().getLogger().info("Spieler " + player.getName() + " interagiert mit Aufzug:"); Elevator.getInstance().getLogger().info(" -> Public: " + isPublic); Elevator.getInstance().getLogger().info(" -> IsOwner: " + isOwner); Elevator.getInstance().getLogger().info(" -> IsAdmin: " + isAdmin); } - + if (!isPublic && !isOwner && !isAdmin) { player.sendMessage("§8[§bElevator§8] §cDieser Aufzug ist privat!"); e.setCancelled(true); return; } - + e.setCancelled(true); openGUI(player, elevatorLoc.getBlock()); } @@ -144,13 +143,12 @@ public class ElevatorListener implements Listener { String floorLabel = (i == 0) ? "Erdgeschoss" : "Etage " + i; meta.setDisplayName((isCurrent ? "§a● " : "§b○ ") + "§l" + floorLabel); - // Lore ohne sichtbare Koordinaten, aber mit versteckter ID am Ende String customName = db.getFloorCustomName(f.getLocation()); meta.setLore(Arrays.asList( "§7Name: §f" + (customName != null ? customName : floorLabel), "", isCurrent ? "§7(Diese Etage)" : "§e➤ Klicken zum Reisen", - "§0HIDDEN:" + f.getY() // Versteckte Zeile (Schwarz auf Schwarz/Unsichtbar) + "§0HIDDEN:" + f.getY() )); item.setItemMeta(meta); @@ -172,11 +170,9 @@ public class ElevatorListener implements Listener { try { List lore = e.getCurrentItem().getItemMeta().getLore(); - // Die versteckte Koordinate steht in der letzten Zeile (Index 3) int targetY = Integer.parseInt(lore.get(3).replace("§0HIDDEN:", "")); p.closeInventory(); - // Prüfe grob, ob der Spieler auf dem Modul steht Block module = findModuleUnderPlayer(p); if (module != null) { @@ -221,21 +217,29 @@ public class ElevatorListener implements Listener { @EventHandler(priority = EventPriority.HIGH) public void onJump(PlayerMoveEvent e) { Player p = e.getPlayer(); + + // Nur bei echter Aufwärtsbewegung if (e.getTo().getY() <= e.getFrom().getY()) return; + // Cooldown prüfen if (cooldowns.containsKey(p.getUniqueId()) && System.currentTimeMillis() - cooldowns.get(p.getUniqueId()) < 300) return; Block b = findModuleUnderPlayer(p); - if (b != null) { - // Prüfe Berechtigung - if (!hasPermissionToUse(p, b)) { - sendDeniedMessage(p); - return; - } - - cooldowns.put(p.getUniqueId(), System.currentTimeMillis()); - handleQuickMove(p, 1); + if (b == null) return; + + // FIX: Prüfe, ob der Spieler in FROM wirklich AUF dem Elevator stand. + // Steht er korrekt drauf: FROM.Y ≈ elevator.getY() + 1.0 + // Läuft er von einer Halbstufe drüber: FROM.Y ≈ elevator.getY() + 0.5 + // → Der Schritt von der Halbstufe wird dadurch zuverlässig ignoriert. + double expectedStandingY = b.getY() + 1.0; + if (e.getFrom().getY() < expectedStandingY - 0.1) return; + + if (!hasPermissionToUse(p, b)) { + sendDeniedMessage(p); + return; } + cooldowns.put(p.getUniqueId(), System.currentTimeMillis()); + handleQuickMove(p, 1); } @EventHandler(priority = EventPriority.MONITOR) @@ -247,22 +251,28 @@ public class ElevatorListener implements Listener { Block b = findModuleUnderPlayer(p); if (b != null) { - // Prüfe Berechtigung if (!hasPermissionToUse(p, b)) { sendDeniedMessage(p); return; } - + cooldowns.put(p.getUniqueId(), System.currentTimeMillis()); handleQuickMove(p, -1); } } - // Hilfsmethode für grobe Erkennung (überall im Listener genutzt) + // Prüft das Modul unter dem Spieler (aktuelle Position) private Block findModuleUnderPlayer(Player p) { + return findModuleUnderLocation(p.getLocation()); + } + + /** + * FIX: Neue Hilfsmethode, die eine beliebige Location prüft. + * Wird in onJump für die FROM-Position genutzt, um Halbstufen-Schritte + * von echten Sprüngen zu unterscheiden. + */ + private Block findModuleUnderLocation(Location l) { DatabaseManager db = Elevator.getInstance().getDatabaseManager(); - Location l = p.getLocation(); - // Check Fußblock und Block darunter Block feet = l.getBlock(); if (feet.getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(feet.getLocation())) return feet; Block below = feet.getRelative(0, -1, 0); @@ -274,28 +284,24 @@ public class ElevatorListener implements Listener { private boolean hasPermissionToUse(Player p, Block elevatorBlock) { DatabaseManager db = Elevator.getInstance().getDatabaseManager(); Location loc = elevatorBlock.getLocation(); - + boolean isPublic = db.isPublic(loc); boolean isOwner = db.getOwner(loc).equals(p.getUniqueId()); boolean isAdmin = p.hasPermission("elevator.admin"); - + return isPublic || isOwner || isAdmin; } - + // Sendet "Privat"-Meldung nur, wenn Cooldown abgelaufen ist private void sendDeniedMessage(Player p) { UUID playerId = p.getUniqueId(); long now = System.currentTimeMillis(); - - // Prüfe ob Cooldown aktiv ist (3 Sekunden) + if (deniedMessageCooldown.containsKey(playerId)) { long lastMessage = deniedMessageCooldown.get(playerId); - if (now - lastMessage < 3000) { - return; // Cooldown noch aktiv, keine Nachricht senden - } + if (now - lastMessage < 3000) return; } - - // Sende Nachricht und setze Cooldown + p.sendMessage("§8[§bElevator§8] §cDieser Aufzug ist privat!"); deniedMessageCooldown.put(playerId, now); } @@ -350,22 +356,13 @@ public class ElevatorListener implements Listener { private void showVisualFeedback(Player p, Block targetBlock) { DatabaseManager db = Elevator.getInstance().getDatabaseManager(); - - // Hole benutzerdefinierten Namen + String customName = db.getFloorCustomName(targetBlock.getLocation()); - - // Falls ein Custom Name existiert, benutze diesen, sonst Fallback + if (customName != null && !customName.isEmpty() && !customName.equals("Etage")) { - // Benutzer hat einen eigenen Namen vergeben p.sendTitle("", "§b" + customName, 5, 25, 5); - - // Optional: Zeige auch ein Hologramm - Elevator.getInstance().getHologramManager().spawnElevatorHolo( - p.getLocation(), - customName - ); + Elevator.getInstance().getHologramManager().spawnElevatorHolo(p.getLocation(), customName); } else { - // Standard: Etagen-Nummer anzeigen List floors = findFloorsInColumn(targetBlock); floors.sort(Comparator.comparingInt(Block::getY)); @@ -379,12 +376,7 @@ public class ElevatorListener implements Listener { String label = (floorIndex <= 0) ? "Erdgeschoss" : "Etage " + floorIndex; p.sendTitle("", "§b" + label, 5, 25, 5); - - // Optional: Zeige auch ein Hologramm - Elevator.getInstance().getHologramManager().spawnElevatorHolo( - p.getLocation(), - label - ); + Elevator.getInstance().getHologramManager().spawnElevatorHolo(p.getLocation(), label); } } diff --git a/src/main/java/de/mviper/elevator/ElevatorTabCompleter.java b/src/main/java/de/mviper/elevator/ElevatorTabCompleter.java new file mode 100644 index 0000000..75b5fa7 --- /dev/null +++ b/src/main/java/de/mviper/elevator/ElevatorTabCompleter.java @@ -0,0 +1,129 @@ +package de.mviper.elevator; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class ElevatorTabCompleter implements TabCompleter { + + // Alle Top-Level Unterbefehle + private static final List SUBCOMMANDS = Arrays.asList( + "name", "group", "private", "public", "status" + ); + + // Unterbefehle von /elevator group + private static final List GROUP_SUBCOMMANDS = Arrays.asList( + "info", "scan", "unlink" + ); + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + if (!(sender instanceof Player)) return Collections.emptyList(); + Player p = (Player) sender; + + // args.length == 1 → Hauptbefehl-Vorschläge + if (args.length == 1) { + return filter(SUBCOMMANDS, args[0]); + } + + // args.length == 2 → zweite Ebene + if (args.length == 2) { + switch (args[0].toLowerCase()) { + + case "group": + return filter(GROUP_SUBCOMMANDS, args[1]); + + case "name": + // Vorschlag: aktueller Etagen-Name als Platzhalter + String currentName = getCurrentFloorName(p); + return currentName != null + ? filter(Collections.singletonList(currentName), args[1]) + : Collections.emptyList(); + + // private / public / status haben keine weiteren Argumente + default: + return Collections.emptyList(); + } + } + + // args.length >= 3 → drittes+ Argument + if (args.length >= 3 && args[0].equalsIgnoreCase("name")) { + // Wörter-Eingabe — aktuellen Namen als Gesamtvorschlag anbieten + String currentName = getCurrentFloorName(p); + if (currentName != null) { + // Prüfen ob bisherige Eingabe zum Namen passt + String typed = String.join(" ", Arrays.copyOfRange(args, 1, args.length)); + if (currentName.toLowerCase().startsWith(typed.toLowerCase())) { + // Nur das nächste fehlende Wort vorschlagen + String[] nameParts = currentName.split(" "); + int wordIndex = args.length - 1; + if (wordIndex < nameParts.length) { + return Collections.singletonList(nameParts[wordIndex]); + } + } + } + return Collections.emptyList(); + } + + return Collections.emptyList(); + } + + /** + * Gibt den aktuellen Etagen-Namen des Moduls zurück, auf dem der Spieler steht. + * Null, wenn kein Modul gefunden. + */ + private String getCurrentFloorName(Player p) { + DatabaseManager db = Elevator.getInstance().getDatabaseManager(); + Block module = findModuleUnderPlayer(p, db); + if (module == null) return null; + + String groupId = db.getGroupId(module.getLocation()); + if (groupId == null) return null; + + String name = db.getGroupName(groupId); + return (name != null && !name.isEmpty() && !name.equals("Etage")) ? name : null; + } + + /** Modul direkt unter dem Spieler suchen (spiegelt Logik aus ElevatorCommand). */ + private Block findModuleUnderPlayer(Player p, DatabaseManager db) { + org.bukkit.Location pLoc = p.getLocation(); + + Block directBelow = pLoc.clone().subtract(0, 1, 0).getBlock(); + if (directBelow.getType() == Material.DAYLIGHT_DETECTOR + && db.isElevator(directBelow.getLocation())) { + return directBelow; + } + + for (double x = -1.0; x <= 1.0; x += 0.5) { + for (double z = -1.0; z <= 1.0; z += 0.5) { + for (double y = -2.0; y <= 0.5; y += 0.5) { + Block check = pLoc.clone().add(x, y, z).getBlock(); + if (check.getType() == Material.DAYLIGHT_DETECTOR + && db.isElevator(check.getLocation())) { + return check; + } + } + } + } + return null; + } + + /** Filtert eine Liste nach dem bereits getippten Prefix (case-insensitive). */ + private List filter(List options, String typed) { + if (typed == null || typed.isEmpty()) return new ArrayList<>(options); + List result = new ArrayList<>(); + String lower = typed.toLowerCase(); + for (String s : options) { + if (s.toLowerCase().startsWith(lower)) result.add(s); + } + return result; + } +} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index b781821..0d2057f 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: Elevator -version: 1.6 +version: 1.8 main: de.mviper.elevator.Elevator api-version: 1.20 author: mviper