diff --git a/api/src/main/java/net/momirealms/customfishing/api/data/DataStorageInterface.java b/api/src/main/java/net/momirealms/customfishing/api/data/DataStorageInterface.java index b15a1598..34839ea0 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/data/DataStorageInterface.java +++ b/api/src/main/java/net/momirealms/customfishing/api/data/DataStorageInterface.java @@ -33,7 +33,7 @@ public interface DataStorageInterface { CompletableFuture> getPlayerData(UUID uuid, boolean force); - CompletableFuture setPlayerData(UUID uuid, PlayerData playerData, boolean unlock); + CompletableFuture savePlayerData(UUID uuid, PlayerData playerData, boolean unlock); - void setPlayersData(Collection users, boolean unlock); + void saveOnlinePlayersData(Collection users, boolean unlock); } diff --git a/api/src/main/java/net/momirealms/customfishing/api/data/PlayerData.java b/api/src/main/java/net/momirealms/customfishing/api/data/PlayerData.java index d2f9c67b..8fb06b33 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/data/PlayerData.java +++ b/api/src/main/java/net/momirealms/customfishing/api/data/PlayerData.java @@ -32,7 +32,7 @@ public class PlayerData { @SerializedName("trade") protected EarningData earningData; - public static PlayerData NEVER_PLAYED = empty(); + public static PlayerData LOCKED = empty(); public static PlayerData empty() { return new Builder() diff --git a/api/src/main/java/net/momirealms/customfishing/api/manager/BagManager.java b/api/src/main/java/net/momirealms/customfishing/api/manager/BagManager.java index f667aa3c..a7815987 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/manager/BagManager.java +++ b/api/src/main/java/net/momirealms/customfishing/api/manager/BagManager.java @@ -17,6 +17,8 @@ package net.momirealms.customfishing.api.manager; +import net.momirealms.customfishing.api.data.user.OfflineUser; +import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import java.util.UUID; @@ -25,4 +27,6 @@ public interface BagManager { boolean isBagEnabled(); Inventory getOnlineBagInventory(UUID uuid); + + void editOfflinePlayerBag(Player admin, OfflineUser userData); } diff --git a/api/src/main/java/net/momirealms/customfishing/api/manager/StorageManager.java b/api/src/main/java/net/momirealms/customfishing/api/manager/StorageManager.java index bec57ae5..985ccdde 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/manager/StorageManager.java +++ b/api/src/main/java/net/momirealms/customfishing/api/manager/StorageManager.java @@ -53,6 +53,8 @@ public interface StorageManager { */ CompletableFuture> getOfflineUser(UUID uuid, boolean force); + CompletableFuture saveUserData(OfflineUser offlineUser, boolean unlock); + /** * Get all the players in servers that connected to the same redis server * @return amount diff --git a/plugin/src/main/java/net/momirealms/customfishing/command/sub/FishingBagCommand.java b/plugin/src/main/java/net/momirealms/customfishing/command/sub/FishingBagCommand.java index 0f143859..ea514304 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/command/sub/FishingBagCommand.java +++ b/plugin/src/main/java/net/momirealms/customfishing/command/sub/FishingBagCommand.java @@ -19,14 +19,20 @@ package net.momirealms.customfishing.command.sub; import dev.jorel.commandapi.CommandAPICommand; import dev.jorel.commandapi.arguments.OfflinePlayerArgument; +import dev.jorel.commandapi.arguments.PlayerArgument; +import dev.jorel.commandapi.arguments.StringArgument; +import dev.jorel.commandapi.arguments.UUIDArgument; import net.momirealms.customfishing.adventure.AdventureManagerImpl; import net.momirealms.customfishing.api.CustomFishingPlugin; import net.momirealms.customfishing.api.data.user.OfflineUser; import net.momirealms.customfishing.setting.Locale; import net.momirealms.customfishing.storage.user.OfflineUserImpl; +import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; +import java.util.Objects; import java.util.UUID; public class FishingBagCommand { @@ -36,37 +42,59 @@ public class FishingBagCommand { public CommandAPICommand getBagCommand() { return new CommandAPICommand("fishingbag") .withPermission("fishingbag.user") - .withSubcommand(getAdminCommand()) + .withSubcommands(getEditOnlineCommand(), getEditOfflineCommand()) .executesPlayer(((player, args) -> { var inv = CustomFishingPlugin.get().getBagManager().getOnlineBagInventory(player.getUniqueId()); - if (inv != null) player.openInventory(inv); + if (inv != null) { + player.openInventory(inv); + } else { + AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, Locale.MSG_Data_Not_Loaded); + } })); } - private CommandAPICommand getAdminCommand() { - return new CommandAPICommand("edit") + private CommandAPICommand getEditOnlineCommand() { + return new CommandAPICommand("edit-online") .withPermission("fishingbag.admin") - .withArguments(new OfflinePlayerArgument("player")) + .withArguments(new PlayerArgument("player")) .executesPlayer(((player, args) -> { - OfflinePlayer offlinePlayer = (OfflinePlayer) args.get("player"); - UUID uuid = offlinePlayer.getUniqueId(); + Player player1 = (Player) args.get("player"); + UUID uuid = player1.getUniqueId(); Inventory onlineInv = CustomFishingPlugin.get().getBagManager().getOnlineBagInventory(uuid); if (onlineInv != null) { player.openInventory(onlineInv); - } else { - CustomFishingPlugin.get().getStorageManager().getOfflineUser(uuid, false).thenAccept(optional -> { - if (optional.isEmpty()) { - AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, Locale.MSG_Unsafe_Modification); - } else { - OfflineUser offlineUser = optional.get(); - if (offlineUser == OfflineUserImpl.NEVER_PLAYED_USER) { - AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, Locale.MSG_Never_Played); - } else { - - } - } - }); } + })); + } + + private CommandAPICommand getEditOfflineCommand() { + return new CommandAPICommand("edit-offline") + .withPermission("fishingbag.admin") + .withArguments(new UUIDArgument("UUID")) + .executesPlayer(((player, args) -> { + UUID uuid = (UUID) args.get("UUID"); + Player online = Bukkit.getPlayer(uuid); + if (online != null) { + Inventory onlineInv = CustomFishingPlugin.get().getBagManager().getOnlineBagInventory(uuid); + if (onlineInv != null) { + player.openInventory(onlineInv); + return; + } + } + CustomFishingPlugin.get().getStorageManager().getOfflineUser(uuid, false).thenAccept(optional -> { + if (optional.isEmpty()) { + AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, Locale.MSG_Never_Played); + return; + } + OfflineUser offlineUser = optional.get(); + if (offlineUser == OfflineUserImpl.LOCKED_USER) { + AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, Locale.MSG_Unsafe_Modification); + return; + } + CustomFishingPlugin.get().getScheduler().runTaskSync(() -> { + CustomFishingPlugin.get().getBagManager().editOfflinePlayerBag(player, offlineUser); + }, player.getLocation()); + }); })); } } diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/action/ActionManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/action/ActionManagerImpl.java index 47509011..408e916e 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/action/ActionManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/action/ActionManagerImpl.java @@ -268,7 +268,7 @@ public class ActionManagerImpl implements ActionManager { int delay; if (args instanceof ConfigurationSection section) { delay = section.getInt("delay", 1); - ConfigurationSection actionSection = section.getConfigurationSection("action"); + ConfigurationSection actionSection = section.getConfigurationSection("actions"); if (actionSection != null) { for (Map.Entry entry : actionSection.getValues(false).entrySet()) { if (entry.getValue() instanceof ConfigurationSection innerSection) { diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/bag/BagManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/bag/BagManagerImpl.java index 93e07e85..017a9303 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/bag/BagManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/bag/BagManagerImpl.java @@ -19,23 +19,31 @@ package net.momirealms.customfishing.mechanic.bag; import net.momirealms.customfishing.CustomFishingPluginImpl; import net.momirealms.customfishing.api.CustomFishingPlugin; +import net.momirealms.customfishing.api.data.user.OfflineUser; import net.momirealms.customfishing.api.manager.BagManager; import net.momirealms.customfishing.api.mechanic.bag.FishingBagHolder; import net.momirealms.customfishing.api.util.LogUtils; import net.momirealms.customfishing.setting.Config; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.Inventory; +import java.util.HashMap; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -public class BagManagerImpl implements BagManager { +public class BagManagerImpl implements BagManager, Listener { private final CustomFishingPlugin plugin; - private final ConcurrentHashMap bagMap; + private final HashMap tempEditMap; public BagManagerImpl(CustomFishingPluginImpl plugin) { this.plugin = plugin; - this.bagMap = new ConcurrentHashMap<>(); + this.tempEditMap = new HashMap<>(); } @Override @@ -44,11 +52,11 @@ public class BagManagerImpl implements BagManager { } public void load() { - + Bukkit.getPluginManager().registerEvents(this, plugin); } public void unload() { - + HandlerList.unregisterAll(this); } public void disable() { @@ -59,9 +67,33 @@ public class BagManagerImpl implements BagManager { public Inventory getOnlineBagInventory(UUID uuid) { var onlinePlayer = plugin.getStorageManager().getOnlineUser(uuid); if (onlinePlayer == null) { - LogUtils.warn("Player " + uuid + "'s bag data is not loaded."); return null; } return onlinePlayer.getHolder().getInventory(); } + + @Override + public void editOfflinePlayerBag(Player admin, OfflineUser userData) { + this.tempEditMap.put(admin.getUniqueId(), userData); + admin.openInventory(userData.getHolder().getInventory()); + } + + @EventHandler + public void onInvClose(InventoryCloseEvent event) { + if (!(event.getInventory().getHolder() instanceof FishingBagHolder)) + return; + final Player viewer = (Player) event.getPlayer(); + OfflineUser offlineUser = tempEditMap.remove(viewer.getUniqueId()); + if (offlineUser == null) + return; + plugin.getStorageManager().saveUserData(offlineUser, true); + } + + @EventHandler + public void onQuit(PlayerQuitEvent event) { + OfflineUser offlineUser = tempEditMap.remove(event.getPlayer().getUniqueId()); + if (offlineUser == null) + return; + plugin.getStorageManager().saveUserData(offlineUser, true); + } } diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/fishing/FishingManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/fishing/FishingManagerImpl.java index 6bbbdaaf..af1450ca 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/fishing/FishingManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/fishing/FishingManagerImpl.java @@ -468,7 +468,8 @@ public class FishingManagerImpl implements Listener, FishingManager { if (loot.getID().equals("vanilla")) { ItemStack itemStack = this.vanillaLootMap.remove(fishingPreparation.getPlayer().getUniqueId()); if (itemStack != null) { - fishingPreparation.insertArg("loot", ""); + fishingPreparation.insertArg("{nick}", ""); + fishingPreparation.insertArg("{loot}", itemStack.getType().toString()); } } diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/loot/LootManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/loot/LootManagerImpl.java index 3161ea82..47fb85a7 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/loot/LootManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/loot/LootManagerImpl.java @@ -134,8 +134,8 @@ public class LootManagerImpl implements LootManager { .showInFinder(section.getBoolean("show-in-fishfinder", showInFinder)) .gameConfig(section.getString("game-group", gameGroup)) .nick(section.getString("nick", section.getString("display.name", key))) - .addActions(getActionMap(section.getConfigurationSection("action"))) - .addTimesActions(getTimesActionMap(section.getConfigurationSection("action.success-times"))) + .addActions(getActionMap(section.getConfigurationSection("events"))) + .addTimesActions(getTimesActionMap(section.getConfigurationSection("events.success-times"))) .build(); } diff --git a/plugin/src/main/java/net/momirealms/customfishing/setting/Locale.java b/plugin/src/main/java/net/momirealms/customfishing/setting/Locale.java index 70330a06..f66d9ece 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/setting/Locale.java +++ b/plugin/src/main/java/net/momirealms/customfishing/setting/Locale.java @@ -55,6 +55,7 @@ public class Locale { public static String FORMAT_Hour; public static String FORMAT_Minute; public static String FORMAT_Second; + public static String MSG_Data_Not_Loaded; public static void load() { try { @@ -99,6 +100,7 @@ public class Locale { MSG_Give_Item = msgSection.getString("give-item"); MSG_Never_Played = msgSection.getString("never-played"); MSG_Unsafe_Modification = msgSection.getString("unsafe-modification"); + MSG_Data_Not_Loaded = msgSection.getString("data-not-loaded"); } } } diff --git a/plugin/src/main/java/net/momirealms/customfishing/storage/StorageManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/storage/StorageManagerImpl.java index 3cb98c4c..7d1997cd 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/storage/StorageManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/storage/StorageManagerImpl.java @@ -113,7 +113,7 @@ public class StorageManagerImpl implements StorageManager, Listener { this.timerSaveTask = this.plugin.getScheduler().runTaskAsyncTimer( () -> { long time1 = System.currentTimeMillis(); - this.dataSource.setPlayersData(this.onlineUserMap.values(), false); + this.dataSource.saveOnlinePlayersData(this.onlineUserMap.values(), false); LogUtils.info("Data Saved for online players. Took " + (System.currentTimeMillis() - time1) + "ms."); }, Config.dataSaveInterval, @@ -124,7 +124,7 @@ public class StorageManagerImpl implements StorageManager, Listener { public void disable() { HandlerList.unregisterAll(this); - this.dataSource.setPlayersData(onlineUserMap.values(), true); + this.dataSource.saveOnlinePlayersData(onlineUserMap.values(), true); this.onlineUserMap.clear(); if (this.dataSource != null) this.dataSource.disable(); @@ -151,15 +151,20 @@ public class StorageManagerImpl implements StorageManager, Listener { return CompletableFuture.completedFuture(Optional.empty()); } PlayerData data = optionalUser.get(); - if (data == PlayerData.NEVER_PLAYED) { - return CompletableFuture.completedFuture(Optional.of(OfflineUserImpl.NEVER_PLAYED_USER)); + if (data == PlayerData.LOCKED) { + return CompletableFuture.completedFuture(Optional.of(OfflineUserImpl.LOCKED_USER)); } else { - OfflineUserImpl offlineUser = new OfflineUserImpl(uuid, data.getName(), data); + OfflineUser offlineUser = new OfflineUserImpl(uuid, data.getName(), data); return CompletableFuture.completedFuture(Optional.of(offlineUser)); } }); } + @Override + public CompletableFuture saveUserData(OfflineUser offlineUser, boolean unlock) { + return dataSource.savePlayerData(offlineUser.getUUID(), offlineUser.getPlayerData(), unlock); + } + @Override public CompletableFuture getRedisPlayerCount() { return redisManager.getPlayerCount(); @@ -195,13 +200,13 @@ public class StorageManagerImpl implements StorageManager, Listener { if (hasRedis) { redisManager.setChangeServer(uuid).thenRun( - () -> redisManager.setPlayerData(uuid, data, true).thenRun( - () -> dataSource.setPlayerData(uuid, data, true).thenAccept( + () -> redisManager.savePlayerData(uuid, data, true).thenRun( + () -> dataSource.savePlayerData(uuid, data, true).thenAccept( result -> { if (result) locked.remove(uuid); }))); } else { - dataSource.setPlayerData(uuid, data, true).thenAccept( + dataSource.savePlayerData(uuid, data, true).thenAccept( result -> { if (result) locked.remove(uuid); }); @@ -210,8 +215,8 @@ public class StorageManagerImpl implements StorageManager, Listener { public void redisReadingData(UUID uuid) { // delay 0.5s for another server to insert the key - plugin.getScheduler().runTaskAsyncLater(() -> redisManager.getChangeServer(uuid).thenAccept(result -> { - if (!result) { + plugin.getScheduler().runTaskAsyncLater(() -> redisManager.getChangeServer(uuid).thenAccept(changeServer -> { + if (!changeServer) { waitForDataLockRelease(uuid, 3); } else { new RedisGetDataTask(uuid); @@ -260,11 +265,14 @@ public class StorageManagerImpl implements StorageManager, Listener { if (player == null || !player.isOnline() || times > 3) return; this.dataSource.getPlayerData(uuid, false).thenAccept(optionalData -> { - if (optionalData.isEmpty()) { - waitForDataLockRelease(uuid, times + 1); - } else { - putDataInCache(player, optionalData.get()); - } + // should not be empty + if (optionalData.isEmpty()) + return; + if (optionalData.get() == PlayerData.LOCKED) { + waitForDataLockRelease(uuid, times + 1); + } else { + putDataInCache(player, optionalData.get()); + } }); }, 1, TimeUnit.SECONDS); } diff --git a/plugin/src/main/java/net/momirealms/customfishing/storage/method/AbstractStorage.java b/plugin/src/main/java/net/momirealms/customfishing/storage/method/AbstractStorage.java index 6dbfe84e..6f3e05a3 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/storage/method/AbstractStorage.java +++ b/plugin/src/main/java/net/momirealms/customfishing/storage/method/AbstractStorage.java @@ -47,9 +47,9 @@ public abstract class AbstractStorage implements DataStorageInterface { } @Override - public void setPlayersData(Collection users, boolean unlock) { + public void saveOnlinePlayersData(Collection users, boolean unlock) { for (OnlineUser user : users) { - this.setPlayerData(user.getUUID(), user.getPlayerData(), unlock); + this.savePlayerData(user.getUUID(), user.getPlayerData(), unlock); } } } diff --git a/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/nosql/MongoDBImpl.java b/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/nosql/MongoDBImpl.java index f2faad68..05c017f2 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/nosql/MongoDBImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/nosql/MongoDBImpl.java @@ -112,17 +112,17 @@ public class MongoDBImpl extends AbstractStorage { public CompletableFuture> getPlayerData(UUID uuid, boolean force) { var future = new CompletableFuture>(); plugin.getScheduler().runTaskAsync(() -> { - MongoCollection collection = database.getCollection("movies"); + MongoCollection collection = database.getCollection(getCollectionName("data")); Document doc = collection.find(Filters.eq("uuid", uuid)).first(); if (doc == null) { if (Bukkit.getPlayer(uuid) != null) { future.complete(Optional.of(PlayerData.empty())); } else { - future.complete(Optional.of(PlayerData.NEVER_PLAYED)); + future.complete(Optional.empty()); } } else { if (!force && doc.getInteger("lock") != 0) { - future.complete(Optional.empty()); + future.complete(Optional.of(PlayerData.LOCKED)); return; } Binary binary = (Binary) doc.get("data"); @@ -133,7 +133,7 @@ public class MongoDBImpl extends AbstractStorage { } @Override - public CompletableFuture setPlayerData(UUID uuid, PlayerData playerData, boolean unlock) { + public CompletableFuture savePlayerData(UUID uuid, PlayerData playerData, boolean unlock) { var future = new CompletableFuture(); plugin.getScheduler().runTaskAsync(() -> { MongoCollection collection = database.getCollection(getCollectionName("data")); @@ -152,7 +152,7 @@ public class MongoDBImpl extends AbstractStorage { } @Override - public void setPlayersData(Collection users, boolean unlock) { + public void saveOnlinePlayersData(Collection users, boolean unlock) { MongoCollection collection = database.getCollection(getCollectionName("data")); try { collection.insertMany(users.stream().map(it -> new Document() diff --git a/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/nosql/RedisManager.java b/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/nosql/RedisManager.java index b98d9ccc..c5d26b8c 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/nosql/RedisManager.java +++ b/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/nosql/RedisManager.java @@ -256,7 +256,7 @@ public class RedisManager extends AbstractStorage { } @Override - public CompletableFuture setPlayerData(UUID uuid, PlayerData playerData, boolean ignore) { + public CompletableFuture savePlayerData(UUID uuid, PlayerData playerData, boolean ignore) { var future = new CompletableFuture(); plugin.getScheduler().runTaskAsync(() -> { try (Jedis jedis = jedisPool.getResource()) { diff --git a/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/sql/AbstractSQLDatabase.java b/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/sql/AbstractSQLDatabase.java index 04bc8e68..842fa69c 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/sql/AbstractSQLDatabase.java +++ b/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/sql/AbstractSQLDatabase.java @@ -91,22 +91,21 @@ public abstract class AbstractSQLDatabase extends AbstractStorage { if (rs.next()) { int lock = rs.getInt(2); if (!force && (lock != 0 && getCurrentSeconds() - Config.dataSaveInterval <= lock)) { - statement.close(); - rs.close(); - connection.close(); - future.complete(Optional.empty()); + statement.close(); rs.close(); connection.close(); + future.complete(Optional.of(PlayerData.LOCKED)); return; } final Blob blob = rs.getBlob("data"); final byte[] dataByteArray = blob.getBytes(1, (int) blob.length()); blob.free(); + lockPlayerData(uuid); future.complete(Optional.of(plugin.getStorageManager().fromBytes(dataByteArray))); } else if (Bukkit.getPlayer(uuid) != null) { var data = PlayerData.empty(); insertPlayerData(uuid, data); future.complete(Optional.of(data)); } else { - future.complete(Optional.of(PlayerData.NEVER_PLAYED)); + future.complete(Optional.empty()); } } catch (SQLException e) { LogUtils.warn("Failed to get " + uuid + "'s data.", e); @@ -117,7 +116,7 @@ public abstract class AbstractSQLDatabase extends AbstractStorage { } @Override - public CompletableFuture setPlayerData(UUID uuid, PlayerData playerData, boolean unlock) { + public CompletableFuture savePlayerData(UUID uuid, PlayerData playerData, boolean unlock) { var future = new CompletableFuture(); plugin.getScheduler().runTaskAsync(() -> { try ( @@ -138,7 +137,7 @@ public abstract class AbstractSQLDatabase extends AbstractStorage { } @Override - public void setPlayersData(Collection users, boolean unlock) { + public void saveOnlinePlayersData(Collection users, boolean unlock) { String sql = String.format(SqlConstants.SQL_UPDATE_BY_UUID, getTableName("data")); try (Connection connection = getConnection()) { connection.setAutoCommit(false); @@ -174,9 +173,23 @@ public abstract class AbstractSQLDatabase extends AbstractStorage { } } + public void lockPlayerData(UUID uuid) { + try ( + Connection connection = getConnection(); + PreparedStatement statement = connection.prepareStatement(String.format(SqlConstants.SQL_LOCK_BY_UUID, getTableName("data"))) + ) { + statement.setInt(1, getCurrentSeconds()); + statement.setString(2, uuid.toString()); + statement.execute(); + } catch (SQLException e) { + LogUtils.warn("Failed to lock " + uuid + "'s data.", e); + } + } + public static class SqlConstants { public static final String SQL_SELECT_BY_UUID = "SELECT * FROM `%s` WHERE `uuid` = ?"; public static final String SQL_UPDATE_BY_UUID = "UPDATE `%s` SET `lock` = ?, `data` = ? WHERE `uuid` = ?"; + public static final String SQL_LOCK_BY_UUID = "UPDATE `%s` SET `lock` = ? WHERE `uuid` = ?"; public static final String SQL_INSERT_DATA_BY_UUID = "INSERT INTO `%s`(`uuid`, `lock`, `data`) VALUES(?, ?, ?)"; } } diff --git a/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/sql/SQLiteImpl.java b/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/sql/SQLiteImpl.java index 38b22709..da015cb5 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/sql/SQLiteImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/sql/SQLiteImpl.java @@ -90,20 +90,19 @@ public class SQLiteImpl extends AbstractSQLDatabase { if (rs.next()) { int lock = rs.getInt(2); if (!force && (lock != 0 && getCurrentSeconds() - Config.dataSaveInterval <= lock)) { - statement.close(); - rs.close(); - connection.close(); - future.complete(Optional.empty()); + statement.close(); rs.close(); connection.close(); + future.complete(Optional.of(PlayerData.LOCKED)); return; } final byte[] dataByteArray = rs.getBytes("data"); + lockPlayerData(uuid); future.complete(Optional.of(plugin.getStorageManager().fromBytes(dataByteArray))); } else if (Bukkit.getPlayer(uuid) != null) { var data = PlayerData.empty(); insertPlayerData(uuid, data); future.complete(Optional.of(data)); } else { - future.complete(Optional.of(PlayerData.NEVER_PLAYED)); + future.complete(Optional.empty()); } } catch (SQLException e) { LogUtils.warn("Failed to get " + uuid + "'s data.", e); @@ -114,7 +113,7 @@ public class SQLiteImpl extends AbstractSQLDatabase { } @Override - public CompletableFuture setPlayerData(UUID uuid, PlayerData playerData, boolean unlock) { + public CompletableFuture savePlayerData(UUID uuid, PlayerData playerData, boolean unlock) { var future = new CompletableFuture(); plugin.getScheduler().runTaskAsync(() -> { try ( @@ -135,7 +134,7 @@ public class SQLiteImpl extends AbstractSQLDatabase { } @Override - public void setPlayersData(Collection users, boolean unlock) { + public void saveOnlinePlayersData(Collection users, boolean unlock) { String sql = String.format(SqlConstants.SQL_UPDATE_BY_UUID, getTableName("data")); try (Connection connection = getConnection()) { connection.setAutoCommit(false); diff --git a/plugin/src/main/java/net/momirealms/customfishing/storage/method/file/JsonImpl.java b/plugin/src/main/java/net/momirealms/customfishing/storage/method/file/JsonImpl.java index 00b1c883..acedc071 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/storage/method/file/JsonImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/storage/method/file/JsonImpl.java @@ -55,13 +55,13 @@ public class JsonImpl extends AbstractStorage { } else if (Bukkit.getPlayer(uuid) != null) { playerData = PlayerData.empty(); } else { - playerData = PlayerData.NEVER_PLAYED; + playerData = null; } - return CompletableFuture.completedFuture(Optional.of(playerData)); + return CompletableFuture.completedFuture(Optional.ofNullable(playerData)); } @Override - public CompletableFuture setPlayerData(UUID uuid, PlayerData playerData, boolean ignore) { + public CompletableFuture savePlayerData(UUID uuid, PlayerData playerData, boolean ignore) { this.saveToJsonFile(playerData, getPlayerDataFile(uuid)); return CompletableFuture.completedFuture(true); } diff --git a/plugin/src/main/java/net/momirealms/customfishing/storage/method/file/YAMLImpl.java b/plugin/src/main/java/net/momirealms/customfishing/storage/method/file/YAMLImpl.java index 8307f6ed..af90882e 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/storage/method/file/YAMLImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/storage/method/file/YAMLImpl.java @@ -56,9 +56,9 @@ public class YAMLImpl extends AbstractStorage { File dataFile = getPlayerDataFile(uuid); if (!dataFile.exists()) { if (Bukkit.getPlayer(uuid) != null) { - return CompletableFuture.completedFuture(Optional.of(PlayerData.empty())); + return CompletableFuture.completedFuture(Optional.of(PlayerData.LOCKED)); } else { - return CompletableFuture.completedFuture(Optional.of(PlayerData.NEVER_PLAYED)); + return CompletableFuture.completedFuture(Optional.of(PlayerData.empty())); } } YamlConfiguration data = ConfigUtils.readData(dataFile); @@ -72,7 +72,7 @@ public class YAMLImpl extends AbstractStorage { } @Override - public CompletableFuture setPlayerData(UUID uuid, PlayerData playerData, boolean ignore) { + public CompletableFuture savePlayerData(UUID uuid, PlayerData playerData, boolean ignore) { YamlConfiguration data = new YamlConfiguration(); data.set("name", playerData.getName()); data.set("bag", playerData.getBagData().serialized); diff --git a/plugin/src/main/java/net/momirealms/customfishing/storage/user/OfflineUserImpl.java b/plugin/src/main/java/net/momirealms/customfishing/storage/user/OfflineUserImpl.java index f11a11d1..5c0057a4 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/storage/user/OfflineUserImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/storage/user/OfflineUserImpl.java @@ -43,7 +43,7 @@ public class OfflineUserImpl implements OfflineUser { private final FishingBagHolder holder; private final EarningData earningData; private final Statistics statistics; - public static OfflineUserImpl NEVER_PLAYED_USER = new OfflineUserImpl(UUID.randomUUID(), "", PlayerData.empty()); + public static OfflineUserImpl LOCKED_USER = new OfflineUserImpl(UUID.randomUUID(), "", PlayerData.empty()); public OfflineUserImpl(UUID uuid, String name, PlayerData playerData) { this.name = name; diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml index 6ea1be57..bf4c9ba0 100644 --- a/plugin/src/main/resources/config.yml +++ b/plugin/src/main/resources/config.yml @@ -28,7 +28,7 @@ mechanics: disable-game: false instant-game: false prevent-grabbing: false - action: + events: success: title_action: type: random-title diff --git a/plugin/src/main/resources/messages/english.yml b/plugin/src/main/resources/messages/english.yml index b656cfc3..228f5927 100644 --- a/plugin/src/main/resources/messages/english.yml +++ b/plugin/src/main/resources/messages/english.yml @@ -23,4 +23,5 @@ messages: goal-total-size: 'Total size of the fish caught' goal-total-score: 'Total score of the fish caught' unsafe-modification: 'You can''t edit a player''s fishing bag when the player is playing on another server that connected to the database' - never-played: 'Player {player} has never played the server. You can''t edit a non existent player''s fishing bag.' \ No newline at end of file + never-played: 'That player has never played the server. You can''t edit a non existent player''s fishing bag.' + data-not-loaded: 'Your data has not been loaded yet. Try rejoining the server. If the problem still occurs, contact the server administrator.' \ No newline at end of file