Update from Git Manager GUI

This commit is contained in:
2026-02-27 17:45:25 +01:00
parent 2f8bb3f566
commit b8a14fcffc
5 changed files with 95 additions and 50 deletions

View File

@@ -129,7 +129,7 @@ public class Ball {
if (entity == null || entity.isDead() || !active) return; if (entity == null || entity.isDead() || !active) return;
Location ballLoc = entity.getLocation(); Location ballLoc = entity.getLocation();
Vector dir = blendDirection(player, 0.65); Vector dir = blendDirection(player, 0.65);
double power = cfg("ball.header-power", 1.3); double power = cfg("gameplay.header-power", 1.3);
dir.setY(Math.max(dir.getY(), -0.05)); dir.setY(Math.max(dir.getY(), -0.05));
dir.multiply(power); dir.multiply(power);
applyKick(dir, ballLoc, 0.85f); applyKick(dir, ballLoc, 0.85f);

View File

@@ -352,6 +352,9 @@ public class Game {
state = GameState.RUNNING; state = GameState.RUNNING;
secondHalf = true; secondHalf = true;
timeLeft = arena.getGameDuration() / 2; timeLeft = arena.getGameDuration() / 2;
// Nachspielzeit der 1. Halbzeit zurücksetzen
injuryTimeBuffer = 0;
inInjuryTime = false;
// Seitenwechsel: Rotes Team → BlueSpawn, Blaues Team → RedSpawn // Seitenwechsel: Rotes Team → BlueSpawn, Blaues Team → RedSpawn
for (UUID uuid : redTeam) { Player p = Bukkit.getPlayer(uuid); if (p != null) p.teleport(arena.getBlueSpawn()); } for (UUID uuid : redTeam) { Player p = Bukkit.getPlayer(uuid); if (p != null) p.teleport(arena.getBlueSpawn()); }
@@ -572,6 +575,7 @@ public class Game {
// ════════════════════════════════════════════════════════════════════════ // ════════════════════════════════════════════════════════════════════════
private void startGameLoop() { private void startGameLoop() {
if (gameTask != null) { gameTask.cancel(); gameTask = null; }
gameTask = new BukkitRunnable() { gameTask = new BukkitRunnable() {
public void run() { public void run() {
if (state != GameState.RUNNING && state != GameState.OVERTIME) return; if (state != GameState.RUNNING && state != GameState.OVERTIME) return;
@@ -841,21 +845,32 @@ public class Game {
} }
private void checkPlayerBallInteraction() { private void checkPlayerBallInteraction() {
if (ball == null || !ball.isActive()) return; if (ball == null || !ball.isActive() || ball.isHeld()) return;
for (UUID uuid : allPlayers) { for (UUID uuid : allPlayers) {
Player p = Bukkit.getPlayer(uuid); Player p = Bukkit.getPlayer(uuid);
if (p == null) continue; if (p == null) continue;
if (ball.getDistanceTo(p) < 1.5) { if (ball.getDistanceTo(p) >= 1.5) continue;
if (throwInTeam != null && getTeam(p) != throwInTeam) continue; if (throwInTeam != null && getTeam(p) != throwInTeam) continue;
lastKicker = p.getUniqueId();
lastTouchTeam = getTeam(p); // ── Rückpass-Regel für Torwarte ──────────────────────────────────
kicks.merge(p.getUniqueId(), 1, Integer::sum); // Torwart im Auto-Kick: falls Ball vom Mitspieler per Fuß zugespielt → überspringen
throwInTeam = null; if (isGoalkeeper(p) && isInOwnHalf(p)) {
ball.kick(p); UUID prev = lastKicker;
if (prev != null && !prev.equals(uuid)) {
Player prevPlayer = Bukkit.getPlayer(prev);
if (prevPlayer != null && getTeam(prevPlayer) == getTeam(p) && !lastKickWasHeader) {
continue; // Rückpass auto-kick nicht ausführen
} }
} }
} }
throwInTeam = null;
setLastKicker(uuid); // korrekt: nutzt setLastKicker statt direktem Feldzugriff
ball.kick(p);
break; // pro Tick max. 1 Auto-Kick
}
}
// ════════════════════════════════════════════════════════════════════════ // ════════════════════════════════════════════════════════════════════════
// TOR // TOR
// ════════════════════════════════════════════════════════════════════════ // ════════════════════════════════════════════════════════════════════════
@@ -1452,12 +1467,20 @@ public class Game {
if (ball != null) ball.remove(); if (ball != null) ball.remove();
if (bossBar != null) { bossBar.removeAll(); bossBar = null; } if (bossBar != null) { bossBar.removeAll(); bossBar = null; }
outOfBoundsCountdown.clear(); outOfBoundsCountdown.clear();
headerCooldowns.clear();
freekickLocation = null; freekickLocation = null;
freekickTicks = 0; freekickTicks = 0;
throwInTeam = null; throwInTeam = null;
injuryTimeBuffer = 0;
inInjuryTime = false;
lastKicker = null;
secondLastKicker = null;
lastKickWasHeader = false;
// Persistente Statistiken speichern // Persistente Statistiken speichern
boolean draw = winner == null || redScore == blueScore; // BUG FIX: nach Elfmeter kann redScore == blueScore true sein obwohl ein Gewinner existiert.
// Einzig korrekte Quelle der Wahrheit ist das übergebene winner-Argument.
boolean draw = (winner == null);
Map<UUID, String> names = new HashMap<>(); Map<UUID, String> names = new HashMap<>();
for (UUID uuid : allPlayers) { Player p = Bukkit.getPlayer(uuid); if (p != null) names.put(uuid, p.getName()); } for (UUID uuid : allPlayers) { Player p = Bukkit.getPlayer(uuid); if (p != null) names.put(uuid, p.getName()); }
plugin.getStatsManager().flushKicks(kicks, names); plugin.getStatsManager().flushKicks(kicks, names);
@@ -1693,6 +1716,8 @@ public class Game {
public Map<UUID, Integer> getGoals() { return goals; } public Map<UUID, Integer> getGoals() { return goals; }
public Map<UUID, Integer> getKicks() { return kicks; } public Map<UUID, Integer> getKicks() { return kicks; }
public boolean isSecondHalf() { return secondHalf; } public boolean isSecondHalf() { return secondHalf; }
public boolean isInInjuryTime() { return inInjuryTime; }
public int getInjuryTimeBuffer() { return injuryTimeBuffer; }
public int getPenaltyRedGoals() { return penaltyRedGoals; } public int getPenaltyRedGoals() { return penaltyRedGoals; }
public int getPenaltyBlueGoals() { return penaltyBlueGoals; } public int getPenaltyBlueGoals() { return penaltyBlueGoals; }
/** Gibt zurück welches Team gerade Einwurf/Ecke/Abstoß hat (null = jeder darf) */ /** Gibt zurück welches Team gerade Einwurf/Ecke/Abstoß hat (null = jeder darf) */

View File

@@ -10,6 +10,8 @@ import org.bukkit.entity.Player;
* *
* Verfügbare Platzhalter: * Verfügbare Platzhalter:
* %fussball_goals% - Tore des Spielers (gesamt) * %fussball_goals% - Tore des Spielers (gesamt)
* %fussball_owngoals% - Eigentore des Spielers
* %fussball_assists% - Vorlagen des Spielers
* %fussball_kicks% - Schüsse des Spielers (gesamt) * %fussball_kicks% - Schüsse des Spielers (gesamt)
* %fussball_wins% - Siege des Spielers * %fussball_wins% - Siege des Spielers
* %fussball_losses% - Niederlagen des Spielers * %fussball_losses% - Niederlagen des Spielers
@@ -19,6 +21,8 @@ import org.bukkit.entity.Player;
* %fussball_ingame% - "true" / "false" ob Spieler gerade im Spiel ist * %fussball_ingame% - "true" / "false" ob Spieler gerade im Spiel ist
* %fussball_arena% - Name der aktuellen Arena (oder "") * %fussball_arena% - Name der aktuellen Arena (oder "")
* %fussball_score% - Aktueller Spielstand (z.B. "2 : 1") oder "" * %fussball_score% - Aktueller Spielstand (z.B. "2 : 1") oder ""
* %fussball_team% - Team des Spielers im aktuellen Spiel ("Rot"/"Blau"/"")
* %fussball_injurytime% - Aktuelle Nachspielzeit in Sekunden (0 wenn keine)
*/ */
public class FussballPlaceholders extends PlaceholderExpansion { public class FussballPlaceholders extends PlaceholderExpansion {
@@ -28,17 +32,10 @@ public class FussballPlaceholders extends PlaceholderExpansion {
this.plugin = plugin; this.plugin = plugin;
} }
@Override @Override public String getIdentifier() { return "fussball"; }
public String getIdentifier() { return "fussball"; } @Override public String getAuthor() { return "M_Viper"; }
@Override public String getVersion() { return plugin.getDescription().getVersion(); }
@Override @Override public boolean persist() { return true; }
public String getAuthor() { return "M_Viper"; }
@Override
public String getVersion() { return plugin.getDescription().getVersion(); }
@Override
public boolean persist() { return true; }
@Override @Override
public String onPlaceholderRequest(Player player, String identifier) { public String onPlaceholderRequest(Player player, String identifier) {
@@ -48,6 +45,8 @@ public class FussballPlaceholders extends PlaceholderExpansion {
return switch (identifier.toLowerCase()) { return switch (identifier.toLowerCase()) {
case "goals" -> String.valueOf(s.goals); case "goals" -> String.valueOf(s.goals);
case "owngoals" -> String.valueOf(s.ownGoals);
case "assists" -> String.valueOf(s.assists);
case "kicks" -> String.valueOf(s.kicks); case "kicks" -> String.valueOf(s.kicks);
case "wins" -> String.valueOf(s.wins); case "wins" -> String.valueOf(s.wins);
case "losses" -> String.valueOf(s.losses); case "losses" -> String.valueOf(s.losses);
@@ -63,6 +62,17 @@ public class FussballPlaceholders extends PlaceholderExpansion {
var game = plugin.getGameManager().getPlayerGame(player); var game = plugin.getGameManager().getPlayerGame(player);
yield game != null ? game.getRedScore() + " : " + game.getBlueScore() : ""; yield game != null ? game.getRedScore() + " : " + game.getBlueScore() : "";
} }
case "team" -> {
var game = plugin.getGameManager().getPlayerGame(player);
if (game == null) yield "";
de.fussball.plugin.game.Team t = game.getTeam(player);
yield t != null ? t.getDisplayName() : "";
}
case "injurytime" -> {
var game = plugin.getGameManager().getPlayerGame(player);
yield (game != null && game.isInInjuryTime())
? String.valueOf(game.getInjuryTimeBuffer()) : "0";
}
default -> null; default -> null;
}; };
} }

View File

@@ -64,15 +64,25 @@ public class FussballScoreboard {
// Zeit / Status-Zeile // Zeit / Status-Zeile
switch (game.getState()) { switch (game.getState()) {
case RUNNING, GOAL -> { case RUNNING, GOAL -> {
int m = game.getTimeLeft() / 60, s = game.getTimeLeft() % 60;
String half = game.isSecondHalf() ? "§72. HZ" : "§71. HZ"; String half = game.isSecondHalf() ? "§72. HZ" : "§71. HZ";
if (game.isInInjuryTime()) {
int injMins = (int) Math.ceil(game.getInjuryTimeBuffer() / 60.0);
set(obj, "§c⏱ +" + injMins + "' §7Nachsp. " + half, l--);
} else {
int m = game.getTimeLeft() / 60, s = game.getTimeLeft() % 60;
set(obj, "§e⏱ " + String.format("%02d:%02d", m, s) + " " + half, l--); set(obj, "§e⏱ " + String.format("%02d:%02d", m, s) + " " + half, l--);
} }
}
case HALFTIME -> set(obj, "§6⏸ HALBZEIT", l--); case HALFTIME -> set(obj, "§6⏸ HALBZEIT", l--);
case OVERTIME -> { case OVERTIME -> {
if (game.isInInjuryTime()) {
int injMins = (int) Math.ceil(game.getInjuryTimeBuffer() / 60.0);
set(obj, "§c⏱ +" + injMins + "' §6VL Nachsp.", l--);
} else {
int m = game.getTimeLeft() / 60, s = game.getTimeLeft() % 60; int m = game.getTimeLeft() / 60, s = game.getTimeLeft() % 60;
set(obj, "§e⏱ " + String.format("%02d:%02d", m, s) + " §6VL", l--); set(obj, "§e⏱ " + String.format("%02d:%02d", m, s) + " §6VL", l--);
} }
}
case PENALTY -> set(obj, "§c⚽ ELFMETER R" + game.getPenaltyRedGoals() + ":B" + game.getPenaltyBlueGoals(), l--); case PENALTY -> set(obj, "§c⚽ ELFMETER R" + game.getPenaltyRedGoals() + ":B" + game.getPenaltyBlueGoals(), l--);
case STARTING -> set(obj, "§e⏱ §6Startet gleich...", l--); case STARTING -> set(obj, "§e⏱ §6Startet gleich...", l--);
default -> set(obj, "§7⏳ Warte auf Spieler...", l--); default -> set(obj, "§7⏳ Warte auf Spieler...", l--);

View File

@@ -1,5 +1,5 @@
name: Fussball name: Fussball
version: 2.0.0 version: 1.0.0
main: de.fussball.plugin.Fussball main: de.fussball.plugin.Fussball
api-version: 1.21 api-version: 1.21
author: M_Viper author: M_Viper