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() {
|
public void disconnect() {
|
||||||
try {
|
try {
|
||||||
if (connection != null && !connection.isClosed()) connection.close();
|
if (connection != null && !connection.isClosed()) connection.close();
|
||||||
@@ -44,55 +78,215 @@ 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() {
|
public void setupTables() {
|
||||||
try (Statement st = connection.createStatement()) {
|
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));");
|
// ── Basis-Tabellen anlegen (falls nicht vorhanden) ────────────────────
|
||||||
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_players (" +
|
||||||
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));");
|
"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) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
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() {
|
public void setupTransferTable() {
|
||||||
try (Statement st = connection.createStatement()) {
|
// Transfers werden jetzt immer in setupTables() angelegt.
|
||||||
st.execute(
|
// Diese Methode existiert nur noch damit bestehende Aufrufe nicht brechen.
|
||||||
"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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
try (PreparedStatement ps = connection.prepareStatement(
|
||||||
"INSERT INTO asc_transfers (uuid, item, amount, target_world) VALUES (?, ?, ?, ?);")) {
|
"REPLACE INTO asc_servers (server_name, last_seen) VALUES (?, NOW());")) {
|
||||||
ps.setString(1, uuid);
|
ps.setString(1, serverName);
|
||||||
ps.setString(2, item);
|
|
||||||
ps.setInt(3, amount);
|
|
||||||
ps.setString(4, targetWorld);
|
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Map<String, Object>> getPendingTransfers(String uuid) {
|
// ── BungeeCord NEU: Transfer mit Server-Routing ───────────────────────────
|
||||||
List<Map<String, Object>> list = new ArrayList<>();
|
/**
|
||||||
|
* 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(
|
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(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();
|
ResultSet rs = ps.executeQuery();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
@@ -100,14 +294,22 @@ public class MySQLManager {
|
|||||||
map.put("item", rs.getString("item"));
|
map.put("item", rs.getString("item"));
|
||||||
map.put("amount", rs.getInt("amount"));
|
map.put("amount", rs.getInt("amount"));
|
||||||
map.put("target_world", rs.getString("target_world"));
|
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);
|
list.add(map);
|
||||||
}
|
}
|
||||||
|
ps.close();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Legacy-Überladung ohne serverName. */
|
||||||
|
public List<Map<String, Object>> getPendingTransfers(String uuid) {
|
||||||
|
return getPendingTransfers(uuid, "");
|
||||||
|
}
|
||||||
|
|
||||||
public void deleteTransfer(long id) {
|
public void deleteTransfer(long id) {
|
||||||
try (PreparedStatement ps = connection.prepareStatement(
|
try (PreparedStatement ps = connection.prepareStatement(
|
||||||
"DELETE FROM asc_transfers WHERE id=?;")) {
|
"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() {
|
public List<Map<String, Object>> getAllPlayers() {
|
||||||
List<Map<String, Object>> list = new ArrayList<>();
|
List<Map<String, Object>> list = new ArrayList<>();
|
||||||
try (Statement st = connection.createStatement();
|
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) {
|
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(
|
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(1, uuid);
|
||||||
ps.setString(2, chestId);
|
ps.setString(2, chestId);
|
||||||
ps.setString(3, world);
|
ps.setString(3, world);
|
||||||
@@ -180,6 +383,7 @@ public class MySQLManager {
|
|||||||
ps.setInt(5, y);
|
ps.setInt(5, y);
|
||||||
ps.setInt(6, z);
|
ps.setInt(6, z);
|
||||||
ps.setBoolean(7, isPublic);
|
ps.setBoolean(7, isPublic);
|
||||||
|
ps.setString(8, serverName != null ? serverName : "");
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -211,6 +415,8 @@ public class MySQLManager {
|
|||||||
map.put("y", rs.getInt("y"));
|
map.put("y", rs.getInt("y"));
|
||||||
map.put("z", rs.getInt("z"));
|
map.put("z", rs.getInt("z"));
|
||||||
map.put("public", rs.getBoolean("public"));
|
map.put("public", rs.getBoolean("public"));
|
||||||
|
try { map.put("server", rs.getString("server")); }
|
||||||
|
catch (SQLException ignored) { map.put("server", ""); }
|
||||||
list.add(map);
|
list.add(map);
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} 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) {
|
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(
|
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(1, uuid);
|
||||||
ps.setString(2, item);
|
ps.setString(2, item);
|
||||||
ps.setString(3, world);
|
ps.setInt(3, slot);
|
||||||
ps.setInt(4, x);
|
ps.setString(4, world);
|
||||||
ps.setInt(5, y);
|
ps.setInt(5, x);
|
||||||
ps.setInt(6, z);
|
ps.setInt(6, y);
|
||||||
ps.setBoolean(7, isPublic);
|
ps.setInt(7, z);
|
||||||
|
ps.setBoolean(8, isPublic);
|
||||||
|
ps.setString(9, serverName != null ? serverName : "");
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
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(
|
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(1, uuid);
|
||||||
ps.setString(2, item);
|
ps.setString(2, item);
|
||||||
ResultSet rs = ps.executeQuery();
|
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<String, Object> map = new HashMap<>();
|
||||||
|
map.put("item", rs.getString("item"));
|
||||||
|
map.put("slot", rs.getInt("slot"));
|
||||||
map.put("world", rs.getString("world"));
|
map.put("world", rs.getString("world"));
|
||||||
map.put("x", rs.getInt("x"));
|
map.put("x", rs.getInt("x"));
|
||||||
map.put("y", rs.getInt("y"));
|
map.put("y", rs.getInt("y"));
|
||||||
map.put("z", rs.getInt("z"));
|
map.put("z", rs.getInt("z"));
|
||||||
map.put("public", rs.getBoolean("public"));
|
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) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return null;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeTargetChest(String uuid, String item) {
|
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) {
|
public List<Map<String, Object>> getTargetChests(String uuid) {
|
||||||
List<Map<String, Object>> list = new ArrayList<>();
|
List<Map<String, Object>> list = new ArrayList<>();
|
||||||
try (PreparedStatement ps = connection.prepareStatement(
|
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);
|
ps.setString(1, uuid);
|
||||||
ResultSet rs = ps.executeQuery();
|
ResultSet rs = ps.executeQuery();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
map.put("item", rs.getString("item"));
|
map.put("item", rs.getString("item"));
|
||||||
|
map.put("slot", rs.getInt("slot"));
|
||||||
map.put("world", rs.getString("world"));
|
map.put("world", rs.getString("world"));
|
||||||
map.put("x", rs.getInt("x"));
|
map.put("x", rs.getInt("x"));
|
||||||
map.put("y", rs.getInt("y"));
|
map.put("y", rs.getInt("y"));
|
||||||
map.put("z", rs.getInt("z"));
|
map.put("z", rs.getInt("z"));
|
||||||
map.put("public", rs.getBoolean("public"));
|
map.put("public", rs.getBoolean("public"));
|
||||||
|
try { map.put("server", rs.getString("server")); }
|
||||||
|
catch (SQLException ignored) { map.put("server", ""); }
|
||||||
list.add(map);
|
list.add(map);
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} 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) {
|
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(
|
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(1, uuid);
|
||||||
ps.setString(2, world);
|
ps.setString(2, world);
|
||||||
ps.setInt(3, x);
|
ps.setInt(3, x);
|
||||||
ps.setInt(4, y);
|
ps.setInt(4, y);
|
||||||
ps.setInt(5, z);
|
ps.setInt(5, z);
|
||||||
ps.setBoolean(6, isPublic);
|
ps.setBoolean(6, isPublic);
|
||||||
|
ps.setString(7, serverName != null ? serverName : "");
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -328,6 +624,8 @@ public class MySQLManager {
|
|||||||
map.put("y", rs.getInt("y"));
|
map.put("y", rs.getInt("y"));
|
||||||
map.put("z", rs.getInt("z"));
|
map.put("z", rs.getInt("z"));
|
||||||
map.put("public", rs.getBoolean("public"));
|
map.put("public", rs.getBoolean("public"));
|
||||||
|
try { map.put("server", rs.getString("server")); }
|
||||||
|
catch (SQLException ignored) { map.put("server", ""); }
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} 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() {
|
public List<Map<String, Object>> getAllInputChests() {
|
||||||
List<Map<String, Object>> list = new ArrayList<>();
|
List<Map<String, Object>> list = new ArrayList<>();
|
||||||
@@ -361,6 +659,8 @@ public class MySQLManager {
|
|||||||
map.put("y", rs.getInt("y"));
|
map.put("y", rs.getInt("y"));
|
||||||
map.put("z", rs.getInt("z"));
|
map.put("z", rs.getInt("z"));
|
||||||
map.put("public", rs.getBoolean("public"));
|
map.put("public", rs.getBoolean("public"));
|
||||||
|
try { map.put("server", rs.getString("server")); }
|
||||||
|
catch (SQLException ignored) { map.put("server", ""); }
|
||||||
list.add(map);
|
list.add(map);
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
@@ -382,6 +682,8 @@ public class MySQLManager {
|
|||||||
map.put("y", rs.getInt("y"));
|
map.put("y", rs.getInt("y"));
|
||||||
map.put("z", rs.getInt("z"));
|
map.put("z", rs.getInt("z"));
|
||||||
map.put("public", rs.getBoolean("public"));
|
map.put("public", rs.getBoolean("public"));
|
||||||
|
try { map.put("server", rs.getString("server")); }
|
||||||
|
catch (SQLException ignored) { map.put("server", ""); }
|
||||||
list.add(map);
|
list.add(map);
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
@@ -402,6 +704,8 @@ public class MySQLManager {
|
|||||||
map.put("y", rs.getInt("y"));
|
map.put("y", rs.getInt("y"));
|
||||||
map.put("z", rs.getInt("z"));
|
map.put("z", rs.getInt("z"));
|
||||||
map.put("public", rs.getBoolean("public"));
|
map.put("public", rs.getBoolean("public"));
|
||||||
|
try { map.put("server", rs.getString("server")); }
|
||||||
|
catch (SQLException ignored) { map.put("server", ""); }
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
|
|||||||
@@ -32,6 +32,28 @@ mysql:
|
|||||||
# Soll serverübergreifendes Sortieren (mit MySQL) erlaubt sein?
|
# Soll serverübergreifendes Sortieren (mit MySQL) erlaubt sein?
|
||||||
server_crosslink: true
|
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)
|
# SPRACHE (Language)
|
||||||
# ---------------------------------------------------
|
# ---------------------------------------------------
|
||||||
@@ -84,7 +106,6 @@ effects:
|
|||||||
# 30+ = SPARSAM (>1,5 Sekunden)
|
# 30+ = SPARSAM (>1,5 Sekunden)
|
||||||
# Für sehr große Server mit schwacher Hardware.
|
# Für sehr große Server mit schwacher Hardware.
|
||||||
#
|
#
|
||||||
sort_interval_ticks: 5
|
|
||||||
|
|
||||||
sort_interval_ticks: 5
|
sort_interval_ticks: 5
|
||||||
|
|
||||||
@@ -94,11 +115,35 @@ sort_interval_ticks: 5
|
|||||||
# Maximale Anzahl an Sortierkisten pro Spielergruppe
|
# Maximale Anzahl an Sortierkisten pro Spielergruppe
|
||||||
|
|
||||||
chest_limits:
|
chest_limits:
|
||||||
default: 50
|
# Sollen Truhen-Limits aktiv sein? (true = ja, false = keine Beschraenkung)
|
||||||
vip: 100
|
enabled: true
|
||||||
# Beispiel für weitere Gruppen:
|
|
||||||
# supporter: 150
|
# Jede Gruppe hat eigene Limits fuer input, rest und target.
|
||||||
# admin: 200
|
# 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)
|
# SCHILDFARBEN (Farbcodes wie im Chat)
|
||||||
@@ -158,4 +203,3 @@ messages:
|
|||||||
mode-changed: "&aModus gewechselt: &e%mode%"
|
mode-changed: "&aModus gewechselt: &e%mode%"
|
||||||
mode-public: "&aÖffentlich"
|
mode-public: "&aÖffentlich"
|
||||||
mode-private: "&cPrivat"
|
mode-private: "&cPrivat"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: AutoSortChest
|
name: AutoSortChest
|
||||||
version: 2.0
|
version: 2.2
|
||||||
main: com.viper.autosortchest.Main
|
main: com.viper.autosortchest.Main
|
||||||
api-version: 1.21
|
api-version: 1.21
|
||||||
authors: [M_Viper]
|
authors: [M_Viper]
|
||||||
|
|||||||
Reference in New Issue
Block a user