Files
VelocityFall/src/main/java/de/velocityfall/manager/GameManager.java
2026-02-01 22:36:30 +01:00

422 lines
17 KiB
Java

package de.velocityfall.manager;
import de.velocityfall.VelocityFall;
import de.velocityfall.utils.ScoreboardHelper;
import de.velocityfall.utils.StatsHandler;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Player;
import org.bukkit.inventory.meta.FireworkMeta;
import org.bukkit.FireworkEffect;
import org.bukkit.Color;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class GameManager {
/* ---------------------------------------------------
* GAME START COUNTDOWN
* --------------------------------------------------- */
public static void startArenaCountdown(String arenaName) {
final VelocityFall plugin = VelocityFall.getInstance();
if (plugin == null) return;
if (plugin.getGameStartedMap().getOrDefault(arenaName, false)) return;
new BukkitRunnable() {
int timeLeft = plugin.getConfig().getInt("BeforeGameCD", 15);
@Override
public void run() {
int playerCount = (int) plugin.getPlayerArenaMap().values()
.stream().filter(arenaName::equals).count();
if (playerCount < 1) {
cancel();
return;
}
if (timeLeft <= 5 && timeLeft > 0) {
broadcast(arenaName, "§aSpiel startet in §e" + timeLeft + "...");
}
if (timeLeft <= 0) {
plugin.getGameStartedMap().put(arenaName, true);
plugin.getArenaPlayersCountMap().put(arenaName, playerCount);
plugin.getSignManager().updateSign(arenaName);
broadcast(arenaName, "§6§lDAS SPIEL BEGINNT!");
Location spawn = plugin.getArenaManager()
.getArenaConfig().getLocation("Arenas." + arenaName + ".Spawn");
// PLAYED Stats erhöhen für alle Spieler
plugin.getPlayerArenaMap().forEach((p, a) -> {
if (arenaName.equals(a)) {
// Stats tracken
StatsHandler.addPlayed(p.getUniqueId().toString());
// Teleport & Setup
if (spawn != null) p.teleport(spawn);
p.setGameMode(GameMode.ADVENTURE);
p.setAllowFlight(false);
p.playSound(p.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 1f, 1f);
// Scoreboard auf InGame umschalten
try {
ScoreboardHelper.updateBoard(p, arenaName, true);
} catch (Exception e) {
plugin.getLogger().warning("Scoreboard Update fehlgeschlagen: " + e.getMessage());
}
}
});
cancel();
}
timeLeft--;
}
}.runTaskTimer(plugin, 0L, 20L);
}
public static void startCountdown(String arenaName) {
startArenaCountdown(arenaName);
}
/* ---------------------------------------------------
* WIN HANDLING - MIT STATS TRACKING
* --------------------------------------------------- */
public static void checkForWinner(String arenaName) {
final VelocityFall plugin = VelocityFall.getInstance();
if (plugin == null) return;
int remaining = plugin.getArenaPlayersCountMap().getOrDefault(arenaName, 0);
if (remaining != 1) return;
// 1) Gewinner finden (Nicht-Spectator)
Player winner = plugin.getPlayerArenaMap().entrySet().stream()
.filter(e -> arenaName.equals(e.getValue()))
.map(Map.Entry::getKey)
.filter(p -> p.getGameMode() != GameMode.SPECTATOR)
.findFirst()
.orElse(null);
// Fallback
if (winner == null) {
List<Player> arenaPlayers = VelocityFall.getArenaPlayers(arenaName);
for (Player p : arenaPlayers) {
if (p != null && p.getGameMode() != GameMode.SPECTATOR) {
winner = p;
break;
}
}
}
if (winner == null) return;
final Player finalWinner = winner;
// 2) Lose-Location ermitteln
Location loseLocation = findLoseLocation(arenaName);
final Location finalLoseLocation = loseLocation;
// 3) Verlierer sammeln (alle Spectators)
List<Player> losers = new ArrayList<>();
plugin.getPlayerArenaMap().forEach((p, a) -> {
if (arenaName.equals(a) && !p.equals(finalWinner) && p.getGameMode() == GameMode.SPECTATOR) {
losers.add(p);
}
});
final List<Player> finalLosers = new ArrayList<>(losers);
// 4) STATS TRACKING - GEWINNER
try {
StatsHandler.addWin(finalWinner.getUniqueId().toString());
} catch (Exception e) {
plugin.getLogger().warning("Win-Stats konnten nicht gespeichert werden: " + e.getMessage());
}
// 5) STATS TRACKING - VERLIERER
for (Player loser : finalLosers) {
try {
StatsHandler.addLose(loser.getUniqueId().toString());
} catch (Exception e) {
plugin.getLogger().warning("Lose-Stats konnten nicht gespeichert werden: " + e.getMessage());
}
}
// 6) GEWINNER VORBEREITEN
try {
finalWinner.setAllowFlight(true);
finalWinner.setFlying(true);
Location winnerSafeLoc = plugin.getArenaManager()
.getArenaConfig().getLocation("Arenas." + arenaName + ".Spawn");
if (winnerSafeLoc != null) {
finalWinner.teleport(winnerSafeLoc);
}
finalWinner.sendMessage(VelocityFall.prefix + ChatColor.translateAlternateColorCodes('&',
plugin.getMessages().getMessagesConfig().getString("WinMessage", "&aDu hast gewonnen!")));
finalWinner.sendTitle(
ChatColor.translateAlternateColorCodes('&', "&6&lSIEG!"),
ChatColor.translateAlternateColorCodes('&', "&eDu hast gewonnen!"),
10, 70, 20
);
finalWinner.playSound(finalWinner.getLocation(), Sound.UI_TOAST_CHALLENGE_COMPLETE, 1f, 1f);
ScoreboardHelper.clearBoard(finalWinner);
} catch (Exception e) {
plugin.getLogger().warning("Gewinner-Setup fehlgeschlagen: " + e.getMessage());
}
// 7) VERLIERER BENACHRICHTIGEN
for (Player loser : finalLosers) {
try {
if (finalLoseLocation != null && loser.getGameMode() == GameMode.SPECTATOR) {
loser.teleport(finalLoseLocation);
}
loser.sendTitle(
ChatColor.translateAlternateColorCodes('&', "&c&lNIEDERLAGE"),
ChatColor.translateAlternateColorCodes('&', "&e" + finalWinner.getName() + " &7hat gewonnen!"),
10, 70, 20
);
loser.playSound(loser.getLocation(), Sound.ENTITY_VILLAGER_NO, 1f, 1f);
ScoreboardHelper.clearBoard(loser);
} catch (Exception e) {
plugin.getLogger().warning("Verlierer-Setup fehlgeschlagen: " + e.getMessage());
}
}
// 8) FEUERWERK MIT DELAY
int delaySeconds = plugin.getConfig().getInt("PostWinDelay", 4);
delaySeconds = Math.min(5, Math.max(3, delaySeconds));
final long delayTicks = delaySeconds * 20L;
new BukkitRunnable() {
int fireworksSpawned = 0;
@Override
public void run() {
if (fireworksSpawned < 5) {
try {
spawnFireworks(finalWinner.getLocation().clone().add(0, 1, 0), 1);
finalWinner.playSound(finalWinner.getLocation(), Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 1f, 1f);
for (Player loser : finalLosers) {
if (loser != null && loser.isOnline()) {
loser.playSound(loser.getLocation(), Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 1f, 1f);
}
}
} catch (Exception e) {
plugin.getLogger().warning("Feuerwerk-Spawn fehlgeschlagen: " + e.getMessage());
}
fireworksSpawned++;
} else {
cancel();
// Nach Feuerwerk: Arena resetten
Bukkit.getScheduler().runTaskLater(plugin, () -> {
try {
performSafeResetAndLobbyTeleport(arenaName, finalWinner, finalLosers);
} catch (Exception e) {
plugin.getLogger().severe("Arena-Reset fehlgeschlagen: " + e.getMessage());
}
try {
plugin.ingameArenas.remove(arenaName);
plugin.getSignManager().updateSign(arenaName);
} catch (Exception ignored) {}
}, 40L);
}
}
}.runTaskTimer(plugin, delayTicks, 10L);
}
/* ---------------------------------------------------
* LOSE LOCATION FINDER - HELPER
* --------------------------------------------------- */
private static Location findLoseLocation(String arenaName) {
final VelocityFall plugin = VelocityFall.getInstance();
if (plugin == null) return null;
var arenaConfig = plugin.getArenaManager().getArenaConfig();
// Verschiedene mögliche Keys probieren
Location loseLocation = arenaConfig.getLocation("Arenas." + arenaName + ".Lose");
if (loseLocation == null) loseLocation = arenaConfig.getLocation("Arenas." + arenaName + ".LoseLocation");
if (loseLocation == null) loseLocation = arenaConfig.getLocation("Arenas." + arenaName + ".LosePoint");
if (loseLocation == null) loseLocation = arenaConfig.getLocation("Arenas." + arenaName + ".SetLose");
// YLose Fallback
if (loseLocation == null) {
Double yLose = arenaConfig.getDouble("Arenas." + arenaName + ".YLose", Double.NaN);
if (!yLose.isNaN()) {
Location spawn = arenaConfig.getLocation("Arenas." + arenaName + ".Spawn");
Location lobby = arenaConfig.getLocation("Arenas." + arenaName + ".Lobby");
if (spawn != null) {
loseLocation = spawn.clone();
loseLocation.setY(yLose);
} else if (lobby != null) {
loseLocation = lobby.clone();
loseLocation.setY(yLose);
} else {
Location pos1 = arenaConfig.getLocation("Arenas." + arenaName + ".Pos1");
Location pos2 = arenaConfig.getLocation("Arenas." + arenaName + ".Pos2");
if (pos1 != null && pos2 != null && pos1.getWorld() != null && pos1.getWorld().equals(pos2.getWorld())) {
double midX = (pos1.getX() + pos2.getX()) / 2.0;
double midZ = (pos1.getZ() + pos2.getZ()) / 2.0;
loseLocation = new Location(pos1.getWorld(), midX, yLose, midZ, 0f, 0f);
}
}
}
}
return loseLocation;
}
/* ---------------------------------------------------
* SAFE RESET & LOBBY TELEPORT
* --------------------------------------------------- */
private static void performSafeResetAndLobbyTeleport(String arenaName, Player winner, List<Player> losers) {
final VelocityFall plugin = VelocityFall.getInstance();
if (plugin == null) return;
// Blöcke zurücksetzen
plugin.getArenaBlocksMap().forEach((block, matName) -> {
try {
block.setType(Material.valueOf(matName));
} catch (Exception e) {
plugin.getLogger().warning("Block-Reset fehlgeschlagen: " + e.getMessage());
}
});
plugin.getArenaBlocksMap().clear();
// Spielzustand zurücksetzen
plugin.getGameStartedMap().put(arenaName, false);
plugin.getArenaPlayersCountMap().remove(arenaName);
// Lobby-Location
Location lobby = plugin.getArenaManager().getArenaConfig().getLocation("Arenas." + arenaName + ".Lobby");
// Alle Spieler sammeln
List<Player> toHandle = new ArrayList<>();
if (winner != null) toHandle.add(winner);
for (Player loser : losers) {
if (loser != null && !toHandle.contains(loser)) {
toHandle.add(loser);
}
}
// Sicherheit: Alle aus playerArenaMap
plugin.getPlayerArenaMap().forEach((p, a) -> {
if (arenaName.equals(a) && !toHandle.contains(p)) {
toHandle.add(p);
}
});
// Alle Spieler resetten
for (Player p : toHandle) {
try {
p.setGameMode(GameMode.SURVIVAL);
p.setAllowFlight(false);
p.setFlying(false);
p.getInventory().clear();
p.getInventory().setArmorContents(null);
p.setHealth(20.0);
p.setFoodLevel(20);
p.resetTitle();
ScoreboardHelper.clearBoard(p);
if (lobby != null) {
p.teleport(lobby);
} else {
Location spawn = plugin.getArenaManager().getArenaConfig().getLocation("Arenas." + arenaName + ".Spawn");
if (spawn != null) {
p.teleport(spawn);
} else if (p.getWorld() != null) {
p.teleport(p.getWorld().getSpawnLocation());
}
}
plugin.ingamePlayers.remove(p);
plugin.getPlayerArenaMap().remove(p);
} catch (Exception e) {
plugin.getLogger().warning("Spieler-Reset fehlgeschlagen für " + p.getName() + ": " + e.getMessage());
}
}
// FloorLoseListener cleanup
try {
if (plugin.getFloorLoseListener() != null) {
plugin.getFloorLoseListener().clearLostPlayers();
}
} catch (Exception ignored) {}
// Signs updaten
try {
plugin.getSignManager().updateSign(arenaName);
} catch (Exception ignored) {}
}
/* ---------------------------------------------------
* FIREWORKS
* --------------------------------------------------- */
private static void spawnFireworks(Location loc, int count) {
if (loc == null || loc.getWorld() == null) return;
for (int i = 0; i < Math.max(1, count); i++) {
try {
Firework fw = loc.getWorld().spawn(loc.clone().add(0, i * 0.5, 0), Firework.class);
FireworkMeta meta = fw.getFireworkMeta();
Color[] colors = {Color.LIME, Color.YELLOW, Color.ORANGE, Color.RED, Color.AQUA, Color.FUCHSIA};
Color randomColor1 = colors[(int)(Math.random() * colors.length)];
Color randomColor2 = colors[(int)(Math.random() * colors.length)];
FireworkEffect effect = FireworkEffect.builder()
.with(FireworkEffect.Type.BALL_LARGE)
.withColor(randomColor1, randomColor2)
.withFade(Color.WHITE)
.trail(true)
.flicker(true)
.build();
meta.addEffect(effect);
meta.setPower(1);
fw.setFireworkMeta(meta);
} catch (Throwable t) {
VelocityFall.getInstance().getLogger().warning("Firework-Spawn fehlgeschlagen: " + t.getMessage());
}
}
}
/* ---------------------------------------------------
* BROADCAST
* --------------------------------------------------- */
private static void broadcast(String arena, String msg) {
final VelocityFall plugin = VelocityFall.getInstance();
if (plugin == null) return;
plugin.getPlayerArenaMap().forEach((player, a) -> {
if (arena.equals(a)) {
player.sendMessage(VelocityFall.prefix + msg);
}
});
}
}