Update from Git Manager GUI

This commit is contained in:
2026-02-27 00:44:25 +01:00
parent f74701ecbe
commit e718d06473
20 changed files with 3679 additions and 0 deletions

View File

@@ -0,0 +1,253 @@
package de.fussball.plugin.arena;
import de.fussball.plugin.Fussball;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import java.util.*;
public class Arena implements ConfigurationSerializable {
private final String name;
private Location center, redSpawn, blueSpawn, ballSpawn;
private Location redGoalMin, redGoalMax, blueGoalMin, blueGoalMax, lobby;
private Location fieldMin, fieldMax;
private int minPlayers, maxPlayers, gameDuration;
/**
* Neue Arena erstellt Standardwerte werden aus der config.yml gelesen.
* Bereits gespeicherte Arenen laden ihre eigenen Werte über deserialize().
*/
public Arena(String name) {
this.name = name;
Fussball plugin = Fussball.getInstance();
if (plugin != null) {
this.minPlayers = plugin.getConfig().getInt("defaults.min-players", 2);
this.maxPlayers = plugin.getConfig().getInt("defaults.max-players", 10);
this.gameDuration = plugin.getConfig().getInt("defaults.game-duration", 300);
} else {
// Fallback falls getInstance() noch nicht verfügbar (z.B. Deserialisierung)
this.minPlayers = 2;
this.maxPlayers = 10;
this.gameDuration = 300;
}
}
public boolean isSetupComplete() {
return center != null && redSpawn != null && blueSpawn != null && ballSpawn != null
&& redGoalMin != null && redGoalMax != null
&& blueGoalMin != null && blueGoalMax != null && lobby != null;
}
public boolean isInRedGoal(Location loc) { return isInRegion(loc, redGoalMin, redGoalMax); }
public boolean isInBlueGoal(Location loc) { return isInRegion(loc, blueGoalMin, blueGoalMax); }
/**
* BUG FIX: Nur X und Z prüfen (Y ignorieren).
* Vorher führte die Y-Prüfung dazu, dass der Ball beim Anstoß sofort
* als Aus erkannt wurde, weil der ArmorStand über dem Boden schwebt.
*/
public boolean isInField(Location loc) {
if (fieldMin == null || fieldMax == null) return true;
return isInField2D(loc);
}
private boolean isInField2D(Location loc) {
if (fieldMin == null || fieldMax == null || loc == null) return true;
double minX = Math.min(fieldMin.getX(), fieldMax.getX());
double maxX = Math.max(fieldMin.getX(), fieldMax.getX());
double minZ = Math.min(fieldMin.getZ(), fieldMax.getZ());
double maxZ = Math.max(fieldMin.getZ(), fieldMax.getZ());
return loc.getX() >= minX && loc.getX() <= maxX
&& loc.getZ() >= minZ && loc.getZ() <= maxZ;
}
/** Auf welcher Seite hat der Ball das Feld verlassen? (nur XZ, kein Y) */
public String getOutSide(Location loc) {
if (fieldMin == null || fieldMax == null) return null;
if (isInField2D(loc)) return null;
double minX = Math.min(fieldMin.getX(), fieldMax.getX());
double maxX = Math.max(fieldMin.getX(), fieldMax.getX());
double minZ = Math.min(fieldMin.getZ(), fieldMax.getZ());
double maxZ = Math.max(fieldMin.getZ(), fieldMax.getZ());
double lenX = maxX - minX;
double lenZ = maxZ - minZ;
if (lenZ >= lenX) {
if (loc.getZ() < minZ) return "redEnd";
if (loc.getZ() > maxZ) return "blueEnd";
return "side";
} else {
if (loc.getX() < minX) return "redEnd";
if (loc.getX() > maxX) return "blueEnd";
return "side";
}
}
public Location clampToField(Location loc) {
if (fieldMin == null || fieldMax == null) return loc;
double x = Math.max(Math.min(fieldMin.getX(), fieldMax.getX()),
Math.min(loc.getX(), Math.max(fieldMin.getX(), fieldMax.getX())));
double y = loc.getY();
double z = Math.max(Math.min(fieldMin.getZ(), fieldMax.getZ()),
Math.min(loc.getZ(), Math.max(fieldMin.getZ(), fieldMax.getZ())));
return new Location(loc.getWorld(), x, y, z);
}
// Tor-Erkennung: volle 3D-Prüfung (Y ist für das Tor wichtig!)
private boolean isInRegion(Location loc, Location min, Location max) {
if (min == null || max == null || loc == null) return false;
if (loc.getWorld() == null || min.getWorld() == null) return false;
if (!loc.getWorld().equals(min.getWorld())) return false;
return loc.getX() >= Math.min(min.getX(), max.getX()) && loc.getX() <= Math.max(min.getX(), max.getX())
&& loc.getY() >= Math.min(min.getY(), max.getY()) && loc.getY() <= Math.max(min.getY(), max.getY())
&& loc.getZ() >= Math.min(min.getZ(), max.getZ()) && loc.getZ() <= Math.max(min.getZ(), max.getZ());
}
// ── Spielfeld-Achse (für Abseits-Berechnung) ────────────────────────────
/**
* Gibt den Einheitsvektor zurück der vom roten Tor zum blauen Tor zeigt.
* Funktioniert unabhängig davon ob das Feld in X- oder Z-Richtung ausgerichtet ist.
*/
public org.bukkit.util.Vector getFieldDirection() {
if (redGoalMin == null || redGoalMax == null || blueGoalMin == null || blueGoalMax == null) return null;
double rX = (redGoalMin.getX() + redGoalMax.getX()) / 2.0;
double rZ = (redGoalMin.getZ() + redGoalMax.getZ()) / 2.0;
double bX = (blueGoalMin.getX() + blueGoalMax.getX()) / 2.0;
double bZ = (blueGoalMin.getZ() + blueGoalMax.getZ()) / 2.0;
org.bukkit.util.Vector dir = new org.bukkit.util.Vector(bX - rX, 0, bZ - rZ);
double len = dir.length();
if (len < 0.001) return null;
return dir.multiply(1.0 / len);
}
/** Projektionswert einer Location auf die Spielfeld-Achse */
public double getAxisValue(org.bukkit.Location loc) {
org.bukkit.util.Vector dir = getFieldDirection();
if (dir == null || loc == null) return 0;
return loc.getX() * dir.getX() + loc.getZ() * dir.getZ();
}
public double getRedGoalAxisValue() {
if (redGoalMin == null || redGoalMax == null) return 0;
org.bukkit.util.Vector dir = getFieldDirection();
if (dir == null) return 0;
double cx = (redGoalMin.getX() + redGoalMax.getX()) / 2.0;
double cz = (redGoalMin.getZ() + redGoalMax.getZ()) / 2.0;
return cx * dir.getX() + cz * dir.getZ();
}
public double getBlueGoalAxisValue() {
if (blueGoalMin == null || blueGoalMax == null) return 0;
org.bukkit.util.Vector dir = getFieldDirection();
if (dir == null) return 0;
double cx = (blueGoalMin.getX() + blueGoalMax.getX()) / 2.0;
double cz = (blueGoalMin.getZ() + blueGoalMax.getZ()) / 2.0;
return cx * dir.getX() + cz * dir.getZ();
}
public double getCenterAxisValue() {
return (getRedGoalAxisValue() + getBlueGoalAxisValue()) / 2.0;
}
// ── Serialisierung ───────────────────────────────────────────────────────
@Override
public Map<String, Object> serialize() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("name", name);
map.put("minPlayers", minPlayers);
map.put("maxPlayers", maxPlayers);
map.put("gameDuration", gameDuration);
if (lobby != null) map.put("lobby", serLoc(lobby));
if (center != null) map.put("center", serLoc(center));
if (redSpawn != null) map.put("redSpawn", serLoc(redSpawn));
if (blueSpawn != null) map.put("blueSpawn", serLoc(blueSpawn));
if (ballSpawn != null) map.put("ballSpawn", serLoc(ballSpawn));
if (redGoalMin != null) map.put("redGoalMin", serLoc(redGoalMin));
if (redGoalMax != null) map.put("redGoalMax", serLoc(redGoalMax));
if (blueGoalMin != null) map.put("blueGoalMin", serLoc(blueGoalMin));
if (blueGoalMax != null) map.put("blueGoalMax", serLoc(blueGoalMax));
if (fieldMin != null) map.put("fieldMin", serLoc(fieldMin));
if (fieldMax != null) map.put("fieldMax", serLoc(fieldMax));
return map;
}
/**
* Beim Laden gespeicherter Arenen werden die eigenen Werte aus der YAML-Datei
* gelesen NICHT aus der config.yml. So kann jede Arena eigene Werte haben.
*/
public static Arena deserialize(Map<String, Object> map) {
Arena a = new Arena((String) map.get("name"));
// Überschreibe Konstruktor-Defaults mit den gespeicherten Werten
a.minPlayers = getInt(map, "minPlayers", a.minPlayers);
a.maxPlayers = getInt(map, "maxPlayers", a.maxPlayers);
a.gameDuration = getInt(map, "gameDuration", a.gameDuration);
if (map.containsKey("lobby")) a.lobby = desLoc(map.get("lobby"));
if (map.containsKey("center")) a.center = desLoc(map.get("center"));
if (map.containsKey("redSpawn")) a.redSpawn = desLoc(map.get("redSpawn"));
if (map.containsKey("blueSpawn")) a.blueSpawn = desLoc(map.get("blueSpawn"));
if (map.containsKey("ballSpawn")) a.ballSpawn = desLoc(map.get("ballSpawn"));
if (map.containsKey("redGoalMin")) a.redGoalMin = desLoc(map.get("redGoalMin"));
if (map.containsKey("redGoalMax")) a.redGoalMax = desLoc(map.get("redGoalMax"));
if (map.containsKey("blueGoalMin")) a.blueGoalMin = desLoc(map.get("blueGoalMin"));
if (map.containsKey("blueGoalMax")) a.blueGoalMax = desLoc(map.get("blueGoalMax"));
if (map.containsKey("fieldMin")) a.fieldMin = desLoc(map.get("fieldMin"));
if (map.containsKey("fieldMax")) a.fieldMax = desLoc(map.get("fieldMax"));
return a;
}
private static String serLoc(Location l) {
return l.getWorld().getName() + ";" + l.getX() + ";" + l.getY() + ";" + l.getZ() + ";" + l.getYaw() + ";" + l.getPitch();
}
private static Location desLoc(Object obj) {
if (obj == null) return null;
try {
String[] p = obj.toString().split(";");
World world = Bukkit.getWorld(p[0]);
if (world == null) return null;
return new Location(world, Double.parseDouble(p[1]), Double.parseDouble(p[2]), Double.parseDouble(p[3]),
p.length > 4 ? Float.parseFloat(p[4]) : 0f, p.length > 5 ? Float.parseFloat(p[5]) : 0f);
} catch (Exception e) { return null; }
}
private static int getInt(Map<String, Object> map, String key, int def) {
Object v = map.get(key); return v instanceof Number ? ((Number) v).intValue() : def;
}
// ── Getter / Setter ──────────────────────────────────────────────────────
public String getName() { return name; }
public Location getCenter() { return center; }
public void setCenter(Location l) { this.center = l; }
public Location getRedSpawn() { return redSpawn; }
public void setRedSpawn(Location l) { this.redSpawn = l; }
public Location getBlueSpawn() { return blueSpawn; }
public void setBlueSpawn(Location l) { this.blueSpawn = l; }
public Location getBallSpawn() { return ballSpawn; }
public void setBallSpawn(Location l) { this.ballSpawn = l; }
public Location getRedGoalMin() { return redGoalMin; }
public void setRedGoalMin(Location l) { this.redGoalMin = l; }
public Location getRedGoalMax() { return redGoalMax; }
public void setRedGoalMax(Location l) { this.redGoalMax = l; }
public Location getBlueGoalMin() { return blueGoalMin; }
public void setBlueGoalMin(Location l) { this.blueGoalMin = l; }
public Location getBlueGoalMax() { return blueGoalMax; }
public void setBlueGoalMax(Location l) { this.blueGoalMax = l; }
public Location getLobby() { return lobby; }
public void setLobby(Location l) { this.lobby = l; }
public Location getFieldMin() { return fieldMin; }
public void setFieldMin(Location l) { this.fieldMin = l; }
public Location getFieldMax() { return fieldMax; }
public void setFieldMax(Location l) { this.fieldMax = l; }
public int getMinPlayers() { return minPlayers; }
public void setMinPlayers(int n) { this.minPlayers = n; }
public int getMaxPlayers() { return maxPlayers; }
public void setMaxPlayers(int n) { this.maxPlayers = n; }
public int getGameDuration() { return gameDuration; }
public void setGameDuration(int n) { this.gameDuration = n; }
}