mdbd/src/main/java/dev/loki/hook/HookHologram.java
2026-06-10 23:00:12 +02:00

141 lines
5.1 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package dev.loki.hook;
import dev.loki.mdbd;
import org.bukkit.Location;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Display;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.TextDisplay;
import org.bukkit.scheduler.BukkitTask;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Floating labels above hooks showing their status.
* Uses TextDisplay (Paper 1.19.4+) with ArmorStand fallback for older versions.
*/
public class HookHologram {
private final mdbd plugin;
private final HookManager manager;
private final Map<UUID, Object> displays = new HashMap<>(); // TextDisplay or ArmorStand
private BukkitTask task;
private boolean useTextDisplay;
public HookHologram(mdbd plugin, HookManager manager) {
this.plugin = plugin;
this.manager = manager;
this.useTextDisplay = isTextDisplayAvailable();
}
private static boolean isTextDisplayAvailable() {
try {
EntityType.valueOf("TEXT_DISPLAY");
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
public void start() {
stop();
spawnAll();
task = plugin.getServer().getScheduler().runTaskTimer(plugin, this::refresh, 20L, 20L);
plugin.getLogger().info("[HookHologram] Started with " + displays.size() + " holograms (mode=" + (useTextDisplay ? "TextDisplay" : "ArmorStand") + ")");
}
public void stop() {
if (task != null) {
task.cancel();
task = null;
}
for (Object display : displays.values()) {
if (display instanceof TextDisplay td && td.isValid()) {
td.remove();
} else if (display instanceof ArmorStand as && as.isValid()) {
as.remove();
}
}
displays.clear();
}
private void spawnAll() {
double heightOffset = plugin.getConfigManager().getGame().getHookHologramHeightOffset();
int index = 0;
for (Hook hook : manager.getAllHooks()) {
Location loc = hook.getLocation();
if (loc.getWorld() == null) {
plugin.getLogger().warning("[HookHologram] Hook " + hook.getId() + " has null world, skipping");
continue;
}
Location holoLoc = loc.clone().add(0.5, 2.5 + heightOffset, 0.5);
try {
if (useTextDisplay) {
TextDisplay display = loc.getWorld().spawn(holoLoc, TextDisplay.class, d -> {
d.setBillboard(Display.Billboard.VERTICAL);
d.setSeeThrough(true);
d.setShadowed(true);
d.setDefaultBackground(false);
d.setPersistent(false);
d.setTextOpacity((byte) -1);
d.setViewRange(128.0f);
});
displays.put(hook.getId(), display);
} else {
ArmorStand stand = loc.getWorld().spawn(holoLoc, ArmorStand.class, as -> {
as.setInvisible(true);
as.setInvulnerable(true);
as.setGravity(false);
as.setMarker(true);
as.setCustomNameVisible(true);
as.setPersistent(false);
});
displays.put(hook.getId(), stand);
}
} catch (Exception e) {
plugin.getLogger().warning("[HookHologram] Failed to spawn hologram for hook " + hook.getId() + ": " + e.getMessage());
}
index++;
}
}
private void refresh() {
int total = manager.getAllHooks().size();
int visibleIndex = 0;
for (Hook hook : manager.getAllHooks()) {
Object display = displays.get(hook.getId());
if (display == null) continue;
boolean valid = (display instanceof TextDisplay td && td.isValid()) ||
(display instanceof ArmorStand as && as.isValid());
if (!valid) continue;
String status;
if (hook.isDisabled()) {
status = "§c✂ Саботирован";
} else if (hook.isOccupied()) {
int pct = (int) hook.getStageProgressPercent();
status = "§4Занят [" + hook.getCurrentStage().name() + " " + pct + "%]";
} else {
status = "§aСвободен";
}
visibleIndex++;
String text = "§c⚓ Крюк §f#" + visibleIndex + "/" + total + "\n§7" + status;
double heightOffset = plugin.getConfigManager().getGame().getHookHologramHeightOffset();
Location base = hook.getLocation().clone().add(0.5, 2.5 + heightOffset, 0.5);
if (display instanceof TextDisplay td) {
td.text(net.kyori.adventure.text.Component.text(text));
td.teleport(base);
} else if (display instanceof ArmorStand as) {
as.setCustomName(text);
as.teleport(base);
}
}
}
}