141 lines
5.1 KiB
Java
141 lines
5.1 KiB
Java
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);
|
||
}
|
||
}
|
||
}
|
||
}
|