365 lines
16 KiB
Java
365 lines
16 KiB
Java
package de.nexuslobby.modules.intro;
|
|
|
|
import de.nexuslobby.NexusLobby;
|
|
import de.nexuslobby.api.Module;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.GameMode;
|
|
import org.bukkit.Location;
|
|
import org.bukkit.command.Command;
|
|
import org.bukkit.command.CommandExecutor;
|
|
import org.bukkit.command.CommandSender;
|
|
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.PlayerJoinEvent;
|
|
import org.bukkit.scheduler.BukkitRunnable;
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.util.*;
|
|
|
|
public class IntroModule implements Module, Listener, CommandExecutor {
|
|
|
|
private final Set<UUID> activeIntro = new HashSet<>();
|
|
|
|
private final List<Location> points = new ArrayList<>();
|
|
private final List<String> labels = new ArrayList<>();
|
|
|
|
// Abschluss-Titel (konfigurierbar)
|
|
private String endTitle = "§a§lWillkommen!";
|
|
private String endSubtitle = "§7Viel Spaß auf NexusLobby";
|
|
|
|
private File configFile;
|
|
private FileConfiguration config;
|
|
|
|
// --- Einstellungen ---
|
|
private final int TICKS_FLUG = 70;
|
|
private final int TICKS_PAUSE = 30;
|
|
|
|
private final int TITLE_FADE_IN = 10;
|
|
private final int TITLE_STAY = 50;
|
|
private final int TITLE_FADE_OUT = 10;
|
|
|
|
@Override
|
|
public String getName() { return "Intro"; }
|
|
|
|
@Override
|
|
public void onEnable() {
|
|
Bukkit.getPluginManager().registerEvents(this, NexusLobby.getInstance());
|
|
if (NexusLobby.getInstance().getCommand("intro") != null) {
|
|
NexusLobby.getInstance().getCommand("intro").setExecutor(this);
|
|
}
|
|
loadConfig();
|
|
}
|
|
|
|
@Override
|
|
public void onDisable() {
|
|
org.bukkit.event.HandlerList.unregisterAll(this);
|
|
activeIntro.clear();
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────
|
|
// Persistenz
|
|
// ─────────────────────────────────────────────────────────────────────────
|
|
|
|
private void loadConfig() {
|
|
points.clear();
|
|
labels.clear();
|
|
configFile = new File(NexusLobby.getInstance().getDataFolder(), "intro.yml");
|
|
if (!configFile.exists()) {
|
|
try { configFile.createNewFile(); } catch (IOException ignored) {}
|
|
}
|
|
config = YamlConfiguration.loadConfiguration(configFile);
|
|
|
|
// Abschluss-Titel laden
|
|
endTitle = config.getString("end-title", "§a§lWillkommen!");
|
|
endSubtitle = config.getString("end-subtitle", "§7Viel Spaß auf NexusLobby");
|
|
|
|
// Punkte laden
|
|
List<?> list = config.getList("intro-points");
|
|
if (list != null) {
|
|
for (Object obj : list) {
|
|
if (obj instanceof Map<?, ?> map) {
|
|
Object locObj = map.get("location");
|
|
Object labelObj = map.get("label");
|
|
if (locObj instanceof Location loc) {
|
|
points.add(loc);
|
|
labels.add(labelObj != null ? labelObj.toString() : "");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Rückwärts-Kompatibilität
|
|
if (points.isEmpty()) {
|
|
List<?> oldList = config.getList("points");
|
|
if (oldList != null) {
|
|
for (Object obj : oldList) {
|
|
if (obj instanceof Location loc) {
|
|
points.add(loc);
|
|
labels.add("");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void saveConfig() {
|
|
// Abschluss-Titel speichern
|
|
config.set("end-title", endTitle);
|
|
config.set("end-subtitle", endSubtitle);
|
|
|
|
// Punkte speichern
|
|
List<Map<String, Object>> data = new ArrayList<>();
|
|
for (int i = 0; i < points.size(); i++) {
|
|
Map<String, Object> entry = new LinkedHashMap<>();
|
|
entry.put("location", points.get(i));
|
|
entry.put("label", labels.get(i));
|
|
data.add(entry);
|
|
}
|
|
config.set("intro-points", data);
|
|
config.set("points", null);
|
|
|
|
try {
|
|
config.save(configFile);
|
|
} catch (IOException e) {
|
|
NexusLobby.getInstance().getLogger().severe("Fehler beim Speichern der Intro-Config: " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────
|
|
// Events
|
|
// ─────────────────────────────────────────────────────────────────────────
|
|
|
|
@EventHandler
|
|
public void onJoin(PlayerJoinEvent event) {
|
|
if (!event.getPlayer().hasPlayedBefore() && points.size() >= 2) {
|
|
startIntro(event.getPlayer());
|
|
}
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────
|
|
// Befehle
|
|
// ─────────────────────────────────────────────────────────────────────────
|
|
|
|
@Override
|
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
|
|
if (!(sender instanceof Player p)) return true;
|
|
if (!p.hasPermission("nexuslobby.admin")) return true;
|
|
|
|
if (args.length == 0) {
|
|
sendHelp(p);
|
|
return true;
|
|
}
|
|
|
|
switch (args[0].toLowerCase()) {
|
|
|
|
case "add" -> {
|
|
String pointLabel = args.length > 1
|
|
? String.join(" ", Arrays.copyOfRange(args, 1, args.length))
|
|
: "";
|
|
points.add(p.getLocation());
|
|
labels.add(pointLabel);
|
|
saveConfig();
|
|
if (pointLabel.isEmpty()) {
|
|
p.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§aPunkt §e#" + points.size() + " §awurde gesetzt.");
|
|
} else {
|
|
p.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§aPunkt §e#" + points.size() + " §amit Text §e\"" + pointLabel + "\" §agesetzt.");
|
|
}
|
|
}
|
|
|
|
case "clear" -> {
|
|
points.clear();
|
|
labels.clear();
|
|
saveConfig();
|
|
p.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§cAlle Intro-Punkte wurden gelöscht.");
|
|
}
|
|
|
|
case "list" -> {
|
|
if (points.isEmpty()) {
|
|
p.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§cKeine Punkte vorhanden.");
|
|
return true;
|
|
}
|
|
p.sendMessage("§8§m------------------------------------");
|
|
p.sendMessage("§6§lIntro-Punkte (" + points.size() + ")");
|
|
for (int i = 0; i < points.size(); i++) {
|
|
Location loc = points.get(i);
|
|
String lbl = labels.get(i).isEmpty() ? "§7(kein Text)" : "§e" + labels.get(i);
|
|
p.sendMessage("§8#" + (i + 1) + " §7"
|
|
+ String.format("%.1f", loc.getX()) + ", "
|
|
+ String.format("%.1f", loc.getY()) + ", "
|
|
+ String.format("%.1f", loc.getZ())
|
|
+ " " + lbl);
|
|
}
|
|
p.sendMessage("§8§m------------------------------------");
|
|
}
|
|
|
|
case "start" -> {
|
|
if (points.size() < 2) {
|
|
p.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§cDu brauchst mindestens 2 Punkte für eine Fahrt.");
|
|
} else {
|
|
startIntro(p);
|
|
}
|
|
}
|
|
|
|
// /intro setendtitle <Text> — setzt den großen Abschluss-Titel
|
|
case "setendtitle" -> {
|
|
if (args.length < 2) {
|
|
p.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§cBenutzung: §e/intro setendtitle <Text>");
|
|
p.sendMessage("§7Farbcodes mit §e& §7möglich. Beispiel: §e/intro setendtitle &a&lWillkommen!");
|
|
return true;
|
|
}
|
|
endTitle = colorize(String.join(" ", Arrays.copyOfRange(args, 1, args.length)));
|
|
saveConfig();
|
|
p.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§aAbschluss-Titel gesetzt: " + endTitle);
|
|
// Vorschau
|
|
p.sendTitle(endTitle, endSubtitle, TITLE_FADE_IN, TITLE_STAY, TITLE_FADE_OUT);
|
|
}
|
|
|
|
// /intro setendsubtitle <Text> — setzt den kleinen Abschluss-Untertitel
|
|
case "setendsubtitle" -> {
|
|
if (args.length < 2) {
|
|
p.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§cBenutzung: §e/intro setendsubtitle <Text>");
|
|
p.sendMessage("§7Farbcodes mit §e& §7möglich. Beispiel: §e/intro setendsubtitle &7Viel Spaß!");
|
|
return true;
|
|
}
|
|
endSubtitle = colorize(String.join(" ", Arrays.copyOfRange(args, 1, args.length)));
|
|
saveConfig();
|
|
p.sendMessage(de.nexuslobby.utils.LangManager.getPrefix() + "§aAbschluss-Untertitel gesetzt: " + endSubtitle);
|
|
// Vorschau
|
|
p.sendTitle(endTitle, endSubtitle, TITLE_FADE_IN, TITLE_STAY, TITLE_FADE_OUT);
|
|
}
|
|
|
|
default -> sendHelp(p);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void sendHelp(Player p) {
|
|
p.sendMessage("§8§m------------------------------------");
|
|
p.sendMessage("§6§lNexus Intro System (Cinematic)");
|
|
p.sendMessage("§e/intro add [Text] §7- Punkt + optionaler Titel");
|
|
p.sendMessage("§e/intro clear §7- Alle Punkte löschen");
|
|
p.sendMessage("§e/intro list §7- Alle Punkte anzeigen");
|
|
p.sendMessage("§e/intro start §7- Fahrt testen");
|
|
p.sendMessage("§e/intro setendtitle <Text> §7- Abschluss-Titel setzen");
|
|
p.sendMessage("§e/intro setendsubtitle <Text> §7- Abschluss-Untertitel setzen");
|
|
p.sendMessage("§7Aktuell: §r" + endTitle + " §8/ §r" + endSubtitle);
|
|
p.sendMessage("§8§m------------------------------------");
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────
|
|
// Intro-Logik
|
|
// ─────────────────────────────────────────────────────────────────────────
|
|
|
|
public void startIntro(Player player) {
|
|
activeIntro.add(player.getUniqueId());
|
|
player.setGameMode(GameMode.SPECTATOR);
|
|
|
|
// Titel für den ersten Punkt sofort anzeigen
|
|
showTitleForSegment(player, 0);
|
|
|
|
new BukkitRunnable() {
|
|
int currentSegment = 0;
|
|
int tickInSegment = 0;
|
|
boolean isPausing = true;
|
|
int lastTitleSegment = 0;
|
|
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
if (!player.isOnline() || !activeIntro.contains(player.getUniqueId())) {
|
|
this.cancel();
|
|
return;
|
|
}
|
|
|
|
if (currentSegment >= points.size() - 1) {
|
|
stopIntro(player);
|
|
this.cancel();
|
|
return;
|
|
}
|
|
|
|
Location start = points.get(currentSegment);
|
|
Location end = points.get(currentSegment + 1);
|
|
|
|
if (isPausing) {
|
|
player.teleport(start);
|
|
tickInSegment++;
|
|
if (tickInSegment >= TICKS_PAUSE) {
|
|
isPausing = false;
|
|
tickInSegment = 0;
|
|
}
|
|
} else {
|
|
double progress = (double) tickInSegment / (double) TICKS_FLUG;
|
|
double smoothT = progress * progress * (3 - 2 * progress);
|
|
|
|
player.teleport(interpolate(start, end, smoothT));
|
|
|
|
tickInSegment++;
|
|
if (tickInSegment >= TICKS_FLUG) {
|
|
isPausing = true;
|
|
tickInSegment = 0;
|
|
currentSegment++;
|
|
|
|
if (currentSegment < points.size() && currentSegment != lastTitleSegment) {
|
|
showTitleForSegment(player, currentSegment);
|
|
lastTitleSegment = currentSegment;
|
|
}
|
|
}
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
this.cancel();
|
|
stopIntro(player);
|
|
}
|
|
}
|
|
}.runTaskTimer(NexusLobby.getInstance(), 0L, 1L);
|
|
}
|
|
|
|
private void showTitleForSegment(Player player, int segmentIndex) {
|
|
if (segmentIndex < 0 || segmentIndex >= labels.size()) return;
|
|
String lbl = labels.get(segmentIndex);
|
|
if (lbl == null || lbl.isEmpty()) return;
|
|
|
|
player.sendTitle(
|
|
"§6§l" + lbl,
|
|
"§7✦ NexusLobby ✦",
|
|
TITLE_FADE_IN,
|
|
TITLE_STAY,
|
|
TITLE_FADE_OUT
|
|
);
|
|
}
|
|
|
|
private Location interpolate(Location start, Location end, double t) {
|
|
double x = start.getX() + (end.getX() - start.getX()) * t;
|
|
double y = start.getY() + (end.getY() - start.getY()) * t;
|
|
double z = start.getZ() + (end.getZ() - start.getZ()) * t;
|
|
|
|
float startYaw = start.getYaw();
|
|
float endYaw = end.getYaw();
|
|
float diff = (endYaw - startYaw) % 360;
|
|
if (diff > 180) diff -= 360;
|
|
if (diff < -180) diff += 360;
|
|
float yaw = startYaw + diff * (float) t;
|
|
float pitch = (float) (start.getPitch() + (end.getPitch() - start.getPitch()) * t);
|
|
|
|
return new Location(start.getWorld(), x, y, z, yaw, pitch);
|
|
}
|
|
|
|
private void stopIntro(Player player) {
|
|
activeIntro.remove(player.getUniqueId());
|
|
player.setGameMode(GameMode.ADVENTURE);
|
|
player.teleport(player.getWorld().getSpawnLocation());
|
|
|
|
// Abschluss-Titel — komplett konfigurierbar
|
|
player.sendTitle(endTitle, endSubtitle, 10, 60, 20);
|
|
}
|
|
|
|
/** Ersetzt &-Farbcodes durch §-Codes */
|
|
private String colorize(String input) {
|
|
return input.replace("&", "§");
|
|
}
|
|
} |