Update from Git Manager GUI
This commit is contained in:
@@ -4,37 +4,47 @@ import de.velocityfall.commands.VelocityCommand;
|
|||||||
import de.velocityfall.listeners.*;
|
import de.velocityfall.listeners.*;
|
||||||
import de.velocityfall.manager.*;
|
import de.velocityfall.manager.*;
|
||||||
import de.velocityfall.utils.*;
|
import de.velocityfall.utils.*;
|
||||||
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class VelocityFall extends JavaPlugin {
|
public class VelocityFall extends JavaPlugin implements Listener {
|
||||||
|
|
||||||
private static VelocityFall instance;
|
private static volatile VelocityFall instance;
|
||||||
public static VelocityFall getInstance() { return instance; }
|
|
||||||
|
public static VelocityFall getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
public static String prefix;
|
public static String prefix;
|
||||||
public static String noperms;
|
public static String noperms;
|
||||||
|
|
||||||
// Spiel-Daten
|
// ===== SPIEL-DATEN - THREAD-SAFE COLLECTIONS =====
|
||||||
public ArrayList<Player> ingamePlayers = new ArrayList<>();
|
public ArrayList<Player> ingamePlayers = new ArrayList<>();
|
||||||
public HashMap<String, Integer> arenaPlayersCount = new HashMap<>();
|
public ConcurrentHashMap<String, Integer> arenaPlayersCount = new ConcurrentHashMap<>();
|
||||||
public HashMap<Player, String> playerArena = new HashMap<>();
|
public ConcurrentHashMap<Player, String> playerArena = new ConcurrentHashMap<>();
|
||||||
public ArrayList<String> ingameArenas = new ArrayList<>();
|
public ArrayList<String> ingameArenas = new ArrayList<>();
|
||||||
public HashMap<String, Boolean> cdstarted = new HashMap<>();
|
public ConcurrentHashMap<String, Boolean> cdstarted = new ConcurrentHashMap<>();
|
||||||
public HashMap<String, Integer> arenaCountdown = new HashMap<>();
|
public ConcurrentHashMap<String, Integer> arenaCountdown = new ConcurrentHashMap<>();
|
||||||
public HashMap<Block, String> arenaBlocks = new HashMap<>();
|
public ConcurrentHashMap<Block, String> arenaBlocks = new ConcurrentHashMap<>();
|
||||||
public HashMap<String, Boolean> gameStarted = new HashMap<>();
|
public ConcurrentHashMap<String, Boolean> gameStarted = new ConcurrentHashMap<>();
|
||||||
public ArrayList<Player> cooldown = new ArrayList<>();
|
public ArrayList<Player> cooldown = new ArrayList<>();
|
||||||
public HashMap<Player, String> spectators = new HashMap<>();
|
public ConcurrentHashMap<Player, String> spectators = new ConcurrentHashMap<>();
|
||||||
public HashMap<Player, Integer> checkint = new HashMap<>();
|
public ConcurrentHashMap<Player, Integer> checkint = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
// Manager
|
// ===== MANAGER =====
|
||||||
private ArenaManager arenaManager;
|
private ArenaManager arenaManager;
|
||||||
private JoinManager joinManager;
|
private JoinManager joinManager;
|
||||||
private SignManager signManager;
|
private SignManager signManager;
|
||||||
@@ -44,9 +54,14 @@ public class VelocityFall extends JavaPlugin {
|
|||||||
private Stats stats;
|
private Stats stats;
|
||||||
private DisableReset disablereset;
|
private DisableReset disablereset;
|
||||||
|
|
||||||
// Listener-Referenzen (für GameManager-Zugriff)
|
// ===== LISTENER-REFERENZEN =====
|
||||||
private FloorLoseListener floorLoseListener;
|
private FloorLoseListener floorLoseListener;
|
||||||
|
|
||||||
|
// ===== UPDATE CHECKER DATEN =====
|
||||||
|
private String latestVersionFound;
|
||||||
|
private final int RESOURCE_ID = 132255;
|
||||||
|
private final String releaseUrl = "https://www.spigotmc.org/resources/" + RESOURCE_ID;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
instance = this;
|
instance = this;
|
||||||
@@ -55,8 +70,11 @@ public class VelocityFall extends JavaPlugin {
|
|||||||
getConfig().options().copyDefaults(true);
|
getConfig().options().copyDefaults(true);
|
||||||
saveConfig();
|
saveConfig();
|
||||||
|
|
||||||
prefix = ChatColor.translateAlternateColorCodes('&', getConfig().getString("Prefix", "&6Velocity&fFall &8» "));
|
// Encoding-Fixed: Korrekte Umlaute
|
||||||
noperms = ChatColor.translateAlternateColorCodes('&', getConfig().getString("NoPermission", "&cKeine Rechte!"));
|
prefix = ChatColor.translateAlternateColorCodes('&',
|
||||||
|
getConfig().getString("Prefix", "&6Velocity&fFall &8» "));
|
||||||
|
noperms = ChatColor.translateAlternateColorCodes('&',
|
||||||
|
getConfig().getString("NoPermission", "&cKeine Rechte!"));
|
||||||
|
|
||||||
ConfigManager.initializeFiles(this);
|
ConfigManager.initializeFiles(this);
|
||||||
|
|
||||||
@@ -79,9 +97,9 @@ public class VelocityFall extends JavaPlugin {
|
|||||||
getCommand("velocityfall").setExecutor(new VelocityCommand(this));
|
getCommand("velocityfall").setExecutor(new VelocityCommand(this));
|
||||||
|
|
||||||
// Listener registrieren
|
// Listener registrieren
|
||||||
|
Bukkit.getPluginManager().registerEvents(this, this);
|
||||||
Bukkit.getPluginManager().registerEvents(new FloorListener(this), this);
|
Bukkit.getPluginManager().registerEvents(new FloorListener(this), this);
|
||||||
|
|
||||||
// FloorLoseListener mit Referenz speichern (für GameManager)
|
|
||||||
this.floorLoseListener = new FloorLoseListener(this);
|
this.floorLoseListener = new FloorLoseListener(this);
|
||||||
Bukkit.getPluginManager().registerEvents(floorLoseListener, this);
|
Bukkit.getPluginManager().registerEvents(floorLoseListener, this);
|
||||||
|
|
||||||
@@ -89,9 +107,44 @@ public class VelocityFall extends JavaPlugin {
|
|||||||
Bukkit.getPluginManager().registerEvents(new SetupListener(this), this);
|
Bukkit.getPluginManager().registerEvents(new SetupListener(this), this);
|
||||||
Bukkit.getPluginManager().registerEvents(new SignListener(this), this);
|
Bukkit.getPluginManager().registerEvents(new SignListener(this), this);
|
||||||
|
|
||||||
|
// Update Check starten
|
||||||
|
checkForUpdates();
|
||||||
|
|
||||||
getLogger().info("VelocityFall aktiviert – Version " + getDescription().getVersion());
|
getLogger().info("VelocityFall aktiviert – Version " + getDescription().getVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkForUpdates() {
|
||||||
|
new UpdateChecker(this, RESOURCE_ID).getLatestVersion(version -> {
|
||||||
|
this.latestVersionFound = version;
|
||||||
|
if (!this.getDescription().getVersion().equalsIgnoreCase(version)) {
|
||||||
|
getLogger().warning("====================================================");
|
||||||
|
getLogger().warning("[VelocityFall] Eine neue Version ist verfügbar: v" + version);
|
||||||
|
getLogger().warning("[VelocityFall] Download: " + releaseUrl);
|
||||||
|
getLogger().warning("====================================================");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (player.hasPermission("velocityfall.admin") || player.isOp()) {
|
||||||
|
if (latestVersionFound != null && !this.getDescription().getVersion().equalsIgnoreCase(latestVersionFound)) {
|
||||||
|
player.sendMessage(" ");
|
||||||
|
player.sendMessage(prefix + "§eEine neue Version (§b" + latestVersionFound + "§e) ist verfügbar!");
|
||||||
|
|
||||||
|
TextComponent message = new TextComponent(prefix + "§eDownload: ");
|
||||||
|
TextComponent link = new TextComponent("§6§l[KLICK HIER]");
|
||||||
|
link.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, releaseUrl));
|
||||||
|
link.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("§7Öffnet die Spigot-Seite")));
|
||||||
|
|
||||||
|
message.addExtra(link);
|
||||||
|
player.spigot().sendMessage(message);
|
||||||
|
player.sendMessage(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setupMySQL() {
|
private void setupMySQL() {
|
||||||
var cfg = stats.getStatsConfig();
|
var cfg = stats.getStatsConfig();
|
||||||
String host = cfg.getString("MySQL.HOST", "localhost");
|
String host = cfg.getString("MySQL.HOST", "localhost");
|
||||||
@@ -114,8 +167,12 @@ public class VelocityFall extends JavaPlugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
if (disablereset != null) disablereset.disableReset();
|
if (disablereset != null) {
|
||||||
if (mysqlConnector != null) mysqlConnector.close();
|
disablereset.disableReset();
|
||||||
|
}
|
||||||
|
if (mysqlConnector != null) {
|
||||||
|
mysqlConnector.close();
|
||||||
|
}
|
||||||
getLogger().info("VelocityFall deaktiviert");
|
getLogger().info("VelocityFall deaktiviert");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +198,7 @@ public class VelocityFall extends JavaPlugin {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manager-Getter
|
// ===== MANAGER-GETTER =====
|
||||||
public ArenaManager getArenaManager() { return arenaManager; }
|
public ArenaManager getArenaManager() { return arenaManager; }
|
||||||
public JoinManager getJoinManager() { return joinManager; }
|
public JoinManager getJoinManager() { return joinManager; }
|
||||||
public SignManager getSignManager() { return signManager; }
|
public SignManager getSignManager() { return signManager; }
|
||||||
@@ -149,13 +206,11 @@ public class VelocityFall extends JavaPlugin {
|
|||||||
public Configs getConfigs() { return configs; }
|
public Configs getConfigs() { return configs; }
|
||||||
public Messages getMessages() { return messages; }
|
public Messages getMessages() { return messages; }
|
||||||
public Stats getStats() { return stats; }
|
public Stats getStats() { return stats; }
|
||||||
|
|
||||||
// Listener-Getter (für GameManager)
|
|
||||||
public FloorLoseListener getFloorLoseListener() { return floorLoseListener; }
|
public FloorLoseListener getFloorLoseListener() { return floorLoseListener; }
|
||||||
|
|
||||||
// Map-Getter
|
// ===== MAP-GETTER =====
|
||||||
public HashMap<Player, String> getPlayerArenaMap() { return playerArena; }
|
public ConcurrentHashMap<Player, String> getPlayerArenaMap() { return playerArena; }
|
||||||
public HashMap<String, Integer> getArenaPlayersCountMap() { return arenaPlayersCount; }
|
public ConcurrentHashMap<String, Integer> getArenaPlayersCountMap() { return arenaPlayersCount; }
|
||||||
public HashMap<String, Boolean> getGameStartedMap() { return gameStarted; }
|
public ConcurrentHashMap<String, Boolean> getGameStartedMap() { return gameStarted; }
|
||||||
public HashMap<Block, String> getArenaBlocksMap() { return arenaBlocks; }
|
public ConcurrentHashMap<Block, String> getArenaBlocksMap() { return arenaBlocks; }
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package de.velocityfall.commands;
|
|||||||
|
|
||||||
import de.velocityfall.VelocityFall;
|
import de.velocityfall.VelocityFall;
|
||||||
import de.velocityfall.manager.GameManager;
|
import de.velocityfall.manager.GameManager;
|
||||||
|
import de.velocityfall.utils.ScoreboardHelper;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
@@ -35,7 +36,7 @@ public class VelocityCommand implements CommandExecutor {
|
|||||||
|
|
||||||
String action = args[0].toLowerCase();
|
String action = args[0].toLowerCase();
|
||||||
|
|
||||||
// --- Spieler-Befehle ---
|
// === SPIELER-BEFEHLE ===
|
||||||
|
|
||||||
if (action.equals("join") && args.length == 2) {
|
if (action.equals("join") && args.length == 2) {
|
||||||
plugin.getJoinManager().join(p, args[1]);
|
plugin.getJoinManager().join(p, args[1]);
|
||||||
@@ -49,30 +50,28 @@ public class VelocityCommand implements CommandExecutor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entfernen aus Registern
|
|
||||||
plugin.getPlayerArenaMap().remove(p);
|
plugin.getPlayerArenaMap().remove(p);
|
||||||
plugin.ingamePlayers.remove(p);
|
plugin.ingamePlayers.remove(p);
|
||||||
|
|
||||||
// Zähler dekrementieren
|
|
||||||
plugin.getArenaPlayersCountMap().compute(arena, (k, v) -> Math.max(0, (v == null ? 0 : v) - 1));
|
plugin.getArenaPlayersCountMap().compute(arena, (k, v) -> Math.max(0, (v == null ? 0 : v) - 1));
|
||||||
|
|
||||||
// Siegprüfung (korrekt über GameManager)
|
|
||||||
GameManager.checkForWinner(arena);
|
GameManager.checkForWinner(arena);
|
||||||
|
|
||||||
// Reset Spieler
|
|
||||||
p.teleport(p.getWorld().getSpawnLocation());
|
p.teleport(p.getWorld().getSpawnLocation());
|
||||||
p.setGameMode(GameMode.SURVIVAL);
|
p.setGameMode(GameMode.SURVIVAL);
|
||||||
p.setAllowFlight(false);
|
p.setAllowFlight(false);
|
||||||
p.setFlying(false);
|
p.setFlying(false);
|
||||||
p.getInventory().clear();
|
p.getInventory().clear();
|
||||||
|
|
||||||
|
ScoreboardHelper.clearBoard(p);
|
||||||
|
|
||||||
p.sendMessage(VelocityFall.prefix + "§eArena verlassen.");
|
p.sendMessage(VelocityFall.prefix + "§eArena verlassen.");
|
||||||
|
|
||||||
plugin.getSignManager().updateSign(arena);
|
plugin.getSignManager().updateSign(arena);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Admin-Befehle ---
|
// === ADMIN-BEFEHLE ===
|
||||||
|
|
||||||
if (!p.hasPermission("velocityfall.admin")) {
|
if (!p.hasPermission("velocityfall.admin")) {
|
||||||
p.sendMessage(VelocityFall.prefix + "§cKeine Rechte.");
|
p.sendMessage(VelocityFall.prefix + "§cKeine Rechte.");
|
||||||
@@ -95,7 +94,7 @@ public class VelocityCommand implements CommandExecutor {
|
|||||||
wand.setItemMeta(meta);
|
wand.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
p.getInventory().addItem(wand);
|
p.getInventory().addItem(wand);
|
||||||
p.sendMessage(VelocityFall.prefix + "§aSetup-Wand erhalten! Nutze Links-/Rechtsklick auf Blöcke.");
|
p.sendMessage(VelocityFall.prefix + "§aSetup-Wand erhalten!");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "savearea":
|
case "savearea":
|
||||||
@@ -184,13 +183,13 @@ public class VelocityCommand implements CommandExecutor {
|
|||||||
if (p.hasPermission("velocityfall.admin")) {
|
if (p.hasPermission("velocityfall.admin")) {
|
||||||
p.sendMessage("§6Admin-Befehle:");
|
p.sendMessage("§6Admin-Befehle:");
|
||||||
p.sendMessage("§6/vfall wand §7- Setup-Wand holen");
|
p.sendMessage("§6/vfall wand §7- Setup-Wand holen");
|
||||||
p.sendMessage("§6/vfall create <Name> §7- Arena erstellen");
|
p.sendMessage("§6/vfall create <n> §7- Arena erstellen");
|
||||||
p.sendMessage("§6/vfall savearea <Name> §7- Bereich speichern");
|
p.sendMessage("§6/vfall savearea <n> §7- Bereich speichern");
|
||||||
p.sendMessage("§6/vfall setlobby <Name> §7- Lobby setzen");
|
p.sendMessage("§6/vfall setlobby <n> §7- Lobby setzen");
|
||||||
p.sendMessage("§6/vfall setspawn <Name> §7- Spawn setzen");
|
p.sendMessage("§6/vfall setspawn <n> §7- Spawn setzen");
|
||||||
p.sendMessage("§6/vfall setlose <Name> §7- Verlust-Höhe setzen");
|
p.sendMessage("§6/vfall setlose <n> §7- Verlust-Höhe setzen");
|
||||||
p.sendMessage("§6/vfall setmax <Name> <Zahl> §7- Max-Spieler setzen");
|
p.sendMessage("§6/vfall setmax <n> <Zahl> §7- Max-Spieler setzen");
|
||||||
p.sendMessage("§6/vfall start <Name> §7- Spiel sofort starten");
|
p.sendMessage("§6/vfall start <n> §7- Spiel sofort starten");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,12 +9,13 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class FloorListener implements Listener {
|
public class FloorListener implements Listener {
|
||||||
private final VelocityFall plugin;
|
private final VelocityFall plugin;
|
||||||
private final Set<Block> blocksInProcess = new HashSet<>();
|
// THREAD-SAFE: ConcurrentHashMap.newKeySet() statt HashSet
|
||||||
|
private final Set<Block> blocksInProcess = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
public FloorListener(VelocityFall plugin) {
|
public FloorListener(VelocityFall plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
@@ -29,21 +30,29 @@ public class FloorListener implements Listener {
|
|||||||
if (!plugin.ingamePlayers.contains(p)) continue;
|
if (!plugin.ingamePlayers.contains(p)) continue;
|
||||||
|
|
||||||
String arena = plugin.getPlayerArenaMap().get(p);
|
String arena = plugin.getPlayerArenaMap().get(p);
|
||||||
if (arena == null || !plugin.getGameStartedMap().getOrDefault(arena, false)) continue;
|
if (arena == null) continue;
|
||||||
|
|
||||||
|
// Nur wenn Spiel läuft UND Spieler nicht Spectator
|
||||||
|
if (!plugin.getGameStartedMap().getOrDefault(arena, false)) continue;
|
||||||
|
if (p.getGameMode() == GameMode.SPECTATOR) continue;
|
||||||
|
|
||||||
|
// Nur Adventure/Survival Spieler
|
||||||
if (p.getGameMode() != GameMode.ADVENTURE && p.getGameMode() != GameMode.SURVIVAL) continue;
|
if (p.getGameMode() != GameMode.ADVENTURE && p.getGameMode() != GameMode.SURVIVAL) continue;
|
||||||
|
|
||||||
Block b = p.getLocation().subtract(0, 0.1, 0).getBlock();
|
Block b = p.getLocation().subtract(0, 0.1, 0).getBlock();
|
||||||
|
|
||||||
if (b.getType() == Material.AIR || blocksInProcess.contains(b)) continue;
|
if (b.getType() == Material.AIR) continue;
|
||||||
|
|
||||||
|
// THREAD-SAFE: putIfAbsent() ist atomar
|
||||||
|
if (!blocksInProcess.add(b)) continue;
|
||||||
|
|
||||||
if (plugin.getArenaManager().isInArenaRegion(arena, b.getLocation())) {
|
if (plugin.getArenaManager().isInArenaRegion(arena, b.getLocation())) {
|
||||||
blocksInProcess.add(b);
|
|
||||||
|
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||||
updateBlock(b);
|
updateBlock(b);
|
||||||
blocksInProcess.remove(b);
|
blocksInProcess.remove(b);
|
||||||
}, 10L); // 0.5 Sekunden Delay
|
}, 10L); // 0.5 Sekunden Delay
|
||||||
|
} else {
|
||||||
|
blocksInProcess.remove(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,9 +71,8 @@ public class FloorListener implements Listener {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (next != null) {
|
if (next != null) {
|
||||||
if (!plugin.getArenaBlocksMap().containsKey(b)) {
|
// Originalblock merken (falls noch nicht vorhanden)
|
||||||
plugin.getArenaBlocksMap().put(b, current.name());
|
plugin.getArenaBlocksMap().putIfAbsent(b, current.name());
|
||||||
}
|
|
||||||
|
|
||||||
b.setType(next);
|
b.setType(next);
|
||||||
|
|
||||||
|
|||||||
@@ -3,27 +3,24 @@ package de.velocityfall.listeners;
|
|||||||
import de.velocityfall.VelocityFall;
|
import de.velocityfall.VelocityFall;
|
||||||
import de.velocityfall.manager.GameManager;
|
import de.velocityfall.manager.GameManager;
|
||||||
import de.velocityfall.utils.ScoreboardHelper;
|
import de.velocityfall.utils.ScoreboardHelper;
|
||||||
import de.velocityfall.utils.StatsHandler;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerMoveEvent;
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class FloorLoseListener implements Listener {
|
public class FloorLoseListener implements Listener {
|
||||||
|
|
||||||
private final VelocityFall plugin;
|
private final VelocityFall plugin;
|
||||||
// Tracking: welche Spieler bereits als "verloren" markiert wurden
|
// THREAD-SAFE: ConcurrentHashMap.newKeySet() statt HashSet
|
||||||
private final Set<Player> alreadyLost = new HashSet<>();
|
private final Set<Player> alreadyLost = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
public FloorLoseListener(VelocityFall plugin) {
|
public FloorLoseListener(VelocityFall plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
@@ -59,21 +56,20 @@ public class FloorLoseListener implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Markiert Spieler als "verloren" - reduziert nur den Counter, entfernt ihn aber
|
* Markiert Spieler als "verloren" - reduziert nur den Counter
|
||||||
* NICHT aus playerArenaMap oder ingamePlayers (das macht später der GameManager)
|
* THREAD-SAFE durch ConcurrentHashMap.newKeySet()
|
||||||
*/
|
*/
|
||||||
private void markPlayerAsLost(Player p, String arena) {
|
private void markPlayerAsLost(Player p, String arena) {
|
||||||
// Verhindere Mehrfach-Verarbeitung
|
// Verhindere Mehrfach-Verarbeitung (atomar durch ConcurrentHashSet)
|
||||||
if (alreadyLost.contains(p)) return;
|
if (!alreadyLost.add(p)) return;
|
||||||
alreadyLost.add(p);
|
|
||||||
|
|
||||||
var arenaPlayersCountMap = plugin.getArenaPlayersCountMap();
|
var arenaPlayersCountMap = plugin.getArenaPlayersCountMap();
|
||||||
|
|
||||||
// Lose-Nachricht
|
// Lose-Nachricht
|
||||||
p.sendMessage(VelocityFall.prefix + ChatColor.translateAlternateColorCodes('&',
|
String loseMsg = plugin.getMessages().getMessagesConfig().getString("LoseMessage", "&cDu bist rausgefallen!");
|
||||||
plugin.getMessages().getMessagesConfig().getString("LoseMessage", "&cDu bist rausgefallen!")));
|
p.sendMessage(VelocityFall.prefix + ChatColor.translateAlternateColorCodes('&', loseMsg));
|
||||||
|
|
||||||
// Setze Spieler sofort in Spectator, damit er nicht weiter interagieren kann
|
// Setze Spieler sofort in Spectator
|
||||||
p.setGameMode(GameMode.SPECTATOR);
|
p.setGameMode(GameMode.SPECTATOR);
|
||||||
|
|
||||||
// Counter reduzieren (wichtig für checkForWinner)
|
// Counter reduzieren (wichtig für checkForWinner)
|
||||||
@@ -81,32 +77,35 @@ public class FloorLoseListener implements Listener {
|
|||||||
|
|
||||||
// Scoreboard leeren
|
// Scoreboard leeren
|
||||||
try {
|
try {
|
||||||
p.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard());
|
ScoreboardHelper.clearBoard(p);
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().warning("Scoreboard Clear fehlgeschlagen: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
// Scoreboard für andere updaten
|
// Scoreboard für andere updaten
|
||||||
try {
|
try {
|
||||||
ScoreboardHelper.updateAllInArena(arena, true);
|
ScoreboardHelper.updateAllInArena(arena, true);
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().warning("Scoreboard Update fehlgeschlagen: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
// Sign updaten
|
// Sign updaten
|
||||||
try {
|
try {
|
||||||
plugin.getSignManager().updateSign(arena);
|
plugin.getSignManager().updateSign(arena);
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().warning("Sign Update fehlgeschlagen: " + e.getMessage());
|
||||||
// WICHTIG: Spieler bleibt in ingamePlayers und playerArenaMap!
|
}
|
||||||
// Er wird erst in performSafeResetAndLobbyTeleport entfernt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup-Methode für den GameManager - wird nach Arena-Reset aufgerufen
|
* Cleanup-Methode für den GameManager
|
||||||
*/
|
*/
|
||||||
public void clearLostPlayers() {
|
public void clearLostPlayers() {
|
||||||
alreadyLost.clear();
|
alreadyLost.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gibt die Menge der verlorenen Spieler zurück (für GameManager)
|
* Gibt eine Kopie der verlorenen Spieler zurück
|
||||||
*/
|
*/
|
||||||
public Set<Player> getAlreadyLost() {
|
public Set<Player> getAlreadyLost() {
|
||||||
return new HashSet<>(alreadyLost);
|
return new HashSet<>(alreadyLost);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.velocityfall.listeners;
|
package de.velocityfall.listeners;
|
||||||
|
|
||||||
import de.velocityfall.VelocityFall;
|
import de.velocityfall.VelocityFall;
|
||||||
|
import de.velocityfall.utils.ScoreboardHelper;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@@ -25,9 +26,13 @@ public class GameListener implements Listener {
|
|||||||
|
|
||||||
if (plugin.ingamePlayers.contains(p)) {
|
if (plugin.ingamePlayers.contains(p)) {
|
||||||
plugin.ingamePlayers.remove(p);
|
plugin.ingamePlayers.remove(p);
|
||||||
|
plugin.getPlayerArenaMap().remove(p);
|
||||||
|
|
||||||
var countMap = plugin.getArenaPlayersCountMap();
|
var countMap = plugin.getArenaPlayersCountMap();
|
||||||
countMap.compute(arena, (k, v) -> Math.max(0, (v == null ? 0 : v) - 1));
|
countMap.compute(arena, (k, v) -> Math.max(0, (v == null ? 0 : v) - 1));
|
||||||
|
|
||||||
|
ScoreboardHelper.clearBoard(p);
|
||||||
|
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||||
de.velocityfall.manager.GameManager.checkForWinner(arena);
|
de.velocityfall.manager.GameManager.checkForWinner(arena);
|
||||||
}, 1L);
|
}, 1L);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.velocityfall.listeners;
|
package de.velocityfall.listeners;
|
||||||
|
|
||||||
import de.velocityfall.VelocityFall;
|
import de.velocityfall.VelocityFall;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.block.Sign;
|
import org.bukkit.block.Sign;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
@@ -19,7 +20,7 @@ public class SignListener implements Listener {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
public void onSignChange(SignChangeEvent e) {
|
public void onSignChange(SignChangeEvent e) {
|
||||||
String line0 = e.getLine(0);
|
String line0 = e.getLine(0);
|
||||||
if (line0 == null || !(line0.equalsIgnoreCase("[VelocityFall]") || line0.equalsIgnoreCase("[LKF]"))) return;
|
if (line0 == null || !(line0.equalsIgnoreCase("[VelocityFall]") || line0.equalsIgnoreCase("[VF]"))) return;
|
||||||
|
|
||||||
String arenaName = e.getLine(1);
|
String arenaName = e.getLine(1);
|
||||||
if (arenaName == null || arenaName.trim().isEmpty()) return;
|
if (arenaName == null || arenaName.trim().isEmpty()) return;
|
||||||
@@ -55,8 +56,8 @@ public class SignListener implements Listener {
|
|||||||
|
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
|
|
||||||
String arenaName = sign.getLine(1).replaceAll("§.", "");
|
String arenaName = ChatColor.stripColor(sign.getLine(1));
|
||||||
if (arenaName.trim().isEmpty()) return;
|
if (arenaName == null || arenaName.trim().isEmpty()) return;
|
||||||
|
|
||||||
plugin.getJoinManager().join(e.getPlayer(), arenaName);
|
plugin.getJoinManager().join(e.getPlayer(), arenaName);
|
||||||
plugin.getSignManager().updateSign(arenaName);
|
plugin.getSignManager().updateSign(arenaName);
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public class ArenaManager {
|
|||||||
arenaConfig.set(path + "Pos2", pos2);
|
arenaConfig.set(path + "Pos2", pos2);
|
||||||
arenaConfig.set(path + "World", pos1.getWorld().getName());
|
arenaConfig.set(path + "World", pos1.getWorld().getName());
|
||||||
|
|
||||||
// Automatisch MinY berechnen und speichern (wichtig für mehrstöckige Arenen)
|
// Automatisch MinY berechnen und speichern
|
||||||
double minY = Math.min(pos1.getY(), pos2.getY());
|
double minY = Math.min(pos1.getY(), pos2.getY());
|
||||||
arenaConfig.set(path + "MinY", minY);
|
arenaConfig.set(path + "MinY", minY);
|
||||||
|
|
||||||
@@ -82,6 +82,10 @@ public class ArenaManager {
|
|||||||
saveArenaRegion(player, arenaName);
|
saveArenaRegion(player, arenaName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Überprüft, ob eine Location innerhalb der Arena ist
|
||||||
|
* VERBESSERT: Konsistente Buffer-Werte (0.5 statt 0.1 / 2.0)
|
||||||
|
*/
|
||||||
public boolean isInArenaRegion(String arenaName, Location loc) {
|
public boolean isInArenaRegion(String arenaName, Location loc) {
|
||||||
if (loc == null || loc.getWorld() == null) return false;
|
if (loc == null || loc.getWorld() == null) return false;
|
||||||
|
|
||||||
@@ -92,22 +96,34 @@ public class ArenaManager {
|
|||||||
if (p1 == null || p2 == null) return false;
|
if (p1 == null || p2 == null) return false;
|
||||||
if (!loc.getWorld().equals(p1.getWorld())) return false;
|
if (!loc.getWorld().equals(p1.getWorld())) return false;
|
||||||
|
|
||||||
double minX = Math.min(p1.getX(), p2.getX());
|
// KONSISTENTER BUFFER: 0.5 Blöcke Toleranz (horizontal UND vertikal)
|
||||||
double maxX = Math.max(p1.getX(), p2.getX());
|
// Konfigurierbar machen über Config falls gewünscht
|
||||||
double minY = Math.min(p1.getY(), p2.getY());
|
double buffer = plugin.getConfig().getDouble("ArenaRegionBuffer", 0.5);
|
||||||
double maxY = Math.max(p1.getY(), p2.getY());
|
|
||||||
double minZ = Math.min(p1.getZ(), p2.getZ());
|
double minX = Math.min(p1.getX(), p2.getX()) - buffer;
|
||||||
double maxZ = Math.max(p1.getZ(), p2.getZ());
|
double maxX = Math.max(p1.getX(), p2.getX()) + buffer;
|
||||||
|
|
||||||
|
double minY = Math.min(p1.getY(), p2.getY()) - buffer;
|
||||||
|
double maxY = Math.max(p1.getY(), p2.getY()) + buffer;
|
||||||
|
|
||||||
|
double minZ = Math.min(p1.getZ(), p2.getZ()) - buffer;
|
||||||
|
double maxZ = Math.max(p1.getZ(), p2.getZ()) + buffer;
|
||||||
|
|
||||||
return loc.getX() >= minX && loc.getX() <= maxX &&
|
return loc.getX() >= minX && loc.getX() <= maxX &&
|
||||||
loc.getY() >= minY && loc.getY() <= maxY &&
|
loc.getY() >= minY && loc.getY() <= maxY &&
|
||||||
loc.getZ() >= minZ && loc.getZ() <= maxZ;
|
loc.getZ() >= minZ && loc.getZ() <= maxZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt die minimale Y-Koordinate der Arena zurück
|
||||||
|
*/
|
||||||
public double getMinY(String arenaName) {
|
public double getMinY(String arenaName) {
|
||||||
return arenaConfig.getDouble("Arenas." + arenaName + ".MinY", -100.0);
|
return arenaConfig.getDouble("Arenas." + arenaName + ".MinY", -100.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt die Arena-Config zurück
|
||||||
|
*/
|
||||||
public FileConfiguration getArenaConfig() {
|
public FileConfiguration getArenaConfig() {
|
||||||
return arenaConfig;
|
return arenaConfig;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
package de.velocityfall.manager;
|
package de.velocityfall.manager;
|
||||||
|
|
||||||
import de.velocityfall.VelocityFall;
|
import de.velocityfall.VelocityFall;
|
||||||
|
import de.velocityfall.utils.ScoreboardHelper;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class DisableReset {
|
public class DisableReset {
|
||||||
|
|
||||||
@@ -10,7 +18,116 @@ public class DisableReset {
|
|||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wird beim Plugin-Shutdown aufgerufen
|
||||||
|
* Resettet alle Arenas und teleportiert Spieler zurück
|
||||||
|
*/
|
||||||
public void disableReset() {
|
public void disableReset() {
|
||||||
plugin.getLogger().info("DisableReset ausgeführt – Plugin heruntergefahren.");
|
plugin.getLogger().info("DisableReset gestartet – Räume Arenas auf...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
resetAllArenas();
|
||||||
|
teleportAllPlayersToSpawn();
|
||||||
|
clearAllScoreboards();
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().severe("Fehler beim DisableReset: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getLogger().info("DisableReset abgeschlossen – Plugin heruntergefahren.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setzt alle Arena-Blöcke zurück
|
||||||
|
*/
|
||||||
|
private void resetAllArenas() {
|
||||||
|
if (plugin.getArenaBlocksMap().isEmpty()) {
|
||||||
|
plugin.getLogger().info("Keine Blöcke zum Zurücksetzen gefunden.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resetCount = 0;
|
||||||
|
for (Map.Entry<Block, String> entry : plugin.getArenaBlocksMap().entrySet()) {
|
||||||
|
try {
|
||||||
|
Block block = entry.getKey();
|
||||||
|
String materialName = entry.getValue();
|
||||||
|
|
||||||
|
Material material = Material.valueOf(materialName);
|
||||||
|
block.setType(material);
|
||||||
|
resetCount++;
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().warning("Fehler beim Block-Reset: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getArenaBlocksMap().clear();
|
||||||
|
plugin.getLogger().info(resetCount + " Blöcke zurückgesetzt.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Teleportiert alle Spieler aus Arenas zurück zum Spawn
|
||||||
|
*/
|
||||||
|
private void teleportAllPlayersToSpawn() {
|
||||||
|
if (plugin.getPlayerArenaMap().isEmpty()) {
|
||||||
|
plugin.getLogger().info("Keine Spieler in Arenas gefunden.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int teleportCount = 0;
|
||||||
|
for (Map.Entry<Player, String> entry : plugin.getPlayerArenaMap().entrySet()) {
|
||||||
|
try {
|
||||||
|
Player player = entry.getKey();
|
||||||
|
String arenaName = entry.getValue();
|
||||||
|
|
||||||
|
if (player == null || !player.isOnline()) continue;
|
||||||
|
|
||||||
|
// Versuche Lobby-Location zu finden
|
||||||
|
Location lobby = plugin.getArenaManager()
|
||||||
|
.getArenaConfig().getLocation("Arenas." + arenaName + ".Lobby");
|
||||||
|
|
||||||
|
if (lobby != null) {
|
||||||
|
player.teleport(lobby);
|
||||||
|
} else if (player.getWorld() != null) {
|
||||||
|
// Fallback: Welt-Spawn
|
||||||
|
player.teleport(player.getWorld().getSpawnLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spieler zurücksetzen
|
||||||
|
player.setGameMode(GameMode.SURVIVAL);
|
||||||
|
player.setAllowFlight(false);
|
||||||
|
player.setFlying(false);
|
||||||
|
player.getInventory().clear();
|
||||||
|
player.getInventory().setArmorContents(null);
|
||||||
|
player.setHealth(20.0);
|
||||||
|
player.setFoodLevel(20);
|
||||||
|
player.resetTitle();
|
||||||
|
|
||||||
|
player.sendMessage(VelocityFall.prefix + "§eServer wird heruntergefahren – Du wurdest aus der Arena teleportiert.");
|
||||||
|
|
||||||
|
teleportCount++;
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().warning("Fehler beim Spieler-Teleport: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getPlayerArenaMap().clear();
|
||||||
|
plugin.ingamePlayers.clear();
|
||||||
|
plugin.getLogger().info(teleportCount + " Spieler aus Arenas teleportiert.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entfernt alle Scoreboards
|
||||||
|
*/
|
||||||
|
private void clearAllScoreboards() {
|
||||||
|
int cleared = 0;
|
||||||
|
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
||||||
|
try {
|
||||||
|
ScoreboardHelper.clearBoard(player);
|
||||||
|
cleared++;
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().warning("Fehler beim Scoreboard-Clear für " + player.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plugin.getLogger().info(cleared + " Scoreboards entfernt.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.velocityfall.manager;
|
package de.velocityfall.manager;
|
||||||
|
|
||||||
import de.velocityfall.VelocityFall;
|
import de.velocityfall.VelocityFall;
|
||||||
|
import de.velocityfall.utils.ScoreboardHelper;
|
||||||
import de.velocityfall.utils.StatsHandler;
|
import de.velocityfall.utils.StatsHandler;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
@@ -18,7 +19,6 @@ import org.bukkit.scheduler.BukkitRunnable;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class GameManager {
|
public class GameManager {
|
||||||
|
|
||||||
@@ -27,6 +27,7 @@ public class GameManager {
|
|||||||
* --------------------------------------------------- */
|
* --------------------------------------------------- */
|
||||||
public static void startArenaCountdown(String arenaName) {
|
public static void startArenaCountdown(String arenaName) {
|
||||||
final VelocityFall plugin = VelocityFall.getInstance();
|
final VelocityFall plugin = VelocityFall.getInstance();
|
||||||
|
if (plugin == null) return;
|
||||||
if (plugin.getGameStartedMap().getOrDefault(arenaName, false)) return;
|
if (plugin.getGameStartedMap().getOrDefault(arenaName, false)) return;
|
||||||
|
|
||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@@ -56,12 +57,24 @@ public class GameManager {
|
|||||||
Location spawn = plugin.getArenaManager()
|
Location spawn = plugin.getArenaManager()
|
||||||
.getArenaConfig().getLocation("Arenas." + arenaName + ".Spawn");
|
.getArenaConfig().getLocation("Arenas." + arenaName + ".Spawn");
|
||||||
|
|
||||||
|
// PLAYED Stats erhöhen für alle Spieler
|
||||||
plugin.getPlayerArenaMap().forEach((p, a) -> {
|
plugin.getPlayerArenaMap().forEach((p, a) -> {
|
||||||
if (arenaName.equals(a)) {
|
if (arenaName.equals(a)) {
|
||||||
|
// Stats tracken
|
||||||
|
StatsHandler.addPlayed(p.getUniqueId().toString());
|
||||||
|
|
||||||
|
// Teleport & Setup
|
||||||
if (spawn != null) p.teleport(spawn);
|
if (spawn != null) p.teleport(spawn);
|
||||||
p.setGameMode(GameMode.ADVENTURE);
|
p.setGameMode(GameMode.ADVENTURE);
|
||||||
p.setAllowFlight(false);
|
p.setAllowFlight(false);
|
||||||
p.playSound(p.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 1f, 1f);
|
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();
|
cancel();
|
||||||
@@ -76,22 +89,24 @@ public class GameManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------
|
/* ---------------------------------------------------
|
||||||
* WIN HANDLING
|
* WIN HANDLING - MIT STATS TRACKING
|
||||||
* --------------------------------------------------- */
|
* --------------------------------------------------- */
|
||||||
public static void checkForWinner(String arenaName) {
|
public static void checkForWinner(String arenaName) {
|
||||||
final VelocityFall plugin = VelocityFall.getInstance();
|
final VelocityFall plugin = VelocityFall.getInstance();
|
||||||
|
if (plugin == null) return;
|
||||||
|
|
||||||
int remaining = plugin.getArenaPlayersCountMap().getOrDefault(arenaName, 0);
|
int remaining = plugin.getArenaPlayersCountMap().getOrDefault(arenaName, 0);
|
||||||
if (remaining != 1) return;
|
if (remaining != 1) return;
|
||||||
|
|
||||||
// 1) Versuche Gewinner zuverlässig über playerArenaMap (Single source)
|
// 1) Gewinner finden (Nicht-Spectator)
|
||||||
Player winner = plugin.getPlayerArenaMap().entrySet().stream()
|
Player winner = plugin.getPlayerArenaMap().entrySet().stream()
|
||||||
.filter(e -> arenaName.equals(e.getValue()))
|
.filter(e -> arenaName.equals(e.getValue()))
|
||||||
.map(Map.Entry::getKey)
|
.map(Map.Entry::getKey)
|
||||||
.filter(p -> p.getGameMode() != GameMode.SPECTATOR) // Nicht-Spectator = Gewinner
|
.filter(p -> p.getGameMode() != GameMode.SPECTATOR)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
|
||||||
// 2) Fallback: VelocityFall.getArenaPlayers(arenaName)
|
// Fallback
|
||||||
if (winner == null) {
|
if (winner == null) {
|
||||||
List<Player> arenaPlayers = VelocityFall.getArenaPlayers(arenaName);
|
List<Player> arenaPlayers = VelocityFall.getArenaPlayers(arenaName);
|
||||||
for (Player p : arenaPlayers) {
|
for (Player p : arenaPlayers) {
|
||||||
@@ -102,40 +117,155 @@ public class GameManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (winner == null) return; // kein Gewinner auffindbar → exit
|
if (winner == null) return;
|
||||||
|
|
||||||
final Player finalWinner = winner;
|
final Player finalWinner = winner;
|
||||||
|
|
||||||
// Nachricht + Stats + Scoreboard
|
// 2) Lose-Location ermitteln
|
||||||
try {
|
Location loseLocation = findLoseLocation(arenaName);
|
||||||
finalWinner.sendMessage(VelocityFall.prefix + ChatColor.translateAlternateColorCodes('&',
|
final Location finalLoseLocation = loseLocation;
|
||||||
plugin.getMessages().getMessagesConfig()
|
|
||||||
.getString("WinMessage", "&aDu hast gewonnen!")));
|
// 3) Verlierer sammeln (alle Spectators)
|
||||||
} catch (Exception ignored) {}
|
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 {
|
try {
|
||||||
StatsHandler.addWin(finalWinner.getUniqueId().toString());
|
StatsHandler.addWin(finalWinner.getUniqueId().toString());
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().warning("Win-Stats konnten nicht gespeichert werden: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5) STATS TRACKING - VERLIERER
|
||||||
|
for (Player loser : finalLosers) {
|
||||||
try {
|
try {
|
||||||
finalWinner.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard());
|
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) {}
|
} catch (Exception ignored) {}
|
||||||
|
}, 40L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskTimer(plugin, delayTicks, 10L);
|
||||||
|
}
|
||||||
|
|
||||||
// Lose-Location: mehrere mögliche Keys supporten + YLose fallback
|
/* ---------------------------------------------------
|
||||||
Location loseLocation = plugin.getArenaManager()
|
* LOSE LOCATION FINDER - HELPER
|
||||||
.getArenaConfig().getLocation("Arenas." + arenaName + ".Lose");
|
* --------------------------------------------------- */
|
||||||
if (loseLocation == null) loseLocation = plugin.getArenaManager()
|
private static Location findLoseLocation(String arenaName) {
|
||||||
.getArenaConfig().getLocation("Arenas." + arenaName + ".LoseLocation");
|
final VelocityFall plugin = VelocityFall.getInstance();
|
||||||
if (loseLocation == null) loseLocation = plugin.getArenaManager()
|
if (plugin == null) return null;
|
||||||
.getArenaConfig().getLocation("Arenas." + arenaName + ".LosePoint");
|
|
||||||
if (loseLocation == null) loseLocation = plugin.getArenaManager()
|
|
||||||
.getArenaConfig().getLocation("Arenas." + arenaName + ".SetLose");
|
|
||||||
|
|
||||||
// Spezial-Fallback: YLose vorhanden? Dann baue Location auf Basis von Spawn oder Lobby X/Z
|
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) {
|
if (loseLocation == null) {
|
||||||
Double yLose = plugin.getArenaManager().getArenaConfig().getDouble("Arenas." + arenaName + ".YLose", Double.NaN);
|
Double yLose = arenaConfig.getDouble("Arenas." + arenaName + ".YLose", Double.NaN);
|
||||||
if (!yLose.isNaN()) {
|
if (!yLose.isNaN()) {
|
||||||
// Priorität: Spawn -> Lobby -> arena center (Pos1/Pos2 midpoint)
|
Location spawn = arenaConfig.getLocation("Arenas." + arenaName + ".Spawn");
|
||||||
Location spawn = plugin.getArenaManager().getArenaConfig().getLocation("Arenas." + arenaName + ".Spawn");
|
Location lobby = arenaConfig.getLocation("Arenas." + arenaName + ".Lobby");
|
||||||
Location lobby = plugin.getArenaManager().getArenaConfig().getLocation("Arenas." + arenaName + ".Lobby");
|
|
||||||
if (spawn != null) {
|
if (spawn != null) {
|
||||||
loseLocation = spawn.clone();
|
loseLocation = spawn.clone();
|
||||||
loseLocation.setY(yLose);
|
loseLocation.setY(yLose);
|
||||||
@@ -143,9 +273,9 @@ public class GameManager {
|
|||||||
loseLocation = lobby.clone();
|
loseLocation = lobby.clone();
|
||||||
loseLocation.setY(yLose);
|
loseLocation.setY(yLose);
|
||||||
} else {
|
} else {
|
||||||
// midpoint of Pos1 and Pos2 if available
|
Location pos1 = arenaConfig.getLocation("Arenas." + arenaName + ".Pos1");
|
||||||
Location pos1 = plugin.getArenaManager().getArenaConfig().getLocation("Arenas." + arenaName + ".Pos1");
|
Location pos2 = arenaConfig.getLocation("Arenas." + arenaName + ".Pos2");
|
||||||
Location pos2 = plugin.getArenaManager().getArenaConfig().getLocation("Arenas." + arenaName + ".Pos2");
|
|
||||||
if (pos1 != null && pos2 != null && pos1.getWorld() != null && pos1.getWorld().equals(pos2.getWorld())) {
|
if (pos1 != null && pos2 != null && pos1.getWorld() != null && pos1.getWorld().equals(pos2.getWorld())) {
|
||||||
double midX = (pos1.getX() + pos2.getX()) / 2.0;
|
double midX = (pos1.getX() + pos2.getX()) / 2.0;
|
||||||
double midZ = (pos1.getZ() + pos2.getZ()) / 2.0;
|
double midZ = (pos1.getZ() + pos2.getZ()) / 2.0;
|
||||||
@@ -155,112 +285,23 @@ public class GameManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final Location finalLoseLocation = loseLocation; // final für Lambdas
|
return loseLocation;
|
||||||
|
|
||||||
// Ermittlung der Verlierer: alle Spectator-Spieler in dieser Arena
|
|
||||||
List<Player> losers = new ArrayList<>();
|
|
||||||
|
|
||||||
// Strategie A: playerArenaMap - alle Spectators sind Verlierer
|
|
||||||
plugin.getPlayerArenaMap().forEach((p, a) -> {
|
|
||||||
if (arenaName.equals(a) && !p.equals(finalWinner) && p.getGameMode() == GameMode.SPECTATOR) {
|
|
||||||
losers.add(p);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Strategie B: Falls keine Verlierer gefunden -> ingamePlayers Liste
|
|
||||||
if (losers.isEmpty()) {
|
|
||||||
try {
|
|
||||||
for (Player p : plugin.ingamePlayers) {
|
|
||||||
if (p != null && !p.equals(finalWinner) && p.getGameMode() == GameMode.SPECTATOR) {
|
|
||||||
losers.add(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strategie C: VelocityFall.getArenaPlayers(arenaName)
|
|
||||||
if (losers.isEmpty()) {
|
|
||||||
List<Player> arenaPlayers = VelocityFall.getArenaPlayers(arenaName);
|
|
||||||
if (!arenaPlayers.isEmpty()) {
|
|
||||||
for (Player p : arenaPlayers) {
|
|
||||||
if (p != null && !p.equals(finalWinner) && p.getGameMode() == GameMode.SPECTATOR) {
|
|
||||||
losers.add(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Erstelle finale Liste der Verlierer (damit sie auch nach Delays verfügbar ist)
|
|
||||||
final List<Player> finalLosers = new ArrayList<>(losers);
|
|
||||||
|
|
||||||
// Teleportiere Verlierer SOFORT zum Lose-Punkt (sie sind bereits in GM3 durch FloorLoseListener)
|
|
||||||
for (Player loser : finalLosers) {
|
|
||||||
try {
|
|
||||||
// Sicherstellen, dass Spectator-Modus gesetzt ist
|
|
||||||
if (loser.getGameMode() != GameMode.SPECTATOR) {
|
|
||||||
loser.setGameMode(GameMode.SPECTATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (finalLoseLocation != null) {
|
|
||||||
loser.teleport(finalLoseLocation);
|
|
||||||
} else {
|
|
||||||
// fallback: direkt neben Gewinner
|
|
||||||
Location fallback = finalWinner.getLocation().clone().add(1.0, 0.0, 0.0);
|
|
||||||
loser.teleport(fallback);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Falls Teleport fehlschlägt, loggen wir es serverseitig
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delay 3-5 Sekunden (konfigurierbar)
|
|
||||||
int delaySeconds = plugin.getConfig().getInt("PostWinDelay", 4);
|
|
||||||
delaySeconds = Math.min(5, Math.max(3, delaySeconds));
|
|
||||||
final long delayTicks = delaySeconds * 20L;
|
|
||||||
|
|
||||||
// Nach Delay: Feuerwerk beim Gewinner und dann Arena resetten / Lobby teleport
|
|
||||||
new BukkitRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
spawnFireworks(finalWinner.getLocation(), 2);
|
|
||||||
finalWinner.playSound(finalWinner.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1f, 1f);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
|
|
||||||
// 1 Sekunde später: Reset & Teleport aller zur Lobby (GM1)
|
|
||||||
new BukkitRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
// Robustes Reset: teleportiere Gewinner + finale Verlierer-Liste zur Lobby
|
|
||||||
performSafeResetAndLobbyTeleport(arenaName, finalWinner, finalLosers);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
|
|
||||||
// Aufräumen maps / Signs
|
|
||||||
try {
|
|
||||||
plugin.ingameArenas.remove(arenaName);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
try {
|
|
||||||
plugin.getSignManager().updateSign(arenaName);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
}
|
|
||||||
}.runTaskLater(plugin, 20L); // 1 Sekunde nach Feuerwerk
|
|
||||||
}
|
|
||||||
}.runTaskLater(plugin, delayTicks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------
|
/* ---------------------------------------------------
|
||||||
* SAFE RESET & LOBBY TELEPORT (robust)
|
* SAFE RESET & LOBBY TELEPORT
|
||||||
* --------------------------------------------------- */
|
* --------------------------------------------------- */
|
||||||
private static void performSafeResetAndLobbyTeleport(String arenaName, Player winner, List<Player> losers) {
|
private static void performSafeResetAndLobbyTeleport(String arenaName, Player winner, List<Player> losers) {
|
||||||
final VelocityFall plugin = VelocityFall.getInstance();
|
final VelocityFall plugin = VelocityFall.getInstance();
|
||||||
|
if (plugin == null) return;
|
||||||
|
|
||||||
// Blöcke zurücksetzen
|
// Blöcke zurücksetzen
|
||||||
plugin.getArenaBlocksMap().forEach((block, matName) -> {
|
plugin.getArenaBlocksMap().forEach((block, matName) -> {
|
||||||
try {
|
try {
|
||||||
block.setType(Material.valueOf(matName));
|
block.setType(Material.valueOf(matName));
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().warning("Block-Reset fehlgeschlagen: " + e.getMessage());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
plugin.getArenaBlocksMap().clear();
|
plugin.getArenaBlocksMap().clear();
|
||||||
|
|
||||||
@@ -268,65 +309,42 @@ public class GameManager {
|
|||||||
plugin.getGameStartedMap().put(arenaName, false);
|
plugin.getGameStartedMap().put(arenaName, false);
|
||||||
plugin.getArenaPlayersCountMap().remove(arenaName);
|
plugin.getArenaPlayersCountMap().remove(arenaName);
|
||||||
|
|
||||||
// Lobby-Location (kann null sein)
|
// Lobby-Location
|
||||||
Location lobby = plugin.getArenaManager().getArenaConfig().getLocation("Arenas." + arenaName + ".Lobby");
|
Location lobby = plugin.getArenaManager().getArenaConfig().getLocation("Arenas." + arenaName + ".Lobby");
|
||||||
|
|
||||||
// Sammle alle Spieler, die teleportiert werden müssen
|
// Alle Spieler sammeln
|
||||||
List<Player> toHandle = new ArrayList<>();
|
List<Player> toHandle = new ArrayList<>();
|
||||||
|
if (winner != null) toHandle.add(winner);
|
||||||
// Gewinner hinzufügen
|
|
||||||
if (winner != null) {
|
|
||||||
toHandle.add(winner);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verlierer hinzufügen (bereits als finale Liste übergeben)
|
|
||||||
for (Player loser : losers) {
|
for (Player loser : losers) {
|
||||||
if (loser != null && !toHandle.contains(loser)) {
|
if (loser != null && !toHandle.contains(loser)) {
|
||||||
toHandle.add(loser);
|
toHandle.add(loser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zusätzlich: alle restlichen Spieler aus playerArenaMap (Sicherheit)
|
// Sicherheit: Alle aus playerArenaMap
|
||||||
plugin.getPlayerArenaMap().forEach((p, a) -> {
|
plugin.getPlayerArenaMap().forEach((p, a) -> {
|
||||||
if (arenaName.equals(a) && !toHandle.contains(p)) {
|
if (arenaName.equals(a) && !toHandle.contains(p)) {
|
||||||
toHandle.add(p);
|
toHandle.add(p);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fallback: ingamePlayers
|
// Alle Spieler resetten
|
||||||
try {
|
|
||||||
for (Player p : new ArrayList<>(plugin.ingamePlayers)) {
|
|
||||||
if (p != null && !toHandle.contains(p)) {
|
|
||||||
// Prüfe ob Spieler möglicherweise zu dieser Arena gehört
|
|
||||||
String playerArena = plugin.getPlayerArenaMap().get(p);
|
|
||||||
if (arenaName.equals(playerArena)) {
|
|
||||||
toHandle.add(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
|
|
||||||
// Fallback: VelocityFall.getArenaPlayers
|
|
||||||
try {
|
|
||||||
List<Player> arenaPlayers = VelocityFall.getArenaPlayers(arenaName);
|
|
||||||
for (Player p : arenaPlayers) {
|
|
||||||
if (p != null && !toHandle.contains(p)) toHandle.add(p);
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
|
|
||||||
// Verarbeite alle gesammelten Spieler: GM1 (SURVIVAL), Inventar clear, teleport zur Lobby, entferne aus Maps
|
|
||||||
for (Player p : toHandle) {
|
for (Player p : toHandle) {
|
||||||
try {
|
try {
|
||||||
p.setGameMode(GameMode.SURVIVAL); // GM1
|
p.setGameMode(GameMode.SURVIVAL);
|
||||||
|
p.setAllowFlight(false);
|
||||||
|
p.setFlying(false);
|
||||||
p.getInventory().clear();
|
p.getInventory().clear();
|
||||||
p.getInventory().setArmorContents(null);
|
p.getInventory().setArmorContents(null);
|
||||||
p.setHealth(20.0);
|
p.setHealth(20.0);
|
||||||
p.setFoodLevel(20);
|
p.setFoodLevel(20);
|
||||||
|
p.resetTitle();
|
||||||
|
|
||||||
|
ScoreboardHelper.clearBoard(p);
|
||||||
|
|
||||||
if (lobby != null) {
|
if (lobby != null) {
|
||||||
p.teleport(lobby);
|
p.teleport(lobby);
|
||||||
} else {
|
} else {
|
||||||
// Fallback: Spawn-Location oder World-Spawn
|
|
||||||
Location spawn = plugin.getArenaManager().getArenaConfig().getLocation("Arenas." + arenaName + ".Spawn");
|
Location spawn = plugin.getArenaManager().getArenaConfig().getLocation("Arenas." + arenaName + ".Spawn");
|
||||||
if (spawn != null) {
|
if (spawn != null) {
|
||||||
p.teleport(spawn);
|
p.teleport(spawn);
|
||||||
@@ -335,11 +353,10 @@ public class GameManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Jetzt erst aus den Maps entfernen
|
|
||||||
plugin.ingamePlayers.remove(p);
|
plugin.ingamePlayers.remove(p);
|
||||||
plugin.getPlayerArenaMap().remove(p);
|
plugin.getPlayerArenaMap().remove(p);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
plugin.getLogger().warning("Spieler-Reset fehlgeschlagen für " + p.getName() + ": " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,12 +381,16 @@ public class GameManager {
|
|||||||
|
|
||||||
for (int i = 0; i < Math.max(1, count); i++) {
|
for (int i = 0; i < Math.max(1, count); i++) {
|
||||||
try {
|
try {
|
||||||
Firework fw = loc.getWorld().spawn(loc.clone().add(0, 1 + i * 0.5, 0), Firework.class);
|
Firework fw = loc.getWorld().spawn(loc.clone().add(0, i * 0.5, 0), Firework.class);
|
||||||
FireworkMeta meta = fw.getFireworkMeta();
|
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()
|
FireworkEffect effect = FireworkEffect.builder()
|
||||||
.with(FireworkEffect.Type.BALL_LARGE)
|
.with(FireworkEffect.Type.BALL_LARGE)
|
||||||
.withColor(Color.LIME, Color.YELLOW)
|
.withColor(randomColor1, randomColor2)
|
||||||
.withFade(Color.WHITE)
|
.withFade(Color.WHITE)
|
||||||
.trail(true)
|
.trail(true)
|
||||||
.flicker(true)
|
.flicker(true)
|
||||||
@@ -379,7 +400,7 @@ public class GameManager {
|
|||||||
meta.setPower(1);
|
meta.setPower(1);
|
||||||
fw.setFireworkMeta(meta);
|
fw.setFireworkMeta(meta);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
t.printStackTrace();
|
VelocityFall.getInstance().getLogger().warning("Firework-Spawn fehlgeschlagen: " + t.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -389,6 +410,8 @@ public class GameManager {
|
|||||||
* --------------------------------------------------- */
|
* --------------------------------------------------- */
|
||||||
private static void broadcast(String arena, String msg) {
|
private static void broadcast(String arena, String msg) {
|
||||||
final VelocityFall plugin = VelocityFall.getInstance();
|
final VelocityFall plugin = VelocityFall.getInstance();
|
||||||
|
if (plugin == null) return;
|
||||||
|
|
||||||
plugin.getPlayerArenaMap().forEach((player, a) -> {
|
plugin.getPlayerArenaMap().forEach((player, a) -> {
|
||||||
if (arena.equals(a)) {
|
if (arena.equals(a)) {
|
||||||
player.sendMessage(VelocityFall.prefix + msg);
|
player.sendMessage(VelocityFall.prefix + msg);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.velocityfall.manager;
|
package de.velocityfall.manager;
|
||||||
|
|
||||||
import de.velocityfall.VelocityFall;
|
import de.velocityfall.VelocityFall;
|
||||||
|
import de.velocityfall.utils.ScoreboardHelper;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -54,6 +55,9 @@ public class JoinManager {
|
|||||||
|
|
||||||
player.sendMessage(VelocityFall.prefix + "§aBeigetreten: §e" + arenaName);
|
player.sendMessage(VelocityFall.prefix + "§aBeigetreten: §e" + arenaName);
|
||||||
|
|
||||||
|
// Scoreboard setzen (Lobby-Scoreboard)
|
||||||
|
ScoreboardHelper.updateBoard(player, arenaName, false);
|
||||||
|
|
||||||
int min = plugin.getConfig().getInt("MinPlayers", 2);
|
int min = plugin.getConfig().getInt("MinPlayers", 2);
|
||||||
if (current + 1 >= min && !plugin.getGameStartedMap().getOrDefault(arenaName, false)) {
|
if (current + 1 >= min && !plugin.getGameStartedMap().getOrDefault(arenaName, false)) {
|
||||||
GameManager.startArenaCountdown(arenaName);
|
GameManager.startArenaCountdown(arenaName);
|
||||||
@@ -62,6 +66,9 @@ public class JoinManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
plugin.getSignManager().updateSign(arenaName);
|
plugin.getSignManager().updateSign(arenaName);
|
||||||
|
|
||||||
|
// Scoreboard für alle anderen in der Arena updaten
|
||||||
|
ScoreboardHelper.updateAllInArena(arenaName, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void join(Player player, String arenaName) {
|
public void join(Player player, String arenaName) {
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ public class MySQLConnector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Führt ein UPDATE, INSERT oder DELETE Statement aus
|
||||||
|
*/
|
||||||
public void executeUpdate(String sql, Object... params) {
|
public void executeUpdate(String sql, Object... params) {
|
||||||
try (PreparedStatement ps = connection.prepareStatement(sql)) {
|
try (PreparedStatement ps = connection.prepareStatement(sql)) {
|
||||||
for (int i = 0; i < params.length; i++) {
|
for (int i = 0; i < params.length; i++) {
|
||||||
@@ -42,23 +45,85 @@ public class MySQLConnector {
|
|||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
plugin.getLogger().warning("Update fehlgeschlagen: " + e.getMessage());
|
plugin.getLogger().warning("Update fehlgeschlagen: " + e.getMessage());
|
||||||
connect();
|
reconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultSet executeQuery(String sql, Object... params) throws SQLException {
|
/**
|
||||||
PreparedStatement ps = connection.prepareStatement(sql);
|
* Gibt einen einzelnen Integer-Wert zurück (ohne Connection Leak)
|
||||||
|
*/
|
||||||
|
public Integer executeQuerySingleInt(String sql, String columnName, Object... params) {
|
||||||
|
try (PreparedStatement ps = connection.prepareStatement(sql)) {
|
||||||
for (int i = 0; i < params.length; i++) {
|
for (int i = 0; i < params.length; i++) {
|
||||||
ps.setObject(i + 1, params[i]);
|
ps.setObject(i + 1, params[i]);
|
||||||
}
|
}
|
||||||
return ps.executeQuery();
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
if (rs.next()) {
|
||||||
|
return rs.getInt(columnName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
plugin.getLogger().warning("Query fehlgeschlagen: " + e.getMessage());
|
||||||
|
reconnect();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt einen einzelnen String-Wert zurück
|
||||||
|
*/
|
||||||
|
public String executeQuerySingleString(String sql, String columnName, Object... params) {
|
||||||
|
try (PreparedStatement ps = connection.prepareStatement(sql)) {
|
||||||
|
for (int i = 0; i < params.length; i++) {
|
||||||
|
ps.setObject(i + 1, params[i]);
|
||||||
|
}
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
if (rs.next()) {
|
||||||
|
return rs.getString(columnName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
plugin.getLogger().warning("Query fehlgeschlagen: " + e.getMessage());
|
||||||
|
reconnect();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prüft ob Verbindung noch aktiv ist und reconnected falls nötig
|
||||||
|
*/
|
||||||
|
private void reconnect() {
|
||||||
|
try {
|
||||||
|
if (connection == null || connection.isClosed()) {
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
plugin.getLogger().severe("Reconnect fehlgeschlagen: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prüft ob MySQL verbunden ist
|
||||||
|
*/
|
||||||
|
public boolean isConnected() {
|
||||||
|
try {
|
||||||
|
return connection != null && !connection.isClosed();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schließt die Verbindung sauber
|
||||||
|
*/
|
||||||
public void close() {
|
public void close() {
|
||||||
try {
|
try {
|
||||||
if (connection != null && !connection.isClosed()) connection.close();
|
if (connection != null && !connection.isClosed()) {
|
||||||
|
connection.close();
|
||||||
|
plugin.getLogger().info("MySQL Verbindung geschlossen.");
|
||||||
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
plugin.getLogger().warning("Fehler beim Schließen der MySQL Verbindung: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,10 +12,12 @@ public class SignManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateSign(String arenaName) {
|
public void updateSign(String arenaName) {
|
||||||
|
try {
|
||||||
var arenaConfig = plugin.getArenaManager().getArenaConfig();
|
var arenaConfig = plugin.getArenaManager().getArenaConfig();
|
||||||
Location signLoc = arenaConfig.getLocation("Arenas." + arenaName + ".SignLoc");
|
Location signLoc = arenaConfig.getLocation("Arenas." + arenaName + ".SignLoc");
|
||||||
|
|
||||||
if (signLoc == null || !(signLoc.getBlock().getState() instanceof Sign sign)) return;
|
if (signLoc == null) return;
|
||||||
|
if (!(signLoc.getBlock().getState() instanceof Sign sign)) return;
|
||||||
|
|
||||||
int count = plugin.getArenaPlayersCountMap().getOrDefault(arenaName, 0);
|
int count = plugin.getArenaPlayersCountMap().getOrDefault(arenaName, 0);
|
||||||
int max = arenaConfig.getInt("Arenas." + arenaName + ".Max", 0);
|
int max = arenaConfig.getInt("Arenas." + arenaName + ".Max", 0);
|
||||||
@@ -26,5 +28,8 @@ public class SignManager {
|
|||||||
sign.setLine(3, "§8" + count + "§7/§8" + max);
|
sign.setLine(3, "§8" + count + "§7/§8" + max);
|
||||||
|
|
||||||
sign.update(true, false);
|
sign.update(true, false);
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().warning("Sign Update fehlgeschlagen für Arena " + arenaName + ": " + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,40 +6,164 @@ import org.bukkit.ChatColor;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.scoreboard.*;
|
import org.bukkit.scoreboard.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ScoreboardHelper {
|
public class ScoreboardHelper {
|
||||||
|
|
||||||
public static void updateBoard(Player player, String arenaName, boolean isIngame) {
|
public static void updateBoard(Player player, String arenaName, boolean isIngame) {
|
||||||
|
try {
|
||||||
VelocityFall plugin = VelocityFall.getInstance();
|
VelocityFall plugin = VelocityFall.getInstance();
|
||||||
|
if (plugin == null) return;
|
||||||
|
|
||||||
Scoreboard board = Bukkit.getScoreboardManager().getNewScoreboard();
|
Scoreboard board = Bukkit.getScoreboardManager().getNewScoreboard();
|
||||||
String titlePath = isIngame ? "InGameScoreBoardTitle" : "LobbyScoreBoardTitle";
|
String titlePath = isIngame ? "InGameScoreBoardTitle" : "LobbyScoreBoardTitle";
|
||||||
String title = ChatColor.translateAlternateColorCodes('&', plugin.getConfig().getString(titlePath, "&6VelocityFall"));
|
String rawTitle = plugin.getConfig().getString(titlePath, "&6&lVELOCITY FALL");
|
||||||
|
String title = ChatColor.translateAlternateColorCodes('&', rawTitle);
|
||||||
|
|
||||||
Objective objective = board.registerNewObjective("vfall", Criteria.DUMMY, title);
|
// Längen-Check OHNE ChatColor Codes
|
||||||
|
String strippedTitle = ChatColor.stripColor(title);
|
||||||
|
if (strippedTitle.length() > 32) {
|
||||||
|
// Intelligentes Kürzen: Behalte Farben bei
|
||||||
|
title = title.substring(0, Math.min(title.length(), 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
Objective objective = board.registerNewObjective("vfall", "dummy", title);
|
||||||
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
||||||
|
|
||||||
String listPath = isIngame ? "InGameScoreBoard" : "LobbyScoreBoard";
|
String listPath = isIngame ? "InGameScoreBoard" : "LobbyScoreBoard";
|
||||||
List<String> lines = plugin.getConfig().getStringList(listPath);
|
List<String> configLines = plugin.getConfig().getStringList(listPath);
|
||||||
|
|
||||||
int scoreValue = lines.size();
|
// Fallback falls Config leer ist
|
||||||
for (String rawLine : lines) {
|
if (configLines == null || configLines.isEmpty()) {
|
||||||
|
configLines = getDefaultLines(isIngame);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variablen für Replacements
|
||||||
|
int currentPlayers = plugin.getArenaPlayersCountMap().getOrDefault(arenaName, 0);
|
||||||
|
int maxPlayers = 0;
|
||||||
|
if (arenaName != null) {
|
||||||
|
maxPlayers = plugin.getArenaManager().getArenaConfig().getInt("Arenas." + arenaName + ".Max", 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status-Anzeige
|
||||||
|
String statusColor = isIngame ? "&c" : "&a";
|
||||||
|
String statusText = isIngame ? "IM SPIEL" : "LOBBY";
|
||||||
|
|
||||||
|
// Spieler-Farbe basierend auf Füllstand
|
||||||
|
String playerColor = getPlayerCountColor(currentPlayers, maxPlayers);
|
||||||
|
|
||||||
|
List<String> processedLines = new ArrayList<>();
|
||||||
|
int scoreValue = configLines.size();
|
||||||
|
|
||||||
|
for (String rawLine : configLines) {
|
||||||
String line = ChatColor.translateAlternateColorCodes('&', rawLine
|
String line = ChatColor.translateAlternateColorCodes('&', rawLine
|
||||||
.replace("%arena%", arenaName != null ? arenaName : "???")
|
.replace("%arena%", arenaName != null ? arenaName : "???")
|
||||||
.replace("%players%", String.valueOf(plugin.getArenaPlayersCountMap().getOrDefault(arenaName, 0)))
|
.replace("%players%", String.valueOf(currentPlayers))
|
||||||
.replace("%max%", String.valueOf(plugin.getArenaManager().getArenaConfig().getInt("Arenas." + arenaName + ".Max", 0))));
|
.replace("%max%", String.valueOf(maxPlayers))
|
||||||
|
.replace("%player%", player.getName())
|
||||||
|
.replace("%status%", statusText)
|
||||||
|
.replace("%status_color%", statusColor)
|
||||||
|
.replace("%player_color%", playerColor));
|
||||||
|
|
||||||
objective.getScore(line).setScore(scoreValue--);
|
// Zeilen-Länge prüfen
|
||||||
|
if (line.length() > 40) {
|
||||||
|
line = line.substring(0, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplikate verhindern
|
||||||
|
while (processedLines.contains(line)) {
|
||||||
|
line = line + ChatColor.RESET;
|
||||||
|
}
|
||||||
|
processedLines.add(line);
|
||||||
|
|
||||||
|
// Score setzen
|
||||||
|
Score score = objective.getScore(line);
|
||||||
|
score.setScore(scoreValue--);
|
||||||
}
|
}
|
||||||
|
|
||||||
player.setScoreboard(board);
|
player.setScoreboard(board);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
VelocityFall plugin = VelocityFall.getInstance();
|
||||||
|
if (plugin != null) {
|
||||||
|
plugin.getLogger().warning("Scoreboard Update fehlgeschlagen: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt die passende Farbe basierend auf der Spieleranzahl zurück
|
||||||
|
*/
|
||||||
|
private static String getPlayerCountColor(int current, int max) {
|
||||||
|
if (max == 0) return "&7";
|
||||||
|
|
||||||
|
double percentage = (double) current / max;
|
||||||
|
|
||||||
|
if (percentage >= 0.8) return "&c"; // 80%+ = rot (fast voll)
|
||||||
|
if (percentage >= 0.5) return "&e"; // 50%+ = gelb
|
||||||
|
return "&a"; // <50% = grün (viel Platz)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updated Scoreboard für alle Spieler in einer Arena
|
||||||
|
*/
|
||||||
public static void updateAllInArena(String arenaName, boolean isIngame) {
|
public static void updateAllInArena(String arenaName, boolean isIngame) {
|
||||||
|
try {
|
||||||
VelocityFall plugin = VelocityFall.getInstance();
|
VelocityFall plugin = VelocityFall.getInstance();
|
||||||
|
if (plugin == null) return;
|
||||||
|
|
||||||
plugin.getPlayerArenaMap().forEach((p, a) -> {
|
plugin.getPlayerArenaMap().forEach((p, a) -> {
|
||||||
if (arenaName.equals(a)) updateBoard(p, arenaName, isIngame);
|
if (arenaName.equals(a)) {
|
||||||
|
updateBoard(p, arenaName, isIngame);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
VelocityFall plugin = VelocityFall.getInstance();
|
||||||
|
if (plugin != null) {
|
||||||
|
plugin.getLogger().warning("Scoreboard Batch-Update fehlgeschlagen: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entfernt Scoreboard von einem Spieler
|
||||||
|
*/
|
||||||
|
public static void clearBoard(Player player) {
|
||||||
|
try {
|
||||||
|
if (player != null && player.isOnline()) {
|
||||||
|
player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Ignoriere Fehler beim Cleanup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard-Zeilen falls Config leer ist (MODERN DESIGN)
|
||||||
|
*/
|
||||||
|
private static List<String> getDefaultLines(boolean isIngame) {
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
if (isIngame) {
|
||||||
|
lines.add("&8&m--------------------");
|
||||||
|
lines.add(" ");
|
||||||
|
lines.add(" &6⚔ &eArena&8: &f%arena%");
|
||||||
|
lines.add(" &c❤ &eÜbrig&8: %player_color%%players%");
|
||||||
|
lines.add(" ");
|
||||||
|
lines.add(" &a✓ &7Überlebe so lange");
|
||||||
|
lines.add(" &7wie möglich!");
|
||||||
|
lines.add(" ");
|
||||||
|
lines.add("&8&m--------------------");
|
||||||
|
} else {
|
||||||
|
lines.add("&8&m--------------------");
|
||||||
|
lines.add(" ");
|
||||||
|
lines.add(" &6⚔ &eArena&8: &f%arena%");
|
||||||
|
lines.add(" &b👥 &eSpieler&8: %player_color%%players%&8/&7%max%");
|
||||||
|
lines.add(" ");
|
||||||
|
lines.add(" &7Warte auf Spieler...");
|
||||||
|
lines.add(" ");
|
||||||
|
lines.add("&8&m--------------------");
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,53 +5,138 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
public class StatsHandler {
|
public class StatsHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erhöht den Win-Counter für einen Spieler
|
||||||
|
*/
|
||||||
public static void addWin(String uuid) {
|
public static void addWin(String uuid) {
|
||||||
addStat(uuid, "WINS");
|
addStat(uuid, "WINS");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erhöht den Lose-Counter für einen Spieler
|
||||||
|
*/
|
||||||
public static void addLose(String uuid) {
|
public static void addLose(String uuid) {
|
||||||
addStat(uuid, "LOSE");
|
addStat(uuid, "LOSE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erhöht den Played-Counter für einen Spieler
|
||||||
|
* NEU: Wird jetzt beim Game-Start aufgerufen
|
||||||
|
*/
|
||||||
|
public static void addPlayed(String uuid) {
|
||||||
|
addStat(uuid, "PLAYED");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interne Methode zum Erhöhen eines Stats
|
||||||
|
*/
|
||||||
private static void addStat(String uuid, String column) {
|
private static void addStat(String uuid, String column) {
|
||||||
VelocityFall plugin = VelocityFall.getInstance();
|
VelocityFall plugin = VelocityFall.getInstance();
|
||||||
|
|
||||||
|
if (plugin == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (plugin.getStats().getStatsConfig().getBoolean("EnableMySQL", false)) {
|
if (plugin.getStats().getStatsConfig().getBoolean("EnableMySQL", false)) {
|
||||||
|
// MySQL: INSERT ... ON DUPLICATE KEY UPDATE
|
||||||
|
// Erstellt automatisch einen Eintrag falls UUID noch nicht existiert
|
||||||
|
if (plugin.getMySQLConnector() != null && plugin.getMySQLConnector().isConnected()) {
|
||||||
plugin.getMySQLConnector().executeUpdate(
|
plugin.getMySQLConnector().executeUpdate(
|
||||||
"UPDATE VelocityFallStats SET " + column + " = " + column + " + 1 WHERE UUID = ?",
|
"INSERT INTO VelocityFallStats (UUID, " + column + ") VALUES (?, 1) " +
|
||||||
|
"ON DUPLICATE KEY UPDATE " + column + " = " + column + " + 1",
|
||||||
uuid
|
uuid
|
||||||
);
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// YAML Fallback
|
||||||
File file = new File(plugin.getDataFolder(), "stats.yml");
|
File file = new File(plugin.getDataFolder(), "stats.yml");
|
||||||
YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file);
|
YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file);
|
||||||
cfg.set(uuid + "." + column, cfg.getInt(uuid + "." + column, 0) + 1);
|
cfg.set(uuid + "." + column, cfg.getInt(uuid + "." + column, 0) + 1);
|
||||||
try {
|
try {
|
||||||
cfg.save(file);
|
cfg.save(file);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
plugin.getLogger().warning("Konnte stats.yml nicht speichern: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holt die Anzahl der Wins
|
||||||
|
*/
|
||||||
public static int getWins(String uuid) {
|
public static int getWins(String uuid) {
|
||||||
return getStat(uuid, "WINS");
|
return getStat(uuid, "WINS");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holt die Anzahl der Loses
|
||||||
|
*/
|
||||||
|
public static int getLoses(String uuid) {
|
||||||
|
return getStat(uuid, "LOSE");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holt die Anzahl der gespielten Runden
|
||||||
|
*/
|
||||||
|
public static int getPlayed(String uuid) {
|
||||||
|
return getStat(uuid, "PLAYED");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interne Methode zum Abrufen eines Stats
|
||||||
|
*/
|
||||||
private static int getStat(String uuid, String column) {
|
private static int getStat(String uuid, String column) {
|
||||||
VelocityFall plugin = VelocityFall.getInstance();
|
VelocityFall plugin = VelocityFall.getInstance();
|
||||||
|
|
||||||
|
if (plugin == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (plugin.getStats().getStatsConfig().getBoolean("EnableMySQL", false)) {
|
if (plugin.getStats().getStatsConfig().getBoolean("EnableMySQL", false)) {
|
||||||
try (ResultSet rs = plugin.getMySQLConnector().executeQuery(
|
// MySQL
|
||||||
"SELECT " + column + " FROM VelocityFallStats WHERE UUID = ?", uuid)) {
|
if (plugin.getMySQLConnector() != null && plugin.getMySQLConnector().isConnected()) {
|
||||||
if (rs.next()) return rs.getInt(column);
|
Integer result = plugin.getMySQLConnector().executeQuerySingleInt(
|
||||||
} catch (SQLException e) {
|
"SELECT " + column + " FROM VelocityFallStats WHERE UUID = ?",
|
||||||
e.printStackTrace();
|
column,
|
||||||
|
uuid
|
||||||
|
);
|
||||||
|
return result != null ? result : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// YAML Fallback
|
||||||
File file = new File(plugin.getDataFolder(), "stats.yml");
|
File file = new File(plugin.getDataFolder(), "stats.yml");
|
||||||
return YamlConfiguration.loadConfiguration(file).getInt(uuid + "." + column, 0);
|
return YamlConfiguration.loadConfiguration(file).getInt(uuid + "." + column, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setzt alle Stats für einen Spieler zurück
|
||||||
|
*/
|
||||||
|
public static void resetStats(String uuid) {
|
||||||
|
VelocityFall plugin = VelocityFall.getInstance();
|
||||||
|
|
||||||
|
if (plugin == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getStats().getStatsConfig().getBoolean("EnableMySQL", false)) {
|
||||||
|
if (plugin.getMySQLConnector() != null && plugin.getMySQLConnector().isConnected()) {
|
||||||
|
plugin.getMySQLConnector().executeUpdate(
|
||||||
|
"DELETE FROM VelocityFallStats WHERE UUID = ?",
|
||||||
|
uuid
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
File file = new File(plugin.getDataFolder(), "stats.yml");
|
||||||
|
YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file);
|
||||||
|
cfg.set(uuid, null);
|
||||||
|
try {
|
||||||
|
cfg.save(file);
|
||||||
|
} catch (IOException e) {
|
||||||
|
plugin.getLogger().warning("Konnte stats.yml nicht speichern: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
33
src/main/java/de/velocityfall/utils/UpdateChecker.java
Normal file
33
src/main/java/de/velocityfall/utils/UpdateChecker.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package de.velocityfall.utils;
|
||||||
|
|
||||||
|
import de.velocityfall.VelocityFall;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class UpdateChecker {
|
||||||
|
|
||||||
|
private final VelocityFall plugin;
|
||||||
|
private final int resourceId;
|
||||||
|
|
||||||
|
public UpdateChecker(VelocityFall plugin, int resourceId) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.resourceId = resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getLatestVersion(final Consumer<String> consumer) {
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> {
|
||||||
|
try (InputStream inputStream = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + this.resourceId).openStream();
|
||||||
|
Scanner scanner = new Scanner(inputStream)) {
|
||||||
|
if (scanner.hasNext()) {
|
||||||
|
consumer.accept(scanner.next());
|
||||||
|
}
|
||||||
|
} catch (IOException exception) {
|
||||||
|
plugin.getLogger().info("Update-Check fehlgeschlagen: " + exception.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,27 +1,127 @@
|
|||||||
Prefix: '&c[VelocityFall] '
|
# _ __ __ _ __ ______ ____
|
||||||
|
# | | / /__ / /___ _____(_) /___ __/ ____/___ _/ / /
|
||||||
|
# | | / / _ \/ / __ \/ ___/ / __/ / / / /_ / __ `/ / /
|
||||||
|
# | |/ / __/ / /_/ / /__/ / /_/ /_/ / __/ / /_/ / / /
|
||||||
|
# |___/\___/_/\____/\___/_/\__/\__, /_/ \__,_/_/_/
|
||||||
|
# /____/
|
||||||
|
|
||||||
|
|
||||||
|
# VelocityFall - Minecraft Minigame Plugin
|
||||||
|
# Beispiel-Konfiguration
|
||||||
|
|
||||||
|
Prefix: "&6Velocity&fFall &8» "
|
||||||
|
NoPermission: "&cKeine Rechte!"
|
||||||
|
|
||||||
|
# Minimale Spieleranzahl für Start
|
||||||
|
MinPlayers: 2
|
||||||
|
|
||||||
|
# Countdown vor Spielstart (Sekunden)
|
||||||
BeforeGameCD: 15
|
BeforeGameCD: 15
|
||||||
CountdownSound: ENTITY_EXPERIENCE_ORB_PICKUP
|
|
||||||
SaveInv: true
|
# Delay nach Sieg bevor Reset (Sekunden, 3-5)
|
||||||
PostWinDelay: 4
|
PostWinDelay: 4
|
||||||
WinCommands:
|
|
||||||
- eco give %player% 10
|
# Inventar speichern?
|
||||||
- msg %player% Du hast gewonnen!
|
SaveInv: false
|
||||||
CmdWhitelist:
|
|
||||||
- /vfall leave
|
# ========================================
|
||||||
- /tell
|
# LOBBY SCOREBOARD (vor Spielstart)
|
||||||
MySQL:
|
# ========================================
|
||||||
Enable: false
|
LobbyScoreBoardTitle: "&6&lVELOCITY &f&lFALL"
|
||||||
Host: localhost
|
|
||||||
Port: '3306'
|
|
||||||
Database: vfall
|
|
||||||
User: root
|
|
||||||
Password: ''
|
|
||||||
LobbyScoreBoardTitle: '&6&lVelocityFall'
|
|
||||||
InGameScoreBoardTitle: '&6&lVelocityFall'
|
|
||||||
LobbyScoreBoard:
|
LobbyScoreBoard:
|
||||||
- '&7---'
|
- "&8&m━━━━━━━━━━━━━━━━━━━━━"
|
||||||
- '&eArena:'
|
- " "
|
||||||
- '&f%arena%'
|
- " &6⚔ &eArena&8: &f%arena%"
|
||||||
- '&7'
|
- " &b👥 &eSpieler&8: %player_color%%players%&8/&7%max%"
|
||||||
- '&eSpieler:'
|
- " "
|
||||||
- '&f%players%'
|
- " &7Warte auf Spieler..."
|
||||||
|
- " "
|
||||||
|
- "&8&m━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# INGAME SCOREBOARD (während des Spiels)
|
||||||
|
# ========================================
|
||||||
|
InGameScoreBoardTitle: "&c&lIM &f&lSPIEL"
|
||||||
|
|
||||||
|
InGameScoreBoard:
|
||||||
|
- "&8&m━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
- " "
|
||||||
|
- " &6⚔ &eArena&8: &f%arena%"
|
||||||
|
- " &c❤ &eÜbrig&8: %player_color%%players%"
|
||||||
|
- " "
|
||||||
|
- " &a✓ &7Überlebe so lange"
|
||||||
|
- " &7wie möglich!"
|
||||||
|
- " "
|
||||||
|
- " &e⚠ &7Pass auf die"
|
||||||
|
- " &7Blöcke auf!"
|
||||||
|
- " "
|
||||||
|
- "&8&m━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# VERFÜGBARE PLATZHALTER
|
||||||
|
# ========================================
|
||||||
|
# %arena% - Arena-Name
|
||||||
|
# %players% - Aktuelle Spielerzahl
|
||||||
|
# %max% - Maximale Spielerzahl
|
||||||
|
# %player% - Name des Spielers
|
||||||
|
# %status% - Status-Text (LOBBY/IM SPIEL)
|
||||||
|
# %status_color% - Farbe basierend auf Status
|
||||||
|
# %player_color% - Farbe basierend auf Füllstand (grün/gelb/rot)
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# ALTERNATIVE DESIGNS (kopiere diese in die Scoreboard-Sektion)
|
||||||
|
# ========================================
|
||||||
|
|
||||||
|
# DESIGN 1: Minimalistisch
|
||||||
|
# LobbyScoreBoard:
|
||||||
|
# - "&7┌─────────────────┐"
|
||||||
|
# - " &6⚡ &e%arena%"
|
||||||
|
# - " &b🎮 %player_color%%players%&7/%max%"
|
||||||
|
# - "&7└─────────────────┘"
|
||||||
|
|
||||||
|
# DESIGN 2: Retro Style
|
||||||
|
# LobbyScoreBoard:
|
||||||
|
# - "&8╔═══════════════════╗"
|
||||||
|
# - " "
|
||||||
|
# - " &e► Arena: &f%arena%"
|
||||||
|
# - " &e► Spieler: %player_color%%players%&7/%max%"
|
||||||
|
# - " "
|
||||||
|
# - "&8╚═══════════════════╝"
|
||||||
|
|
||||||
|
# DESIGN 3: Modern Gradient
|
||||||
|
# LobbyScoreBoard:
|
||||||
|
# - "&6▬▬▬&e▬▬▬&f▬▬▬&e▬▬▬&6▬▬▬"
|
||||||
|
# - " "
|
||||||
|
# - " &6⚡ &eArena &f%arena%"
|
||||||
|
# - " &b👤 %player_color%%players%&8/&7%max% &eSpieler"
|
||||||
|
# - " "
|
||||||
|
# - " &7Bereit? Warte..."
|
||||||
|
# - " "
|
||||||
|
# - "&6▬▬▬&e▬▬▬&f▬▬▬&e▬▬▬&6▬▬▬"
|
||||||
|
|
||||||
|
# DESIGN 4: Kompakt
|
||||||
|
# LobbyScoreBoard:
|
||||||
|
# - "&8━━━━━━━━━━━━━━━━"
|
||||||
|
# - "&6⚔ &e%arena%"
|
||||||
|
# - "&b👥 %player_color%%players%&7/%max%"
|
||||||
|
# - "&7Warte..."
|
||||||
|
# - "&8━━━━━━━━━━━━━━━━"
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# FARB-CODES REFERENZ
|
||||||
|
# ========================================
|
||||||
|
# &0 = Schwarz &8 = Dunkelgrau
|
||||||
|
# &1 = Dunkelblau &9 = Blau
|
||||||
|
# &2 = Dunkelgrün &a = Grün
|
||||||
|
# &3 = Türkis &b = Hellblau
|
||||||
|
# &4 = Dunkelrot &c = Rot
|
||||||
|
# &5 = Lila &d = Pink
|
||||||
|
# &6 = Gold &e = Gelb
|
||||||
|
# &7 = Grau &f = Weiß
|
||||||
|
#
|
||||||
|
# &l = Fett
|
||||||
|
# &m = Durchgestrichen
|
||||||
|
# &n = Unterstrichen
|
||||||
|
# &o = Kursiv
|
||||||
|
# &r = Reset
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: VelocityFall
|
name: VelocityFall
|
||||||
version: 1.0.0
|
version: 1.0.1
|
||||||
main: de.velocityfall.VelocityFall
|
main: de.velocityfall.VelocityFall
|
||||||
api-version: 1.21
|
api-version: 1.21
|
||||||
author: M_Viper
|
author: M_Viper
|
||||||
|
|||||||
Reference in New Issue
Block a user