Fixed the first Duplication Glitch with this Plugin and released 1.1.

This commit is contained in:
2025-12-04 17:23:55 +01:00
parent 355b3cdc8f
commit 6b0c22b71f
4 changed files with 72 additions and 9 deletions

View File

@@ -6,7 +6,7 @@
<groupId>com.user404_</groupId> <groupId>com.user404_</groupId>
<artifactId>BalSync</artifactId> <artifactId>BalSync</artifactId>
<version>1.0</version> <version>1.1</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>BalSync</name> <name>BalSync</name>

View File

@@ -21,6 +21,7 @@ public class BalanceManager {
private BukkitTask dbPollingTask; private BukkitTask dbPollingTask;
private final Map<UUID, Double> lastKnownBalances = new HashMap<>(); private final Map<UUID, Double> lastKnownBalances = new HashMap<>();
private final Map<UUID, Double> lastKnownDbBalances = new HashMap<>(); private final Map<UUID, Double> lastKnownDbBalances = new HashMap<>();
public void saveAllBalances() { public void saveAllBalances() {
plugin.getPluginLogger().info("Saving all player balances to database..."); 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."); plugin.getPluginLogger().info("Saved " + saved + " player balances to database.");
}); });
} }
public BalanceManager(BalSyncPlugin plugin, Economy economy, DatabaseManager databaseManager) { public BalanceManager(BalSyncPlugin plugin, Economy economy, DatabaseManager databaseManager) {
this.plugin = plugin; this.plugin = plugin;
this.economy = economy; this.economy = economy;
@@ -227,18 +229,32 @@ public class BalanceManager {
Double lastBalance = lastKnownBalances.get(uuid); Double lastBalance = lastKnownBalances.get(uuid);
if (lastBalance != null && Math.abs(currentBalance - lastBalance) > 0.001) { 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 { 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); lastKnownBalances.put(uuid, currentBalance);
lastKnownDbBalances.put(uuid, newDbBalance);
plugin.getLogger().info("Detected offline change for " + 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) { } catch (SQLException e) {
plugin.getLogger().log(Level.WARNING, plugin.getPluginLogger().log(Level.WARNING,
"Failed to save offline change for " + offlinePlayer.getName(), e); "Failed to save offline change for " + offlinePlayer.getName(), e);
} }
} else if (lastBalance == null) { } 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); lastKnownBalances.put(uuid, currentBalance);
} }
} }
@@ -264,6 +280,23 @@ public class BalanceManager {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try { try {
double balance = economy.getBalance(player); 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); databaseManager.saveBalance(player.getUniqueId(), player.getName(), balance);
lastKnownBalances.put(player.getUniqueId(), balance); lastKnownBalances.put(player.getUniqueId(), balance);
lastKnownDbBalances.put(player.getUniqueId(), balance); lastKnownDbBalances.put(player.getUniqueId(), balance);

View File

@@ -64,7 +64,7 @@ public class DatabaseManager {
"`id` INT AUTO_INCREMENT PRIMARY KEY, " + "`id` INT AUTO_INCREMENT PRIMARY KEY, " +
"`player_uuid` CHAR(36) UNIQUE NOT NULL, " + "`player_uuid` CHAR(36) UNIQUE NOT NULL, " +
"`player_name` VARCHAR(16), " + "`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, " + "`last_updated` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
"INDEX `idx_uuid` (`player_uuid`)" + "INDEX `idx_uuid` (`player_uuid`)" +
") CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB", ") CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB",
@@ -111,7 +111,7 @@ public class DatabaseManager {
"`id` INT AUTO_INCREMENT PRIMARY KEY, " + "`id` INT AUTO_INCREMENT PRIMARY KEY, " +
"`player_uuid` CHAR(36) UNIQUE NOT NULL, " + "`player_uuid` CHAR(36) UNIQUE NOT NULL, " +
"`player_name` VARCHAR(16), " + "`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, " + "`last_updated` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
"INDEX `idx_uuid` (`player_uuid`)" + "INDEX `idx_uuid` (`player_uuid`)" +
") CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB", ") 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 { public Connection getConnection() throws SQLException {
return dataSource.getConnection(); return dataSource.getConnection();
} }

View File

@@ -1,5 +1,5 @@
name: BalSync name: BalSync
version: 1.0 version: 1.1
main: com.user404_.balsync.BalSyncPlugin main: com.user404_.balsync.BalSyncPlugin
api-version: '1.20' api-version: '1.20'
description: Synchronizes player balances with MySQL database description: Synchronizes player balances with MySQL database