From b15396ba1689953b429454ec66f9fe0452ce2c4b Mon Sep 17 00:00:00 2001 From: M_Viper Date: Fri, 27 Feb 2026 15:11:33 +0100 Subject: [PATCH] Update from Git Manager GUI --- .../java/de/fussball/plugin/arena/Arena.java | 26 ++++++- .../plugin/commands/FussballCommand.java | 36 ++++++++-- .../java/de/fussball/plugin/game/Game.java | 71 +++++++++++++++++-- .../plugin/listeners/BallListener.java | 1 - 4 files changed, 121 insertions(+), 13 deletions(-) diff --git a/src/main/java/de/fussball/plugin/arena/Arena.java b/src/main/java/de/fussball/plugin/arena/Arena.java index 3c2bb1f..30c1656 100644 --- a/src/main/java/de/fussball/plugin/arena/Arena.java +++ b/src/main/java/de/fussball/plugin/arena/Arena.java @@ -15,6 +15,8 @@ public class Arena implements ConfigurationSerializable { private Location fieldMin, fieldMax; // Strafräume – optional manuell gesetzt; sonst auto-berechnet aus Tor + config private Location redPenaltyMin, redPenaltyMax, bluePenaltyMin, bluePenaltyMax; + // Elfmeter-Punkte (optional – sonst wird ballSpawn genutzt) + private Location redPenaltySpot, bluePenaltySpot; private int minPlayers, maxPlayers, gameDuration; /** @@ -255,6 +257,8 @@ public class Arena implements ConfigurationSerializable { if (redPenaltyMax != null) map.put("redPenaltyMax", serLoc(redPenaltyMax)); if (bluePenaltyMin != null) map.put("bluePenaltyMin", serLoc(bluePenaltyMin)); if (bluePenaltyMax != null) map.put("bluePenaltyMax", serLoc(bluePenaltyMax)); + if (redPenaltySpot != null) map.put("redPenaltySpot", serLoc(redPenaltySpot)); + if (bluePenaltySpot != null) map.put("bluePenaltySpot", serLoc(bluePenaltySpot)); return map; } @@ -283,6 +287,8 @@ public class Arena implements ConfigurationSerializable { if (map.containsKey("redPenaltyMax")) a.redPenaltyMax = desLoc(map.get("redPenaltyMax")); if (map.containsKey("bluePenaltyMin")) a.bluePenaltyMin = desLoc(map.get("bluePenaltyMin")); if (map.containsKey("bluePenaltyMax")) a.bluePenaltyMax = desLoc(map.get("bluePenaltyMax")); + if (map.containsKey("redPenaltySpot")) a.redPenaltySpot = desLoc(map.get("redPenaltySpot")); + if (map.containsKey("bluePenaltySpot")) a.bluePenaltySpot = desLoc(map.get("bluePenaltySpot")); return a; } @@ -338,7 +344,25 @@ public class Arena implements ConfigurationSerializable { public void setBluePenaltyMin(Location l) { this.bluePenaltyMin = l; } public Location getBluePenaltyMax() { return bluePenaltyMax; } public void setBluePenaltyMax(Location l) { this.bluePenaltyMax = l; } - public boolean hasManualpPenaltyAreas() { return redPenaltyMin != null && redPenaltyMax != null + + // ── Elfmeter-Punkte ────────────────────────────────────────────────────── + public Location getRedPenaltySpot() { return redPenaltySpot; } + public void setRedPenaltySpot(Location l) { this.redPenaltySpot = l; } + public Location getBluePenaltySpot() { return bluePenaltySpot; } + public void setBluePenaltySpot(Location l) { this.bluePenaltySpot = l; } + + /** + * Gibt den Elfmeter-Punkt für ein Team zurück. + * Falls nicht gesetzt, wird ballSpawn als Fallback verwendet. + */ + public Location getPenaltySpot(de.fussball.plugin.game.Team team) { + if (team == de.fussball.plugin.game.Team.RED) { + return redPenaltySpot != null ? redPenaltySpot : ballSpawn; + } else { + return bluePenaltySpot != null ? bluePenaltySpot : ballSpawn; + } + } + public boolean hasManualPenaltyAreas() { return redPenaltyMin != null && redPenaltyMax != null && bluePenaltyMin != null && bluePenaltyMax != null; } public int getMinPlayers() { return minPlayers; } public void setMinPlayers(int n) { this.minPlayers = n; } diff --git a/src/main/java/de/fussball/plugin/commands/FussballCommand.java b/src/main/java/de/fussball/plugin/commands/FussballCommand.java index adad6f4..1e8b2fd 100644 --- a/src/main/java/de/fussball/plugin/commands/FussballCommand.java +++ b/src/main/java/de/fussball/plugin/commands/FussballCommand.java @@ -133,6 +133,22 @@ public class FussballCommand implements CommandExecutor, TabCompleter { sender.sendMessage(MessageUtil.success("Spiel in §e" + args[1] + " §aberendet.")); } + // ── Torwart manuell zuweisen ───────────────────────────────────────── + case "setgk" -> { + if (!sender.hasPermission("fussball.admin")) { sender.sendMessage(MessageUtil.error("Keine Berechtigung!")); return true; } + // Nutzung: /fb setgk + if (args.length < 3) { sender.sendMessage(MessageUtil.error("Benutze: /fb setgk ")); return true; } + Game gkGame = plugin.getGameManager().getGame(args[1]); + if (gkGame == null) { sender.sendMessage(MessageUtil.error("Kein aktives Spiel in §e" + args[1] + "§c!")); return true; } + Player target = Bukkit.getPlayerExact(args[2]); + if (target == null) { sender.sendMessage(MessageUtil.error("Spieler §e" + args[2] + " §cnicht online!")); return true; } + if (!gkGame.isInGame(target)) { sender.sendMessage(MessageUtil.error("§e" + args[2] + " §cist nicht in diesem Spiel!")); return true; } + if (!gkGame.setGoalkeeper(target)) { + sender.sendMessage(MessageUtil.error("Konnte Torwart nicht zuweisen – Spieler hat kein Team?")); + } else { + sender.sendMessage(MessageUtil.success("§e" + target.getName() + " §aist jetzt Torwart!")); + } + } case "top" -> { if (args.length < 2) { sender.sendMessage(MessageUtil.error("Benutze: /fussball top goals|wins|kicks")); @@ -163,8 +179,6 @@ public class FussballCommand implements CommandExecutor, TabCompleter { } case "kicks" -> { sender.sendMessage(MessageUtil.header("🏆 Top Schützen (Schüsse)")); - var list = plugin.getStatsManager().getTopScorers(10); - // Nutze getTopScorers und zeige kicks var kickList = new java.util.ArrayList<>(plugin.getStatsManager().getTopScorers(100)); kickList.sort((a, b) -> b.getValue().kicks - a.getValue().kicks); for (int i = 0; i < Math.min(10, kickList.size()); i++) { @@ -213,6 +227,8 @@ public class FussballCommand implements CommandExecutor, TabCompleter { case "redpenaltymax" -> { arena.setRedPenaltyMax(player.getLocation()); player.sendMessage(MessageUtil.success("Roter Strafraum Max gesetzt: " + locStr(player.getLocation()))); } case "bluepenaltymin" -> { arena.setBluePenaltyMin(player.getLocation()); player.sendMessage(MessageUtil.success("Blauer Strafraum Min gesetzt: "+ locStr(player.getLocation()))); } case "bluepenaltymax" -> { arena.setBluePenaltyMax(player.getLocation()); player.sendMessage(MessageUtil.success("Blauer Strafraum Max gesetzt: "+ locStr(player.getLocation()))); } + case "redpenaltyspot" -> { arena.setRedPenaltySpot(player.getLocation()); player.sendMessage(MessageUtil.success("Roter Elfmeter-Punkt gesetzt: " + locStr(player.getLocation()))); } + case "bluepenaltyspot" -> { arena.setBluePenaltySpot(player.getLocation()); player.sendMessage(MessageUtil.success("Blauer Elfmeter-Punkt gesetzt: " + locStr(player.getLocation()))); } case "minplayers" -> { if (args.length < 4) return; arena.setMinPlayers(Integer.parseInt(args[3])); player.sendMessage(MessageUtil.success("Min-Spieler: §e" + args[3])); } case "maxplayers" -> { if (args.length < 4) return; arena.setMaxPlayers(Integer.parseInt(args[3])); player.sendMessage(MessageUtil.success("Max-Spieler: §e" + args[3])); } case "duration" -> { if (args.length < 4) return; arena.setGameDuration(Integer.parseInt(args[3])); player.sendMessage(MessageUtil.success("Spieldauer: §e" + args[3] + "s")); } @@ -230,6 +246,8 @@ public class FussballCommand implements CommandExecutor, TabCompleter { + " §8(optional – sonst auto-berechnet)"); player.sendMessage("§7 Blauer Strafraum: " + check(arena.getBluePenaltyMin(), arena.getBluePenaltyMax()) + " §8(optional – sonst auto-berechnet)"); + player.sendMessage("§7 Roter Elfmeter-Punkt: " + check(arena.getRedPenaltySpot()) + " §8(optional – sonst ball-spawn)"); + player.sendMessage("§7 Blauer Elfmeter-Punkt: " + check(arena.getBluePenaltySpot()) + " §8(optional – sonst ball-spawn)"); player.sendMessage("§7 Min. Spieler: §e" + arena.getMinPlayers()); player.sendMessage("§7 Max. Spieler: §e" + arena.getMaxPlayers()); player.sendMessage("§7 Spieldauer: §e" + arena.getGameDuration() + "s"); @@ -327,14 +345,24 @@ public class FussballCommand implements CommandExecutor, TabCompleter { List list = new ArrayList<>(); if (args.length == 1) { list.addAll(List.of("join", "leave", "list", "stats", "top", "spectate")); - if (sender.hasPermission("fussball.admin")) list.addAll(List.of("create", "delete", "setup", "stop", "debug")); - } else if (args.length == 2 && List.of("join","delete","setup","stop","debug","spectate").contains(args[0].toLowerCase())) { + if (sender.hasPermission("fussball.admin")) list.addAll(List.of("create", "delete", "setup", "stop", "setgk", "debug")); + } else if (args.length == 2 && List.of("join","delete","setup","stop","setgk","debug","spectate").contains(args[0].toLowerCase())) { list.addAll(plugin.getArenaManager().getArenaNames()); + } else if (args.length == 3 && args[0].equalsIgnoreCase("setgk")) { + // Spielernamen aus dem aktiven Spiel vorschlagen + Game gkGame = plugin.getGameManager().getGame(args[1]); + if (gkGame != null) { + for (UUID uuid : gkGame.getAllPlayers()) { + Player p = Bukkit.getPlayer(uuid); + if (p != null) list.add(p.getName()); + } + } } else if (args.length == 3 && args[0].equalsIgnoreCase("setup")) { list.addAll(List.of("lobby","redspawn","bluespawn","ballspawn","center", "redgoalmin","redgoalmax","bluegoalmin","bluegoalmax", "fieldmin","fieldmax", "redpenaltymin","redpenaltymax","bluepenaltymin","bluepenaltymax", + "redpenaltyspot","bluepenaltyspot", "minplayers","maxplayers","duration","info")); } else if (args.length == 2 && args[0].equalsIgnoreCase("top")) { list.addAll(List.of("goals", "wins")); diff --git a/src/main/java/de/fussball/plugin/game/Game.java b/src/main/java/de/fussball/plugin/game/Game.java index d6212f5..b89117d 100644 --- a/src/main/java/de/fussball/plugin/game/Game.java +++ b/src/main/java/de/fussball/plugin/game/Game.java @@ -411,6 +411,9 @@ public class Game { for (UUID uuid : blueTeam) { Player p = Bukkit.getPlayer(uuid); if (p != null) { p.teleport(arena.getBlueSpawn()); p.sendTitle("§6§lVERLÄNGERUNG!", "§710 Minuten extra!", 10, 60, 10); } } if (bossBar != null) { bossBar.setColor(BarColor.YELLOW); bossBar.setTitle("§6VERLÄNGERUNG §c" + redScore + " §7: §9" + blueScore); } scoreboard.updateAll(); + + // Neuen Game-Loop für die Verlängerung starten + startGameLoop(); } // ════════════════════════════════════════════════════════════════════════ @@ -475,18 +478,18 @@ public class Game { for (UUID uuid : redTeam) { Player p = Bukkit.getPlayer(uuid); if (p != null && !p.equals(shooter)) p.teleport(arena.getRedSpawn()); } for (UUID uuid : blueTeam) { Player p = Bukkit.getPlayer(uuid); if (p != null && !p.equals(shooter)) p.teleport(arena.getBlueSpawn()); } - // Ball aufstellen + // Ball aufstellen – am Elfmeter-Punkt des schießenden Teams (Fallback: ballSpawn) if (ball != null) ball.remove(); - // KORREKTUR: Hier muss 'this' übergeben werden - ball = new Ball(this, plugin, arena.getBallSpawn()); + Location penaltySpot = arena.getPenaltySpot(penaltyTurn); + ball = new Ball(this, plugin, penaltySpot); spawnCooldown = 0; // Elfmeter sofort spielbar new BukkitRunnable() { - public void run() { ball.spawn(); lastBallLocation = arena.getBallSpawn().clone(); } + public void run() { ball.spawn(); lastBallLocation = penaltySpot.clone(); } }.runTaskLater(plugin, 2L); // Schützen vorbereiten if (shooter != null) { - shooter.teleport(arena.getBallSpawn()); + shooter.teleport(penaltySpot); shooter.sendTitle(teamColor + "Du schießt!", "§7Du hast §e15 Sekunden§7!", 10, 40, 10); shooter.sendMessage(MessageUtil.info("§eDu schießt den Elfmeter! Tritt auf den Ball!")); } else { @@ -525,7 +528,7 @@ public class Game { broadcastAll(c + "⚽ TREFFER! §7(" + penaltyRedGoals + ":" + penaltyBlueGoals + ")"); for (UUID uuid : allPlayers) { Player p = Bukkit.getPlayer(uuid); - if (p != null) { spawnFirework(arena.getBallSpawn(), penaltyTurn); p.playSound(p.getLocation(), Sound.ENTITY_FIREWORK_ROCKET_BLAST, 2f, 1f); } + if (p != null) { spawnFirework(arena.getPenaltySpot(penaltyTurn), penaltyTurn); p.playSound(p.getLocation(), Sound.ENTITY_FIREWORK_ROCKET_BLAST, 2f, 1f); } } scoreboard.updateAll(); advancePenaltyTurn(); @@ -1043,6 +1046,60 @@ public class Game { return uuid.equals(redGoalkeeper) || uuid.equals(blueGoalkeeper); } + /** + * Weist einem Spieler manuell die Torwart-Rolle zu. + * Der bisherige Torwart des Teams verliert seine TW-Rüstung und erhält normale Team-Rüstung. + * @return false wenn der Spieler nicht im entsprechenden Team ist + */ + public boolean setGoalkeeper(Player newGk) { + Team team = getTeam(newGk); + if (team == null) return false; + + // Bisherigen TW zurücksetzen + UUID oldGkUuid = (team == Team.RED) ? redGoalkeeper : blueGoalkeeper; + if (oldGkUuid != null && !oldGkUuid.equals(newGk.getUniqueId())) { + Player oldGk = Bukkit.getPlayer(oldGkUuid); + if (oldGk != null) { + applyTeamArmor(oldGk, team); + oldGk.sendMessage(MessageUtil.info("§7Du bist nicht mehr Torwart.")); + } + } + + // Neuen TW setzen + if (team == Team.RED) redGoalkeeper = newGk.getUniqueId(); + else blueGoalkeeper = newGk.getUniqueId(); + applyGoalkeeperArmor(newGk, team); + newGk.sendMessage(Messages.get("goalkeeper-assigned")); + broadcastAll(MessageUtil.info("§6" + newGk.getName() + " §7ist jetzt Torwart (" + team.getColorCode() + team.getDisplayName() + "§7).")); + return true; + } + + /** Gibt dem Spieler normale Team-Lederrüstung (ohne TW-Sonderlook) */ + private void applyTeamArmor(Player player, Team team) { + org.bukkit.Color c = team == Team.RED + ? org.bukkit.Color.fromRGB(180, 0, 0) + : org.bukkit.Color.fromRGB(0, 0, 200); + for (int slot = 0; slot < 4; slot++) { + Material mat = switch (slot) { + case 0 -> Material.LEATHER_BOOTS; + case 1 -> Material.LEATHER_LEGGINGS; + case 2 -> Material.LEATHER_CHESTPLATE; + default -> Material.LEATHER_HELMET; + }; + ItemStack item = new ItemStack(mat); + if (item.getItemMeta() instanceof org.bukkit.inventory.meta.LeatherArmorMeta meta) { + meta.setColor(c); + item.setItemMeta(meta); + } + switch (slot) { + case 0 -> player.getInventory().setBoots(item); + case 1 -> player.getInventory().setLeggings(item); + case 2 -> player.getInventory().setChestplate(item); + case 3 -> player.getInventory().setHelmet(item); + } + } + } + public boolean isInOwnHalf(Player player) { if (arena.getFieldDirection() == null) return true; double playerAxis = arena.getAxisValue(player.getLocation()); @@ -1400,7 +1457,7 @@ public class Game { throwInTeam = null; // Persistente Statistiken speichern - boolean draw = (winner == null || redScore == blueScore) && state != GameState.PENALTY; + boolean draw = winner == null || redScore == blueScore; Map names = new HashMap<>(); for (UUID uuid : allPlayers) { Player p = Bukkit.getPlayer(uuid); if (p != null) names.put(uuid, p.getName()); } plugin.getStatsManager().flushKicks(kicks, names); diff --git a/src/main/java/de/fussball/plugin/listeners/BallListener.java b/src/main/java/de/fussball/plugin/listeners/BallListener.java index cd6c12b..800a276 100644 --- a/src/main/java/de/fussball/plugin/listeners/BallListener.java +++ b/src/main/java/de/fussball/plugin/listeners/BallListener.java @@ -20,7 +20,6 @@ import org.bukkit.scheduler.BukkitRunnable; import java.util.HashMap; import java.util.Map; import java.util.UUID; -import java.util.UUID; /** * Verwaltet Ball-Interaktionen: