Update from Git Manager GUI
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,40 @@ public class MySQLManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migriert den PRIMARY KEY von (uuid, item) auf (uuid, item, slot) falls nötig.
|
||||
* Nutzt DATABASE() um nur die aktuelle DB zu prüfen (kein Cross-DB-Problem).
|
||||
*/
|
||||
private void migrateTargetChestPrimaryKey(Statement st) {
|
||||
try {
|
||||
// Slot-Spalte zuerst sicherstellen (muss vor PK-Änderung existieren)
|
||||
// tryAlterColumn wurde bereits aufgerufen, hier nochmal sicher prüfen
|
||||
if (!columnExists("asc_target_chests", "slot")) {
|
||||
st.execute("ALTER TABLE asc_target_chests ADD COLUMN slot INT NOT NULL DEFAULT 0;");
|
||||
}
|
||||
|
||||
// Prüfen ob slot bereits im PRIMARY KEY ist
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"SELECT COUNT(*) FROM information_schema.KEY_COLUMN_USAGE " +
|
||||
"WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'asc_target_chests' " +
|
||||
"AND CONSTRAINT_NAME = 'PRIMARY' AND COLUMN_NAME = 'slot';")) {
|
||||
ResultSet rs = ps.executeQuery();
|
||||
if (rs.next() && rs.getInt(1) > 0) {
|
||||
rs.close();
|
||||
return; // Bereits migriert
|
||||
}
|
||||
rs.close();
|
||||
}
|
||||
|
||||
// Alten PK droppen und neuen mit slot anlegen
|
||||
st.execute("ALTER TABLE asc_target_chests DROP PRIMARY KEY, ADD PRIMARY KEY(uuid, item, slot);");
|
||||
} catch (SQLException e) {
|
||||
if (!e.getMessage().toLowerCase().contains("primary")) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
try {
|
||||
if (connection != null && !connection.isClosed()) connection.close();
|
||||
@@ -44,70 +78,238 @@ public class MySQLManager {
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// BungeeCord-Erweiterung: Sanfte Schema-Migration
|
||||
// Fügt eine Spalte hinzu, falls sie noch nicht existiert.
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
/**
|
||||
* Fügt eine Spalte hinzu, falls sie noch nicht existiert.
|
||||
* Nutzt DatabaseMetaData statt IF NOT EXISTS (kompatibel mit allen MySQL/MariaDB-Versionen).
|
||||
*/
|
||||
private void tryAlterColumn(Statement st, String table, String column, String definition) {
|
||||
try {
|
||||
ResultSet rs = st.getConnection().getMetaData().getColumns(null, null, table, column);
|
||||
if (!rs.next()) {
|
||||
st.execute("ALTER TABLE " + table + " ADD COLUMN " + column + " " + definition + ";");
|
||||
}
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
if (!e.getMessage().toLowerCase().contains("duplicate column")) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft ob eine Spalte in einer Tabelle existiert.
|
||||
*/
|
||||
private boolean columnExists(String table, String column) {
|
||||
try {
|
||||
ResultSet rs = connection.getMetaData().getColumns(null, null, table, column);
|
||||
boolean exists = rs.next();
|
||||
rs.close();
|
||||
return exists;
|
||||
} catch (SQLException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft ob ein Index/Constraint auf einer Tabelle existiert.
|
||||
*/
|
||||
private boolean indexExists(String table, String indexName) {
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"SELECT COUNT(*) FROM information_schema.STATISTICS " +
|
||||
"WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND INDEX_NAME = ?;")) {
|
||||
ps.setString(1, table);
|
||||
ps.setString(2, indexName);
|
||||
ResultSet rs = ps.executeQuery();
|
||||
boolean exists = rs.next() && rs.getInt(1) > 0;
|
||||
rs.close();
|
||||
return exists;
|
||||
} catch (SQLException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt alle Tabellen und führt automatisch alle Schema-Migrationen durch.
|
||||
* Bestehende Datenbanken älterer Versionen werden vollständig und sicher migriert:
|
||||
*
|
||||
* Alte Version → Neue Spalten:
|
||||
* asc_input_chests : +server
|
||||
* asc_rest_chests : +server
|
||||
* asc_target_chests : +slot, +server, PRIMARY KEY (uuid,item) → (uuid,item,slot)
|
||||
* asc_transfers : +target_server, +source_server
|
||||
* Neue Tabellen (falls fehlend):
|
||||
* asc_servers (BungeeCord Heartbeat)
|
||||
* asc_transfers (CrossLink Transfers)
|
||||
*/
|
||||
public void setupTables() {
|
||||
try (Statement st = connection.createStatement()) {
|
||||
st.execute("CREATE TABLE IF NOT EXISTS asc_players (uuid VARCHAR(36) PRIMARY KEY, name VARCHAR(32));");
|
||||
st.execute("CREATE TABLE IF NOT EXISTS asc_input_chests (uuid VARCHAR(36), chest_id VARCHAR(36), world VARCHAR(32), x INT, y INT, z INT, `public` BOOLEAN DEFAULT FALSE, PRIMARY KEY(uuid, chest_id));");
|
||||
st.execute("CREATE TABLE IF NOT EXISTS asc_target_chests (uuid VARCHAR(36), item VARCHAR(64), world VARCHAR(32), x INT, y INT, z INT, `public` BOOLEAN DEFAULT FALSE, PRIMARY KEY(uuid, item));");
|
||||
st.execute("CREATE TABLE IF NOT EXISTS asc_rest_chests (uuid VARCHAR(36), world VARCHAR(32), x INT, y INT, z INT, `public` BOOLEAN DEFAULT FALSE, PRIMARY KEY(uuid));");
|
||||
|
||||
// ── Basis-Tabellen anlegen (falls nicht vorhanden) ────────────────────
|
||||
st.execute("CREATE TABLE IF NOT EXISTS asc_players (" +
|
||||
"uuid VARCHAR(36) PRIMARY KEY, name VARCHAR(32)" +
|
||||
");");
|
||||
|
||||
st.execute("CREATE TABLE IF NOT EXISTS asc_input_chests (" +
|
||||
"uuid VARCHAR(36), chest_id VARCHAR(36), world VARCHAR(32)," +
|
||||
"x INT, y INT, z INT, `public` BOOLEAN DEFAULT FALSE," +
|
||||
"PRIMARY KEY(uuid, chest_id)" +
|
||||
");");
|
||||
|
||||
// asc_target_chests: neue Installs bekommen slot direkt im Schema.
|
||||
// Alte Installs werden weiter unten per Migration angepasst.
|
||||
st.execute("CREATE TABLE IF NOT EXISTS asc_target_chests (" +
|
||||
"uuid VARCHAR(36), item VARCHAR(64), slot INT NOT NULL DEFAULT 0," +
|
||||
"world VARCHAR(32), x INT, y INT, z INT, `public` BOOLEAN DEFAULT FALSE," +
|
||||
"PRIMARY KEY(uuid, item, slot)" +
|
||||
");");
|
||||
|
||||
st.execute("CREATE TABLE IF NOT EXISTS asc_rest_chests (" +
|
||||
"uuid VARCHAR(36), world VARCHAR(32)," +
|
||||
"x INT, y INT, z INT, `public` BOOLEAN DEFAULT FALSE," +
|
||||
"PRIMARY KEY(uuid)" +
|
||||
");");
|
||||
|
||||
// ── asc_transfers: immer beim Start sicherstellen ─────────────────────
|
||||
// (früher lazy – führte dazu dass target_server/source_server fehlten)
|
||||
st.execute("CREATE TABLE IF NOT EXISTS asc_transfers (" +
|
||||
"id BIGINT AUTO_INCREMENT PRIMARY KEY," +
|
||||
"uuid VARCHAR(36) NOT NULL," +
|
||||
"item VARCHAR(64) NOT NULL," +
|
||||
"amount INT NOT NULL," +
|
||||
"target_world VARCHAR(32) NOT NULL," +
|
||||
"created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP" +
|
||||
");");
|
||||
|
||||
// ── asc_servers: BungeeCord Heartbeat ────────────────────────────────
|
||||
st.execute("CREATE TABLE IF NOT EXISTS asc_servers (" +
|
||||
"server_name VARCHAR(64) PRIMARY KEY," +
|
||||
"last_seen TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
|
||||
");");
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════
|
||||
// SCHEMA-MIGRATIONEN (für bestehende Datenbanken älterer Versionen)
|
||||
// Jede Migration ist idempotent – mehrfaches Ausführen schadet nicht.
|
||||
// ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
// v1 → v2 (BungeeCord): server-Spalten
|
||||
tryAlterColumn(st, "asc_input_chests", "server", "VARCHAR(64) DEFAULT ''");
|
||||
tryAlterColumn(st, "asc_target_chests", "server", "VARCHAR(64) DEFAULT ''");
|
||||
tryAlterColumn(st, "asc_rest_chests", "server", "VARCHAR(64) DEFAULT ''");
|
||||
|
||||
// v1 → v2 (BungeeCord): Transfer-Routing-Spalten
|
||||
tryAlterColumn(st, "asc_transfers", "target_server", "VARCHAR(64) DEFAULT ''");
|
||||
tryAlterColumn(st, "asc_transfers", "source_server", "VARCHAR(64) DEFAULT ''");
|
||||
|
||||
// v2 → v3 (Multi-Target): slot-Spalte + PRIMARY KEY Migration
|
||||
migrateTargetChestPrimaryKey(st);
|
||||
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer-Tabelle für serverübergreifende Sortierung.
|
||||
* setupTransferTable() bleibt für Rückwärtskompatibilität erhalten,
|
||||
* delegiert aber nur noch an setupTables() da alles konsolidiert wurde.
|
||||
*/
|
||||
public void setupTransferTable() {
|
||||
try (Statement st = connection.createStatement()) {
|
||||
st.execute(
|
||||
"CREATE TABLE IF NOT EXISTS asc_transfers (" +
|
||||
" id BIGINT AUTO_INCREMENT PRIMARY KEY," +
|
||||
" uuid VARCHAR(36) NOT NULL," +
|
||||
" item VARCHAR(64) NOT NULL," +
|
||||
" amount INT NOT NULL," +
|
||||
" target_world VARCHAR(32) NOT NULL," +
|
||||
" created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP" +
|
||||
");"
|
||||
);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Transfers werden jetzt immer in setupTables() angelegt.
|
||||
// Diese Methode existiert nur noch damit bestehende Aufrufe nicht brechen.
|
||||
}
|
||||
|
||||
public void addTransfer(String uuid, String item, int amount, String targetWorld) {
|
||||
// ── BungeeCord NEU: Heartbeat ─────────────────────────────────────────────
|
||||
/**
|
||||
* Schreibt / aktualisiert den Heartbeat-Eintrag für diesen Server.
|
||||
* Sollte alle 30 Sekunden asynchron aufgerufen werden.
|
||||
*/
|
||||
public void heartbeat(String serverName) {
|
||||
if (serverName == null || serverName.isEmpty()) return;
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"INSERT INTO asc_transfers (uuid, item, amount, target_world) VALUES (?, ?, ?, ?);")) {
|
||||
ps.setString(1, uuid);
|
||||
ps.setString(2, item);
|
||||
ps.setInt(3, amount);
|
||||
ps.setString(4, targetWorld);
|
||||
"REPLACE INTO asc_servers (server_name, last_seen) VALUES (?, NOW());")) {
|
||||
ps.setString(1, serverName);
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getPendingTransfers(String uuid) {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
// ── BungeeCord NEU: Transfer mit Server-Routing ───────────────────────────
|
||||
/**
|
||||
* Legt einen Transfer-Eintrag mit explizitem Ziel-Server an.
|
||||
*/
|
||||
public void addTransfer(String uuid, String item, int amount,
|
||||
String targetWorld, String targetServer, String sourceServer) {
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"SELECT id, item, amount, target_world FROM asc_transfers WHERE uuid=? ORDER BY created_at ASC;")) {
|
||||
"INSERT INTO asc_transfers (uuid, item, amount, target_world, target_server, source_server) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?);")) {
|
||||
ps.setString(1, uuid);
|
||||
ps.setString(2, item);
|
||||
ps.setInt(3, amount);
|
||||
ps.setString(4, targetWorld);
|
||||
ps.setString(5, targetServer != null ? targetServer : "");
|
||||
ps.setString(6, sourceServer != null ? sourceServer : "");
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy-Überladung (ohne Server-Routing) – Rückwärtskompatibilität.
|
||||
*/
|
||||
public void addTransfer(String uuid, String item, int amount, String targetWorld) {
|
||||
addTransfer(uuid, item, amount, targetWorld, "", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt ausstehende Transfers zurück, gefiltert nach serverName.
|
||||
* serverName leer/null → alle Transfers (Legacy).
|
||||
* serverName gesetzt → nur Transfers mit target_server == serverName ODER target_server == '' (Legacy).
|
||||
*/
|
||||
public List<Map<String, Object>> getPendingTransfers(String uuid, String serverName) {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
try {
|
||||
PreparedStatement ps;
|
||||
if (serverName == null || serverName.isEmpty()) {
|
||||
ps = connection.prepareStatement(
|
||||
"SELECT id, item, amount, target_world, target_server, source_server " +
|
||||
"FROM asc_transfers WHERE uuid=? ORDER BY created_at ASC;");
|
||||
ps.setString(1, uuid);
|
||||
} else {
|
||||
ps = connection.prepareStatement(
|
||||
"SELECT id, item, amount, target_world, target_server, source_server " +
|
||||
"FROM asc_transfers WHERE uuid=? AND (target_server=? OR target_server='') " +
|
||||
"ORDER BY created_at ASC;");
|
||||
ps.setString(1, uuid);
|
||||
ps.setString(2, serverName);
|
||||
}
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("id", rs.getLong("id"));
|
||||
map.put("item", rs.getString("item"));
|
||||
map.put("amount", rs.getInt("amount"));
|
||||
map.put("target_world", rs.getString("target_world"));
|
||||
map.put("id", rs.getLong("id"));
|
||||
map.put("item", rs.getString("item"));
|
||||
map.put("amount", rs.getInt("amount"));
|
||||
map.put("target_world", rs.getString("target_world"));
|
||||
map.put("target_server", rs.getString("target_server"));
|
||||
map.put("source_server", rs.getString("source_server"));
|
||||
list.add(map);
|
||||
}
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/** Legacy-Überladung ohne serverName. */
|
||||
public List<Map<String, Object>> getPendingTransfers(String uuid) {
|
||||
return getPendingTransfers(uuid, "");
|
||||
}
|
||||
|
||||
public void deleteTransfer(long id) {
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"DELETE FROM asc_transfers WHERE id=?;")) {
|
||||
@@ -142,12 +344,6 @@ public class MySQLManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle Spieler aus der asc_players-Tabelle zurück.
|
||||
* Wird für den Export (MySQL → YAML) benötigt.
|
||||
*
|
||||
* @return Liste mit uuid und name je Spieler
|
||||
*/
|
||||
public List<Map<String, Object>> getAllPlayers() {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
try (Statement st = connection.createStatement();
|
||||
@@ -171,8 +367,15 @@ public class MySQLManager {
|
||||
}
|
||||
|
||||
public void addInputChest(String uuid, String chestId, String world, int x, int y, int z, boolean isPublic) {
|
||||
addInputChest(uuid, chestId, world, x, y, z, isPublic, "");
|
||||
}
|
||||
|
||||
/** BungeeCord-Überladung mit serverName. */
|
||||
public void addInputChest(String uuid, String chestId, String world,
|
||||
int x, int y, int z, boolean isPublic, String serverName) {
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"REPLACE INTO asc_input_chests (uuid, chest_id, world, x, y, z, `public`) VALUES (?, ?, ?, ?, ?, ?, ?);")) {
|
||||
"REPLACE INTO asc_input_chests (uuid, chest_id, world, x, y, z, `public`, server) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?);")) {
|
||||
ps.setString(1, uuid);
|
||||
ps.setString(2, chestId);
|
||||
ps.setString(3, world);
|
||||
@@ -180,6 +383,7 @@ public class MySQLManager {
|
||||
ps.setInt(5, y);
|
||||
ps.setInt(6, z);
|
||||
ps.setBoolean(7, isPublic);
|
||||
ps.setString(8, serverName != null ? serverName : "");
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
@@ -206,11 +410,13 @@ public class MySQLManager {
|
||||
while (rs.next()) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("chest_id", rs.getString("chest_id"));
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("public", rs.getBoolean("public"));
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("public", rs.getBoolean("public"));
|
||||
try { map.put("server", rs.getString("server")); }
|
||||
catch (SQLException ignored) { map.put("server", ""); }
|
||||
list.add(map);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
@@ -226,40 +432,118 @@ public class MySQLManager {
|
||||
}
|
||||
|
||||
public void setTargetChest(String uuid, String item, String world, int x, int y, int z, boolean isPublic) {
|
||||
setTargetChest(uuid, item, world, x, y, z, isPublic, "");
|
||||
}
|
||||
|
||||
/** BungeeCord-Überladung mit serverName. Slot=0 (Standard, erster Platz). */
|
||||
public void setTargetChest(String uuid, String item, String world,
|
||||
int x, int y, int z, boolean isPublic, String serverName) {
|
||||
setTargetChest(uuid, item, 0, world, x, y, z, isPublic, serverName);
|
||||
}
|
||||
|
||||
/** Vollständige Überladung mit slot für Multi-Target-Support. */
|
||||
public void setTargetChest(String uuid, String item, int slot, String world,
|
||||
int x, int y, int z, boolean isPublic, String serverName) {
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"REPLACE INTO asc_target_chests (uuid, item, world, x, y, z, `public`) VALUES (?, ?, ?, ?, ?, ?, ?);")) {
|
||||
"REPLACE INTO asc_target_chests (uuid, item, slot, world, x, y, z, `public`, server) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);")) {
|
||||
ps.setString(1, uuid);
|
||||
ps.setString(2, item);
|
||||
ps.setString(3, world);
|
||||
ps.setInt(4, x);
|
||||
ps.setInt(5, y);
|
||||
ps.setInt(6, z);
|
||||
ps.setBoolean(7, isPublic);
|
||||
ps.setInt(3, slot);
|
||||
ps.setString(4, world);
|
||||
ps.setInt(5, x);
|
||||
ps.setInt(6, y);
|
||||
ps.setInt(7, z);
|
||||
ps.setBoolean(8, isPublic);
|
||||
ps.setString(9, serverName != null ? serverName : "");
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> getTargetChest(String uuid, String item) {
|
||||
/** Löscht eine spezifische Slot-Zieltruhe und verschiebt höhere Slots nach unten. */
|
||||
public void removeTargetChestSlot(String uuid, String item, int slot) {
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"SELECT * FROM asc_target_chests WHERE uuid=? AND item=?;")) {
|
||||
"DELETE FROM asc_target_chests WHERE uuid=? AND item=? AND slot=?;")) {
|
||||
ps.setString(1, uuid);
|
||||
ps.setString(2, item);
|
||||
ps.setInt(3, slot);
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Slots nach dem gelöschten nach unten schieben
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"UPDATE asc_target_chests SET slot=slot-1 WHERE uuid=? AND item=? AND slot>?;")) {
|
||||
ps.setString(1, uuid);
|
||||
ps.setString(2, item);
|
||||
ps.setInt(3, slot);
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/** Gibt den nächsten freien Slot für ein Item zurück. */
|
||||
public int getNextTargetSlot(String uuid, String item) {
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"SELECT COALESCE(MAX(slot)+1, 0) AS next_slot FROM asc_target_chests WHERE uuid=? AND item=?;")) {
|
||||
ps.setString(1, uuid);
|
||||
ps.setString(2, item);
|
||||
ResultSet rs = ps.executeQuery();
|
||||
if (rs.next()) {
|
||||
if (rs.next()) return rs.getInt("next_slot");
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Zählt wie viele Zieltruhen für ein bestimmtes Item registriert sind. */
|
||||
public int countTargetChestsForItem(String uuid, String item) {
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"SELECT COUNT(*) FROM asc_target_chests WHERE uuid=? AND item=?;")) {
|
||||
ps.setString(1, uuid);
|
||||
ps.setString(2, item);
|
||||
ResultSet rs = ps.executeQuery();
|
||||
if (rs.next()) return rs.getInt(1);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Gibt die erste (slot=0) Zieltruhe für ein Item zurück (Legacy-Kompatibilität). */
|
||||
public Map<String, Object> getTargetChest(String uuid, String item) {
|
||||
List<Map<String, Object>> all = getTargetChestsForItem(uuid, item);
|
||||
return all.isEmpty() ? null : all.get(0);
|
||||
}
|
||||
|
||||
/** Gibt ALLE Zieltruhen für ein bestimmtes Item zurück, sortiert nach slot. */
|
||||
public List<Map<String, Object>> getTargetChestsForItem(String uuid, String item) {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"SELECT * FROM asc_target_chests WHERE uuid=? AND item=? ORDER BY slot ASC;")) {
|
||||
ps.setString(1, uuid);
|
||||
ps.setString(2, item);
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("item", rs.getString("item"));
|
||||
map.put("slot", rs.getInt("slot"));
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("public", rs.getBoolean("public"));
|
||||
return map;
|
||||
try { map.put("server", rs.getString("server")); }
|
||||
catch (SQLException ignored) { map.put("server", ""); }
|
||||
list.add(map);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
return list;
|
||||
}
|
||||
|
||||
public void removeTargetChest(String uuid, String item) {
|
||||
@@ -273,20 +557,24 @@ public class MySQLManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** Gibt alle Zieltruhen eines Spielers zurück, sortiert nach item + slot. */
|
||||
public List<Map<String, Object>> getTargetChests(String uuid) {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"SELECT * FROM asc_target_chests WHERE uuid=?;")) {
|
||||
"SELECT * FROM asc_target_chests WHERE uuid=? ORDER BY item ASC, slot ASC;")) {
|
||||
ps.setString(1, uuid);
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("item", rs.getString("item"));
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("item", rs.getString("item"));
|
||||
map.put("slot", rs.getInt("slot"));
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("public", rs.getBoolean("public"));
|
||||
try { map.put("server", rs.getString("server")); }
|
||||
catch (SQLException ignored) { map.put("server", ""); }
|
||||
list.add(map);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
@@ -302,14 +590,22 @@ public class MySQLManager {
|
||||
}
|
||||
|
||||
public void setRestChest(String uuid, String world, int x, int y, int z, boolean isPublic) {
|
||||
setRestChest(uuid, world, x, y, z, isPublic, "");
|
||||
}
|
||||
|
||||
/** BungeeCord-Überladung mit serverName. */
|
||||
public void setRestChest(String uuid, String world, int x, int y, int z,
|
||||
boolean isPublic, String serverName) {
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"REPLACE INTO asc_rest_chests (uuid, world, x, y, z, `public`) VALUES (?, ?, ?, ?, ?, ?);")) {
|
||||
"REPLACE INTO asc_rest_chests (uuid, world, x, y, z, `public`, server) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?);")) {
|
||||
ps.setString(1, uuid);
|
||||
ps.setString(2, world);
|
||||
ps.setInt(3, x);
|
||||
ps.setInt(4, y);
|
||||
ps.setInt(5, z);
|
||||
ps.setBoolean(6, isPublic);
|
||||
ps.setString(7, serverName != null ? serverName : "");
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
@@ -323,11 +619,13 @@ public class MySQLManager {
|
||||
ResultSet rs = ps.executeQuery();
|
||||
if (rs.next()) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("public", rs.getBoolean("public"));
|
||||
try { map.put("server", rs.getString("server")); }
|
||||
catch (SQLException ignored) { map.put("server", ""); }
|
||||
return map;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
@@ -346,7 +644,7 @@ public class MySQLManager {
|
||||
}
|
||||
}
|
||||
|
||||
// --- Hilfsmethoden für serverCrosslink ---
|
||||
// --- Hilfsmethoden für serverCrosslink (unverändert) ---
|
||||
|
||||
public List<Map<String, Object>> getAllInputChests() {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
@@ -355,12 +653,14 @@ public class MySQLManager {
|
||||
while (rs.next()) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("chest_id", rs.getString("chest_id"));
|
||||
map.put("uuid", rs.getString("uuid"));
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("public", rs.getBoolean("public"));
|
||||
map.put("uuid", rs.getString("uuid"));
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("public", rs.getBoolean("public"));
|
||||
try { map.put("server", rs.getString("server")); }
|
||||
catch (SQLException ignored) { map.put("server", ""); }
|
||||
list.add(map);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
@@ -375,13 +675,15 @@ public class MySQLManager {
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("item", rs.getString("item"));
|
||||
map.put("uuid", rs.getString("uuid"));
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("item", rs.getString("item"));
|
||||
map.put("uuid", rs.getString("uuid"));
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("public", rs.getBoolean("public"));
|
||||
try { map.put("server", rs.getString("server")); }
|
||||
catch (SQLException ignored) { map.put("server", ""); }
|
||||
list.add(map);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
@@ -396,12 +698,14 @@ public class MySQLManager {
|
||||
ResultSet rs = ps.executeQuery();
|
||||
if (rs.next()) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("uuid", rs.getString("uuid"));
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("uuid", rs.getString("uuid"));
|
||||
map.put("world", rs.getString("world"));
|
||||
map.put("x", rs.getInt("x"));
|
||||
map.put("y", rs.getInt("y"));
|
||||
map.put("z", rs.getInt("z"));
|
||||
map.put("public", rs.getBoolean("public"));
|
||||
try { map.put("server", rs.getString("server")); }
|
||||
catch (SQLException ignored) { map.put("server", ""); }
|
||||
return map;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
|
||||
@@ -32,6 +32,28 @@ mysql:
|
||||
# Soll serverübergreifendes Sortieren (mit MySQL) erlaubt sein?
|
||||
server_crosslink: true
|
||||
|
||||
# ---------------------------------------------------
|
||||
# BUNGEE CORD / MULTI-SERVER SETUP
|
||||
# ---------------------------------------------------
|
||||
# Eindeutiger Name dieses Servers im BungeeCord-Netzwerk.
|
||||
# WICHTIG: Jeder Server braucht einen anderen Namen!
|
||||
#
|
||||
# Beispiele:
|
||||
# server_name: "lobby"
|
||||
# server_name: "survival"
|
||||
# server_name: "creative"
|
||||
#
|
||||
# Leer lassen = Legacy-Modus (welt-basierte Erkennung, kein BungeeCord).
|
||||
# Fuer BungeeCord MUSS mysql.enabled: true gesetzt sein!
|
||||
#
|
||||
# Setup-Schritte:
|
||||
# 1. Gleiche MySQL-Datenbank auf allen Servern eintragen.
|
||||
# 2. Auf jedem Server einen einzigartigen server_name setzen.
|
||||
# 3. mysql.enabled: true und server_crosslink: true setzen.
|
||||
# 4. Alle Server neu starten - Schema wird automatisch migriert.
|
||||
|
||||
server_name: ""
|
||||
|
||||
# ---------------------------------------------------
|
||||
# SPRACHE (Language)
|
||||
# ---------------------------------------------------
|
||||
@@ -84,7 +106,6 @@ effects:
|
||||
# 30+ = SPARSAM (>1,5 Sekunden)
|
||||
# Für sehr große Server mit schwacher Hardware.
|
||||
#
|
||||
sort_interval_ticks: 5
|
||||
|
||||
sort_interval_ticks: 5
|
||||
|
||||
@@ -94,11 +115,35 @@ sort_interval_ticks: 5
|
||||
# Maximale Anzahl an Sortierkisten pro Spielergruppe
|
||||
|
||||
chest_limits:
|
||||
default: 50
|
||||
vip: 100
|
||||
# Beispiel für weitere Gruppen:
|
||||
# supporter: 150
|
||||
# admin: 200
|
||||
# Sollen Truhen-Limits aktiv sein? (true = ja, false = keine Beschraenkung)
|
||||
enabled: true
|
||||
|
||||
# Jede Gruppe hat eigene Limits fuer input, rest und target.
|
||||
# Spieler benoetigen die Permission: autosortchest.limit.<gruppe>
|
||||
|
||||
default:
|
||||
input: 1 # Eingangstruhen (Input)
|
||||
rest: 1 # Rest-Truhen (Fallback)
|
||||
target: 50 # Zieltruhen gesamt
|
||||
target_per_item: 1 # Wie viele Zieltruhen pro Item-Typ erlaubt sind
|
||||
|
||||
vip:
|
||||
input: 2
|
||||
rest: 2
|
||||
target: 100
|
||||
target_per_item: 3
|
||||
|
||||
# Weitere Gruppen:
|
||||
# supporter:
|
||||
# input: 3
|
||||
# rest: 2
|
||||
# target: 150
|
||||
# target_per_item: 5
|
||||
# admin:
|
||||
# input: 5
|
||||
# rest: 3
|
||||
# target: 200
|
||||
# target_per_item: 10
|
||||
|
||||
# ---------------------------------------------------
|
||||
# SCHILDFARBEN (Farbcodes wie im Chat)
|
||||
@@ -157,5 +202,4 @@ messages:
|
||||
target-chest-full: "&cZieltruhe für %item% ist voll! Koordinaten: (%x%, %y%, %z%)"
|
||||
mode-changed: "&aModus gewechselt: &e%mode%"
|
||||
mode-public: "&aÖffentlich"
|
||||
mode-private: "&cPrivat"
|
||||
|
||||
mode-private: "&cPrivat"
|
||||
@@ -1,5 +1,5 @@
|
||||
name: AutoSortChest
|
||||
version: 2.0
|
||||
version: 2.2
|
||||
main: com.viper.autosortchest.Main
|
||||
api-version: 1.21
|
||||
authors: [M_Viper]
|
||||
|
||||
Reference in New Issue
Block a user