From 6b0c22b71f8c919cd0f738cf3b218a9c078d9ed8 Mon Sep 17 00:00:00 2001 From: deutschich Date: Thu, 4 Dec 2025 17:23:55 +0100 Subject: [PATCH] Fixed the first Duplication Glitch with this Plugin and released 1.1. --- pom.xml | 2 +- .../com/user404_/balsync/BalanceManager.java | 43 ++++++++++++++++--- .../com/user404_/balsync/DatabaseManager.java | 34 ++++++++++++++- src/main/resources/plugin.yml | 2 +- 4 files changed, 72 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 70a6ae3..f552a8a 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.user404_ BalSync - 1.0 + 1.1 jar BalSync diff --git a/src/main/java/com/user404_/balsync/BalanceManager.java b/src/main/java/com/user404_/balsync/BalanceManager.java index 6849c98..f1af05f 100644 --- a/src/main/java/com/user404_/balsync/BalanceManager.java +++ b/src/main/java/com/user404_/balsync/BalanceManager.java @@ -21,6 +21,7 @@ public class BalanceManager { private BukkitTask dbPollingTask; private final Map lastKnownBalances = new HashMap<>(); private final Map lastKnownDbBalances = new HashMap<>(); + public void saveAllBalances() { plugin.getPluginLogger().info("Saving all player balances to database..."); @@ -43,6 +44,7 @@ public class BalanceManager { plugin.getPluginLogger().info("Saved " + saved + " player balances to database."); }); } + public BalanceManager(BalSyncPlugin plugin, Economy economy, DatabaseManager databaseManager) { this.plugin = plugin; this.economy = economy; @@ -227,18 +229,32 @@ public class BalanceManager { Double lastBalance = lastKnownBalances.get(uuid); if (lastBalance != null && Math.abs(currentBalance - lastBalance) > 0.001) { - // Balance has changed - save to database + // Balance has changed on this server. Instead of overwriting the DB with + // a stale server value, compute the delta and apply that to the DB. + double delta = currentBalance - lastBalance; try { - databaseManager.saveBalance(uuid, offlinePlayer.getName(), currentBalance); + databaseManager.addBalanceDelta(uuid, offlinePlayer.getName(), delta); + + // Refresh DB snapshot for tracking + double newDbBalance = databaseManager.getBalance(uuid); + lastKnownBalances.put(uuid, currentBalance); + lastKnownDbBalances.put(uuid, newDbBalance); + plugin.getLogger().info("Detected offline change for " + - offlinePlayer.getName() + ": " + currentBalance); + offlinePlayer.getName() + ": serverDelta=" + delta + ", newDB=" + newDbBalance); + + // Optional: send configured offline-change message to console/log + String msg = plugin.getTranslationManager().getMessage("offline-change-detected"); + if (msg != null && !msg.isEmpty()) { + plugin.getLogger().info(plugin.getTranslationManager().formatMessage("prefix") + msg); + } } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, + plugin.getPluginLogger().log(Level.WARNING, "Failed to save offline change for " + offlinePlayer.getName(), e); } } else if (lastBalance == null) { - // First time seeing this player, store initial balance + // First time seeing this player on this server, store initial balance lastKnownBalances.put(uuid, currentBalance); } } @@ -264,6 +280,23 @@ public class BalanceManager { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { try { double balance = economy.getBalance(player); + UUID uuid = player.getUniqueId(); + + Double lastBalance = lastKnownBalances.get(uuid); + if (lastBalance != null) { + // There is a last-known server-side snapshot => compute delta and apply it + double delta = balance - lastBalance; + if (Math.abs(delta) > 0.001) { + databaseManager.addBalanceDelta(uuid, player.getName(), delta); + + double newDb = databaseManager.getBalance(uuid); + lastKnownBalances.put(uuid, balance); + lastKnownDbBalances.put(uuid, newDb); + return; + } + } + + // Fallback: overwrite DB with current balance databaseManager.saveBalance(player.getUniqueId(), player.getName(), balance); lastKnownBalances.put(player.getUniqueId(), balance); lastKnownDbBalances.put(player.getUniqueId(), balance); diff --git a/src/main/java/com/user404_/balsync/DatabaseManager.java b/src/main/java/com/user404_/balsync/DatabaseManager.java index c937421..6e02f81 100644 --- a/src/main/java/com/user404_/balsync/DatabaseManager.java +++ b/src/main/java/com/user404_/balsync/DatabaseManager.java @@ -64,7 +64,7 @@ public class DatabaseManager { "`id` INT AUTO_INCREMENT PRIMARY KEY, " + "`player_uuid` CHAR(36) UNIQUE NOT NULL, " + "`player_name` VARCHAR(16), " + - "`balance` DECIMAL(15, 2) NOT NULL DEFAULT %.2f, " + // DECIMAL für bessere Präzision + "`balance` DECIMAL(15, 2) NOT NULL DEFAULT %.2f, " + "`last_updated` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " + "INDEX `idx_uuid` (`player_uuid`)" + ") CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB", @@ -111,7 +111,7 @@ public class DatabaseManager { "`id` INT AUTO_INCREMENT PRIMARY KEY, " + "`player_uuid` CHAR(36) UNIQUE NOT NULL, " + "`player_name` VARCHAR(16), " + - "`balance` DECIMAL(15, 2) NOT NULL, " + // Kein DEFAULT hier + "`balance` DECIMAL(15, 2) NOT NULL, " + "`last_updated` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " + "INDEX `idx_uuid` (`player_uuid`)" + ") CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB", @@ -158,6 +158,36 @@ public class DatabaseManager { } } + /** + * Atomically add a delta to the stored balance. This avoids overwriting the DB with stale + * values when multiple servers write concurrently. If no row exists, insert one with + * (startingBalance + delta). + */ + public void addBalanceDelta(UUID playerUUID, String playerName, double delta) throws SQLException { + String updateSql = String.format("UPDATE %s SET balance = balance + ? WHERE player_uuid = ?", tableName); + + try (Connection conn = dataSource.getConnection()) { + // Try atomic update first + try (PreparedStatement update = conn.prepareStatement(updateSql)) { + update.setDouble(1, delta); + update.setString(2, playerUUID.toString()); + int affected = update.executeUpdate(); + + if (affected == 0) { + // No row existed — insert with startingBalance + delta + double starting = plugin.getConfigManager().getStartingBalance(); + String insertSql = String.format("INSERT INTO %s (player_uuid, player_name, balance) VALUES (?, ?, ?)", tableName); + try (PreparedStatement insert = conn.prepareStatement(insertSql)) { + insert.setString(1, playerUUID.toString()); + insert.setString(2, playerName); + insert.setDouble(3, starting + delta); + insert.executeUpdate(); + } + } + } + } + } + public Connection getConnection() throws SQLException { return dataSource.getConnection(); } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5c3704e..7fca260 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: BalSync -version: 1.0 +version: 1.1 main: com.user404_.balsync.BalSyncPlugin api-version: '1.20' description: Synchronizes player balances with MySQL database