Files
NexusLobby/src/main/java/de/nexuslobby/modules/hologram/HologramModule.java
2026-04-18 08:39:58 +02:00

221 lines
8.2 KiB
Java

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.Entity;
import org.bukkit.entity.Interaction;
import org.bukkit.entity.Player;
import org.bukkit.entity.TextDisplay;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
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());
// Render-Task: Prüft alle 5 Ticks Sichtbarkeit und Placeholder-Updates
Bukkit.getScheduler().runTaskTimer(NexusLobby.getInstance(), () -> {
for (Player player : Bukkit.getOnlinePlayers()) {
holograms.values().forEach(h -> h.renderForPlayer(player));
}
}, 20L, 5L);
}
private void loadConfig() {
file = new File(NexusLobby.getInstance().getDataFolder(), "holograms.yml");
config = YamlConfiguration.loadConfiguration(file);
}
private void loadHolograms() {
// Vorherige Instanzen säubern
holograms.values().forEach(NexusHologram::removeAll);
holograms.clear();
for (String id : config.getKeys(false)) {
String worldName = config.getString(id + ".world");
if (worldName == null) continue;
World world = Bukkit.getWorld(worldName);
if (world == null) continue;
Location loc = new Location(world,
config.getDouble(id + ".x"),
config.getDouble(id + ".y"),
config.getDouble(id + ".z"));
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) {
// Nur auf Interaction-Entities reagieren (Hologramm-Hitboxen)
if (!(event.getRightClicked() instanceof Interaction)) return;
for (NexusHologram holo : holograms.values()) {
if (holo.isInteractionEntity(event.getRightClicked().getUniqueId())) {
holo.nextPage(event.getPlayer());
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 Entity-Reste, die eventuell noch in der Welt schweben
Bukkit.getScheduler().runTaskLater(NexusLobby.getInstance(), () -> {
Player p = event.getPlayer();
for (Entity entity : p.getWorld().getEntities()) {
if (entity.getCustomName() != null && entity.getCustomName().startsWith("nexus_h_")) {
// Wenn das Hologramm nicht exakt für diesen Spieler benannt ist -> verstecken
if (!entity.getCustomName().endsWith("_" + p.getName())) {
p.hideEntity(NexusLobby.getInstance(), entity);
}
}
}
}, 10L);
}
public void createHologram(String id, Location loc, List<String> pages) {
// Falls ID bereits existiert, altes Hologramm sauber entfernen
if (holograms.containsKey(id)) {
removeHologram(id);
}
config.set(id + ".world", loc.getWorld().getName());
config.set(id + ".x", loc.getX());
config.set(id + ".y", loc.getY());
config.set(id + ".z", loc.getZ());
config.set(id + ".text", pages);
saveHoloConfig();
NexusHologram holo = new NexusHologram(id, loc, pages);
holograms.put(id, holo);
}
public void removeHologram(String id) {
NexusHologram holo = holograms.remove(id);
if (holo != null) {
// Erst für alle Spieler visuell entfernen
for (Player player : Bukkit.getOnlinePlayers()) {
holo.removeForPlayer(player);
}
// Dann Entities serverseitig löschen
holo.removeAll();
}
config.set(id, null);
saveHoloConfig();
}
/**
* Lädt die holograms.yml neu und rendert alle Hologramme für Online-Spieler neu.
* Wird von HoloCommand (/holo reload) aufgerufen.
*/
public void reloadHolograms() {
// Alle aktiven Hologramme für alle Spieler entfernen
for (Player player : Bukkit.getOnlinePlayers()) {
holograms.values().forEach(h -> h.removeForPlayer(player));
}
// Config neu einlesen und Hologramme neu laden
loadConfig();
loadHolograms();
}
private void saveHoloConfig() {
try {
// Sicherstellen, dass Placeholder-Strings (z.B. %bungeetotal%) korrekt
// gequotet gespeichert werden, damit SnakeYAML sie nicht als YAML-Direktive
// missinterpretiert. Dazu speichern wir die text-Listen explizit als
// String-Werte mit einfachen Anführungszeichen via eigener Serialisierung.
StringBuilder yaml = new StringBuilder();
for (String id : config.getKeys(false)) {
yaml.append(id).append(":\n");
yaml.append(" world: ").append(quoteIfNeeded(config.getString(id + ".world", ""))).append("\n");
yaml.append(" x: ").append(config.getDouble(id + ".x")).append("\n");
yaml.append(" y: ").append(config.getDouble(id + ".y")).append("\n");
yaml.append(" z: ").append(config.getDouble(id + ".z")).append("\n");
yaml.append(" text:\n");
for (String line : config.getStringList(id + ".text")) {
yaml.append(" - ").append(quoteIfNeeded(line)).append("\n");
}
}
java.nio.file.Files.writeString(file.toPath(), yaml.toString());
} catch (IOException e) {
NexusLobby.getInstance().getLogger().severe("Konnte holograms.yml nicht speichern!");
NexusLobby.getInstance().getLogger().severe("Fehler beim Speichern der Hologramme: " + e.getMessage());
}
}
/**
* Umschließt Strings mit einfachen Anführungszeichen, wenn sie YAML-Sonderzeichen
* wie '%', ':', '#' enthalten, um Parsing-Fehler zu vermeiden.
*/
private String quoteIfNeeded(String value) {
if (value == null) return "''";
if (value.contains("%") || value.contains(":") || value.contains("#") || value.contains("'")) {
return "'" + value.replace("'", "''") + "'";
}
return value;
}
/**
* WICHTIG: Diese Methode wird vom LobbyTabCompleter benötigt!
* @return Set aller registrierten Hologramm-IDs
*/
public Set<String> getHologramIds() {
return holograms.keySet();
}
@Override
public void onDisable() {
org.bukkit.event.HandlerList.unregisterAll(this);
holograms.values().forEach(NexusHologram::removeAll);
holograms.clear();
}
}