From 0525c704527662026c3b15744d7943c49a008ab0 Mon Sep 17 00:00:00 2001 From: Phoenix616 Date: Sat, 1 Jul 2017 17:14:41 +0100 Subject: [PATCH] Rewrite NameManager to support multiple short names per user This should fix the issue where the player's short name on the shop sign does not reflect the actual player's name. This works by storing every uuid-username combination together with the associated short name and the last time the player logged in with that combination. --- .../Acrobot/ChestShop/Database/Account.java | 31 +- .../ChestShop/Database/Migrations.java | 29 +- .../Events/PreShopCreationEvent.java | 2 + .../Economy/ServerAccountCorrector.java | 10 +- .../Listeners/Economy/TaxModule.java | 2 +- .../Listeners/Player/PlayerInteract.java | 11 +- .../TransactionMessageSender.java | 6 +- .../PreShopCreation/NameChecker.java | 11 +- .../ShopRemoval/ShopRefundListener.java | 9 +- .../Acrobot/ChestShop/Plugins/Lockette.java | 6 +- .../java/com/Acrobot/ChestShop/Security.java | 7 +- .../Acrobot/ChestShop/UUIDs/NameManager.java | 284 ++++++++++-------- 12 files changed, 230 insertions(+), 178 deletions(-) diff --git a/src/main/java/com/Acrobot/ChestShop/Database/Account.java b/src/main/java/com/Acrobot/ChestShop/Database/Account.java index 441796c..bbc6afb 100644 --- a/src/main/java/com/Acrobot/ChestShop/Database/Account.java +++ b/src/main/java/com/Acrobot/ChestShop/Database/Account.java @@ -1,9 +1,11 @@ package com.Acrobot.ChestShop.Database; import com.Acrobot.Breeze.Utils.NameUtil; +import com.j256.ormlite.field.DataType; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; +import java.util.Date; import java.util.UUID; /** @@ -14,18 +16,18 @@ import java.util.UUID; @DatabaseFileName("users.db") public class Account { - @DatabaseField(canBeNull = false) - private String lastSeenName; - - @DatabaseField(id = true, canBeNull = false) + @DatabaseField(index = true, canBeNull = false, uniqueCombo = true) private String name; - @DatabaseField(index = true, canBeNull = false) + @DatabaseField(id = true, index = true, canBeNull = false) private String shortName; - @DatabaseField(canBeNull = false) + @DatabaseField(index = true, canBeNull = false, uniqueCombo = true) private UUID uuid; + @DatabaseField(canBeNull = false, dataType = DataType.DATE_LONG, defaultValue = "0") + private Date lastSeen; + public Account() { //empty constructor, needed for ORMLite } @@ -33,18 +35,9 @@ public class Account { public Account(String name, UUID uuid) { this.name = name; this.shortName = NameUtil.stripUsername(name); - this.lastSeenName = name; this.uuid = uuid; } - public String getLastSeenName() { - return lastSeenName; - } - - public void setLastSeenName(String lastSeenName) { - this.lastSeenName = lastSeenName; - } - public String getName() { return name; } @@ -68,4 +61,12 @@ public class Account { public void setUuid(UUID uuid) { this.uuid = uuid; } + + public Date getLastSeen() { + return lastSeen; + } + + public void setLastSeen(Date lastSeen) { + this.lastSeen = lastSeen; + } } diff --git a/src/main/java/com/Acrobot/ChestShop/Database/Migrations.java b/src/main/java/com/Acrobot/ChestShop/Database/Migrations.java index 7b4eac8..8c9ea50 100644 --- a/src/main/java/com/Acrobot/ChestShop/Database/Migrations.java +++ b/src/main/java/com/Acrobot/ChestShop/Database/Migrations.java @@ -11,7 +11,7 @@ import java.sql.SQLException; * @author Andrzej Pomirski */ public class Migrations { - public static final int CURRENT_DATABASE_VERSION = 2; + public static final int CURRENT_DATABASE_VERSION = 3; /** * Migrates a database from the given version @@ -33,9 +33,19 @@ public class Migrations { if (migrated) { currentVersion++; } - + break; case 2: + + boolean migrated3 = migrateTo3(); + + if (migrated3) { + currentVersion++; + } + break; + case 3: + break; default: + break; //do nothing } @@ -53,4 +63,19 @@ public class Migrations { return false; } } + + private static boolean migrateTo3() { + try { + Dao accountsOld = DaoCreator.getDao(Account.class); + accountsOld.executeRaw("ALTER TABLE `accounts` RENAME TO `accounts-old`"); + + Dao accounts = DaoCreator.getDaoAndCreateTable(Account.class); + accounts.executeRaw("INSERT INTO `accounts` (name, shortName, uuid) SELECT name, shortName, uuid FROM `accounts-old`"); + + return true; + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } } diff --git a/src/main/java/com/Acrobot/ChestShop/Events/PreShopCreationEvent.java b/src/main/java/com/Acrobot/ChestShop/Events/PreShopCreationEvent.java index 9edd533..eef1009 100644 --- a/src/main/java/com/Acrobot/ChestShop/Events/PreShopCreationEvent.java +++ b/src/main/java/com/Acrobot/ChestShop/Events/PreShopCreationEvent.java @@ -142,6 +142,8 @@ public class PreShopCreationEvent extends Event { INVALID_PRICE, INVALID_QUANTITY, + UNKNOWN_PLAYER, + SELL_PRICE_HIGHER_THAN_BUY_PRICE, NO_CHEST, diff --git a/src/main/java/com/Acrobot/ChestShop/Listeners/Economy/ServerAccountCorrector.java b/src/main/java/com/Acrobot/ChestShop/Listeners/Economy/ServerAccountCorrector.java index ad580b8..3f3a30a 100644 --- a/src/main/java/com/Acrobot/ChestShop/Listeners/Economy/ServerAccountCorrector.java +++ b/src/main/java/com/Acrobot/ChestShop/Listeners/Economy/ServerAccountCorrector.java @@ -21,7 +21,7 @@ public class ServerAccountCorrector implements Listener { public static void onCurrencyAdd(CurrencyAddEvent event) { UUID target = event.getTarget(); - if (!NameManager.isAdminShop(target) || NameManager.getUsername(target).equals(SERVER_ECONOMY_ACCOUNT)) { + if (!NameManager.isAdminShop(target) || SERVER_ECONOMY_ACCOUNT.equals(NameManager.getUsername(target))) { return; } @@ -42,7 +42,7 @@ public class ServerAccountCorrector implements Listener { public static void onCurrencySubtract(CurrencySubtractEvent event) { UUID target = event.getTarget(); - if (!NameManager.isAdminShop(target) || NameManager.getUsername(target).equals(SERVER_ECONOMY_ACCOUNT)) { + if (!NameManager.isAdminShop(target) || SERVER_ECONOMY_ACCOUNT.equals(NameManager.getUsername(target))) { return; } @@ -63,7 +63,7 @@ public class ServerAccountCorrector implements Listener { public static void onCurrencyCheck(CurrencyCheckEvent event) { UUID target = event.getAccount(); - if (!NameManager.isAdminShop(target) || NameManager.getUsername(target).equals(SERVER_ECONOMY_ACCOUNT)) { + if (!NameManager.isAdminShop(target) || SERVER_ECONOMY_ACCOUNT.equals(NameManager.getUsername(target))) { return; } @@ -84,7 +84,7 @@ public class ServerAccountCorrector implements Listener { public static void onCurrencyHoldCheck(CurrencyHoldEvent event) { UUID target = event.getAccount(); - if (!NameManager.isAdminShop(target) || NameManager.getUsername(target).equals(SERVER_ECONOMY_ACCOUNT)) { + if (!NameManager.isAdminShop(target) || SERVER_ECONOMY_ACCOUNT.equals(NameManager.getUsername(target))) { return; } @@ -96,7 +96,7 @@ public class ServerAccountCorrector implements Listener { public static void onBalanceCheck(CurrencyAmountEvent event) { UUID target = event.getAccount(); - if (!NameManager.isAdminShop(target) || NameManager.getUsername(target).equals(SERVER_ECONOMY_ACCOUNT)) { + if (!NameManager.isAdminShop(target) || SERVER_ECONOMY_ACCOUNT.equals(NameManager.getUsername(target))) { return; } diff --git a/src/main/java/com/Acrobot/ChestShop/Listeners/Economy/TaxModule.java b/src/main/java/com/Acrobot/ChestShop/Listeners/Economy/TaxModule.java index 60a1985..6e804aa 100644 --- a/src/main/java/com/Acrobot/ChestShop/Listeners/Economy/TaxModule.java +++ b/src/main/java/com/Acrobot/ChestShop/Listeners/Economy/TaxModule.java @@ -33,7 +33,7 @@ public class TaxModule implements Listener { UUID target = event.getTarget(); - if (NameManager.getUsername(target).equals(Economy.getServerAccountName())) { + if (Economy.getServerAccountName().equals(NameManager.getUsername(target))) { return; } diff --git a/src/main/java/com/Acrobot/ChestShop/Listeners/Player/PlayerInteract.java b/src/main/java/com/Acrobot/ChestShop/Listeners/Player/PlayerInteract.java index eb36854..1cd5c99 100644 --- a/src/main/java/com/Acrobot/ChestShop/Listeners/Player/PlayerInteract.java +++ b/src/main/java/com/Acrobot/ChestShop/Listeners/Player/PlayerInteract.java @@ -4,6 +4,7 @@ import com.Acrobot.Breeze.Utils.*; import com.Acrobot.ChestShop.Configuration.Messages; import com.Acrobot.ChestShop.Configuration.Properties; import com.Acrobot.ChestShop.Containers.AdminInventory; +import com.Acrobot.ChestShop.Database.Account; import com.Acrobot.ChestShop.Events.PreTransactionEvent; import com.Acrobot.ChestShop.Events.TransactionEvent; import com.Acrobot.ChestShop.Listeners.Economy.Plugins.VaultListener; @@ -112,15 +113,11 @@ public class PlayerInteract implements Listener { String prices = sign.getLine(PRICE_LINE); String material = sign.getLine(ITEM_LINE); - String ownerName = NameManager.getFullUsername(name); - if (ownerName == null || ownerName.isEmpty()) + Account account = NameManager.getAccountFromShortName(name); + if (account == null) return null; - UUID uuid = NameManager.getUUID(ownerName); - if (uuid == null) - return null; - - OfflinePlayer owner = Bukkit.getOfflinePlayer(uuid); + OfflinePlayer owner = Bukkit.getOfflinePlayer(account.getUuid()); // check if player exists in economy if(!ChestShopSign.isAdminShop(sign) && (owner == null || owner.getName() == null || !VaultListener.getProvider().hasAccount(owner))) diff --git a/src/main/java/com/Acrobot/ChestShop/Listeners/PostTransaction/TransactionMessageSender.java b/src/main/java/com/Acrobot/ChestShop/Listeners/PostTransaction/TransactionMessageSender.java index 1166750..a2f172e 100644 --- a/src/main/java/com/Acrobot/ChestShop/Listeners/PostTransaction/TransactionMessageSender.java +++ b/src/main/java/com/Acrobot/ChestShop/Listeners/PostTransaction/TransactionMessageSender.java @@ -33,7 +33,6 @@ public class TransactionMessageSender implements Listener { protected static void sendBuyMessage(TransactionEvent event) { String itemName = parseItemInformation(event.getStock()); - String owner = NameManager.getUsername(event.getOwner().getUniqueId()); Player player = event.getClient(); @@ -41,7 +40,7 @@ public class TransactionMessageSender implements Listener { if (Properties.SHOW_TRANSACTION_INFORMATION_CLIENT) { String message = formatMessage(Messages.YOU_BOUGHT_FROM_SHOP, itemName, price); - message = message.replace("%owner", owner); + message = message.replace("%owner", event.getOwner().getName()); player.sendMessage(message); } @@ -56,7 +55,6 @@ public class TransactionMessageSender implements Listener { protected static void sendSellMessage(TransactionEvent event) { String itemName = parseItemInformation(event.getStock()); - String owner = NameManager.getUsername(event.getOwner().getUniqueId()); Player player = event.getClient(); @@ -64,7 +62,7 @@ public class TransactionMessageSender implements Listener { if (Properties.SHOW_TRANSACTION_INFORMATION_CLIENT) { String message = formatMessage(Messages.YOU_SOLD_TO_SHOP, itemName, price); - message = message.replace("%buyer", owner); + message = message.replace("%buyer", event.getOwner().getName()); player.sendMessage(message); } diff --git a/src/main/java/com/Acrobot/ChestShop/Listeners/PreShopCreation/NameChecker.java b/src/main/java/com/Acrobot/ChestShop/Listeners/PreShopCreation/NameChecker.java index 8c500b1..412f18f 100644 --- a/src/main/java/com/Acrobot/ChestShop/Listeners/PreShopCreation/NameChecker.java +++ b/src/main/java/com/Acrobot/ChestShop/Listeners/PreShopCreation/NameChecker.java @@ -1,6 +1,6 @@ package com.Acrobot.ChestShop.Listeners.PreShopCreation; -import com.Acrobot.Breeze.Utils.NameUtil; +import com.Acrobot.ChestShop.Database.Account; import com.Acrobot.ChestShop.Events.PreShopCreationEvent; import com.Acrobot.ChestShop.Permission; import com.Acrobot.ChestShop.UUIDs.NameManager; @@ -10,6 +10,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import static com.Acrobot.ChestShop.Signs.ChestShopSign.NAME_LINE; +import static com.Acrobot.ChestShop.Events.PreShopCreationEvent.CreationOutcome.UNKNOWN_PLAYER; /** * @author Acrobot @@ -22,8 +23,12 @@ public class NameChecker implements Listener { Player player = event.getPlayer(); if (name.isEmpty() || (!NameManager.canUseName(player, name) && !Permission.has(player, Permission.ADMIN))) { - String shortName = NameUtil.stripUsername(NameManager.getUsername(player.getUniqueId())); - event.setSignLine(NAME_LINE, shortName); + Account account = NameManager.getAccount(player.getName()); + if (account != null) { + event.setSignLine(NAME_LINE, account.getShortName()); + } else { + event.setOutcome(UNKNOWN_PLAYER); + } } } } diff --git a/src/main/java/com/Acrobot/ChestShop/Listeners/ShopRemoval/ShopRefundListener.java b/src/main/java/com/Acrobot/ChestShop/Listeners/ShopRemoval/ShopRefundListener.java index d7ee13f..cc1ae26 100644 --- a/src/main/java/com/Acrobot/ChestShop/Listeners/ShopRemoval/ShopRefundListener.java +++ b/src/main/java/com/Acrobot/ChestShop/Listeners/ShopRemoval/ShopRefundListener.java @@ -3,6 +3,7 @@ package com.Acrobot.ChestShop.Listeners.ShopRemoval; import com.Acrobot.ChestShop.ChestShop; import com.Acrobot.ChestShop.Configuration.Messages; import com.Acrobot.ChestShop.Configuration.Properties; +import com.Acrobot.ChestShop.Database.Account; import com.Acrobot.ChestShop.Economy.Economy; import com.Acrobot.ChestShop.Events.Economy.CurrencyAddEvent; import com.Acrobot.ChestShop.Events.Economy.CurrencySubtractEvent; @@ -31,14 +32,12 @@ public class ShopRefundListener implements Listener { return; } - String ownerName = NameManager.getFullUsername(event.getSign().getLine(NAME_LINE)); - if (ownerName == null || ownerName.isEmpty()) { + Account account = NameManager.getAccountFromShortName(event.getSign().getLine(NAME_LINE)); + if (account == null) { return; } - UUID owner = NameManager.getUUID(ownerName); - - CurrencyAddEvent currencyEvent = new CurrencyAddEvent(BigDecimal.valueOf(refundPrice), owner, event.getSign().getWorld()); + CurrencyAddEvent currencyEvent = new CurrencyAddEvent(BigDecimal.valueOf(refundPrice), account.getUuid(), event.getSign().getWorld()); ChestShop.callEvent(currencyEvent); if (!Economy.getServerAccountName().isEmpty()) { diff --git a/src/main/java/com/Acrobot/ChestShop/Plugins/Lockette.java b/src/main/java/com/Acrobot/ChestShop/Plugins/Lockette.java index d175534..871c09b 100644 --- a/src/main/java/com/Acrobot/ChestShop/Plugins/Lockette.java +++ b/src/main/java/com/Acrobot/ChestShop/Plugins/Lockette.java @@ -1,6 +1,7 @@ package com.Acrobot.ChestShop.Plugins; import com.Acrobot.Breeze.Utils.NameUtil; +import com.Acrobot.ChestShop.Database.Account; import com.Acrobot.ChestShop.Events.Protection.ProtectionCheckEvent; import com.Acrobot.ChestShop.UUIDs.NameManager; import org.bukkit.block.Block; @@ -26,9 +27,8 @@ public class Lockette implements Listener { return; } - String shortPlayerName = NameUtil.stripUsername(NameManager.getUsername(player.getUniqueId())); - - if (!org.yi.acru.bukkit.Lockette.Lockette.isUser(block, shortPlayerName, true)) { + Account account = NameManager.getAccount(player.getUniqueId()); + if (account != null && !org.yi.acru.bukkit.Lockette.Lockette.isUser(block, account.getName(), true)) { event.setResult(Event.Result.DENY); } } diff --git a/src/main/java/com/Acrobot/ChestShop/Security.java b/src/main/java/com/Acrobot/ChestShop/Security.java index 5f38d6d..8913e28 100644 --- a/src/main/java/com/Acrobot/ChestShop/Security.java +++ b/src/main/java/com/Acrobot/ChestShop/Security.java @@ -3,6 +3,7 @@ package com.Acrobot.ChestShop; import com.Acrobot.Breeze.Utils.BlockUtil; import com.Acrobot.Breeze.Utils.NameUtil; import com.Acrobot.ChestShop.Configuration.Properties; +import com.Acrobot.ChestShop.Database.Account; import com.Acrobot.ChestShop.Events.Protection.ProtectBlockEvent; import com.Acrobot.ChestShop.Events.Protection.ProtectionCheckEvent; import com.Acrobot.ChestShop.Signs.ChestShopSign; @@ -64,9 +65,6 @@ public class Security { } private static boolean anotherShopFound(Block baseBlock, Block signBlock, Player player) { - String playerName = NameManager.getUsername(player.getUniqueId()); - String shortName = NameUtil.stripUsername(playerName); - for (BlockFace face : SIGN_CONNECTION_FACES) { Block block = baseBlock.getRelative(face); @@ -80,7 +78,8 @@ public class Security { continue; } - if (!sign.getLine(ChestShopSign.NAME_LINE).equals(shortName)) { + Account account = NameManager.getAccountFromShortName(sign.getLine(ChestShopSign.NAME_LINE)); + if (account != null && !account.getUuid().equals(player.getUniqueId())) { return true; } } diff --git a/src/main/java/com/Acrobot/ChestShop/UUIDs/NameManager.java b/src/main/java/com/Acrobot/ChestShop/UUIDs/NameManager.java index b856f5b..771e192 100644 --- a/src/main/java/com/Acrobot/ChestShop/UUIDs/NameManager.java +++ b/src/main/java/com/Acrobot/ChestShop/UUIDs/NameManager.java @@ -10,7 +10,6 @@ import com.Acrobot.ChestShop.Permission; import com.Acrobot.ChestShop.Signs.ChestShopSign; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; -import com.j256.ormlite.dao.CloseableIterator; import com.j256.ormlite.dao.Dao; import org.apache.commons.lang.Validate; @@ -19,6 +18,7 @@ import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import java.sql.SQLException; +import java.util.Date; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.logging.Level; @@ -32,118 +32,167 @@ import java.util.logging.Level; public class NameManager { private static Dao accounts; - private static Cache usernameToUUID = CacheBuilder.newBuilder().maximumSize(Properties.CACHE_SIZE).build(); - private static Cache uuidToUsername = CacheBuilder.newBuilder().maximumSize(Properties.CACHE_SIZE).build(); - private static Cache shortToLongName = CacheBuilder.newBuilder().maximumSize(Properties.CACHE_SIZE).build(); + private static Cache usernameToAccount = CacheBuilder.newBuilder().maximumSize(Properties.CACHE_SIZE).build(); + private static Cache uuidToAccount = CacheBuilder.newBuilder().maximumSize(Properties.CACHE_SIZE).build(); + private static Cache shortToAccount = CacheBuilder.newBuilder().maximumSize(Properties.CACHE_SIZE).build(); /** - * Get the UUID from a player's (non-shortened) username - * @param username The player's username - * @return The UUID or null if the UUID can't be found or an error occurred + * Get account info from a UUID + * @param uuid The UUID of the player to get the account info + * @return The account info or null if none was found */ - public static UUID getUUID(String username) { - Validate.notEmpty(username, "username cannot be null or empty!"); + public static Account getAccount(UUID uuid) { try { - return usernameToUUID.get(username, () -> { - UUID uuid = null; - Player player = Bukkit.getPlayer(username); - if (player != null) { - uuid = player.getUniqueId(); - } - if (uuid == null) { - try { - Account account = accounts.queryBuilder().selectColumns("uuid").where().eq("lastSeenName", username).queryForFirst(); - if (account != null) { - uuid = account.getUuid(); - } - } catch (SQLException e) { - ChestShop.getBukkitLogger().log(Level.WARNING, "Error while getting uuid for " + username + ":", e); + return uuidToAccount.get(uuid, () -> { + try { + Account account = accounts.queryBuilder().orderBy("lastSeen", false).where().eq("uuid", uuid).queryForFirst(); + if (account != null) { + account.setUuid(uuid); //HOW IS IT EVEN POSSIBLE THAT UUID IS NOT SET EVEN IF WE HAVE FOUND THE PLAYER?! + shortToAccount.put(account.getShortName(), account); + usernameToAccount.put(account.getName(), account); + return account; } + } catch (SQLException e) { + ChestShop.getBukkitLogger().log(Level.WARNING, "Error while getting account for " + uuid + ":", e); } - if (uuid == null) { - OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(username); - if (offlinePlayer != null && offlinePlayer.hasPlayedBefore() && offlinePlayer.getUniqueId() != null) { - uuid = offlinePlayer.getUniqueId(); - } - } - if (uuid != null) { - uuidToUsername.put(uuid, username); - return uuid; - } - throw new Exception("Could not find username for " + uuid); + throw new Exception("Could not find account for " + uuid); }); - } catch (ExecutionException e) { + } catch (ExecutionException ignored) { return null; } } + /** + * Get account info from a non-shortened username + * @param fullName The full name of the player to get the account info + * @return The account info or null if none was found + * @throws IllegalArgumentException if the username is empty or null + */ + public static Account getAccount(String fullName) { + Validate.notEmpty(fullName, "fullName cannot be null or empty!"); + try { + return usernameToAccount.get(fullName, () -> { + try { + Account account = accounts.queryBuilder().orderBy("lastSeen", false).where().eq("name", fullName).queryForFirst(); + if (account != null) { + account.setName(fullName); //HOW IS IT EVEN POSSIBLE THAT UUID IS NOT SET EVEN IF WE HAVE FOUND THE PLAYER?! + shortToAccount.put(account.getShortName(), account); + return account; + } + } catch (SQLException e) { + ChestShop.getBukkitLogger().log(Level.WARNING, "Error while getting account for " + fullName + ":", e); + } + throw new Exception("Could not find account for " + fullName); + }); + } catch (ExecutionException ignored) { + return null; + } + } + + /** + * Get account info from a username that might be shortened + * @param shortName The name of the player to get the account info + * @return The account info or null if none was found + * @throws IllegalArgumentException if the username is not a shortened name and longer than 15 chars + */ + public static Account getAccountFromShortName(String shortName) { + Validate.notEmpty(shortName, "shortName cannot be null or empty!"); + Validate.isTrue(shortName.length() < 16, "Username is not a shortened name and longer than 15 chars!"); + + try { + return shortToAccount.get(shortName, () -> { + try { + Account account = accounts.queryBuilder().where().eq("shortName", shortName).queryForFirst(); + if (account != null) { + account.setShortName(shortName); //HOW IS IT EVEN POSSIBLE THAT UUID IS NOT SET EVEN IF WE HAVE FOUND THE PLAYER?! + return account; + } + } catch (SQLException e) { + ChestShop.getBukkitLogger().log(Level.WARNING, "Error while getting account for " + shortName + ":", e); + } + throw new Exception("Could not find account for " + shortName); + }); + } catch (ExecutionException ignored) { + return null; + } + } + + /** + * Get the UUID from a player's (non-shortened) username + * @param username The player's username + * @return The UUID or null if the UUID can't be found or an error occurred + * @deprecated Use {@link NameManager#getAccount(String)} + */ + @Deprecated + public static UUID getUUID(String username) { + Validate.notEmpty(username, "username cannot be null or empty!"); + Player player = Bukkit.getPlayer(username); + if (player != null) { + return player.getUniqueId(); + } + Account account = getAccount(username); + if (account != null) { + return account.getUuid(); + } + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(username); + if (offlinePlayer != null && offlinePlayer.hasPlayedBefore() && offlinePlayer.getUniqueId() != null) { + return offlinePlayer.getUniqueId(); + } + return null; + } + /** * Get the username from a player's UUID * @param uuid The UUID of the player - * @return The username that is stored, an empty string if none was found or null if an error occurred + * @return The username that is stored or null if none was found + * @deprecated Use {@link NameManager#getAccount(UUID)} */ + @Deprecated public static String getUsername(UUID uuid) { - try { - return uuidToUsername.get(uuid, () -> { - String name = null; - Player player = Bukkit.getPlayer(uuid); - if (player != null) { - name = player.getName(); - } - if (name == null) { - try { - Account account = accounts.queryBuilder().selectColumns("lastSeenName").where().eq("uuid", uuid).queryForFirst(); - if (account != null) { - name = account.getLastSeenName(); - } - } catch (SQLException e) { - ChestShop.getBukkitLogger().log(Level.WARNING, "Error while getting username for " + uuid + ":", e); - } - } - if (name == null) { - OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); - if (offlinePlayer != null && offlinePlayer.hasPlayedBefore() && offlinePlayer.getName() != null) { - name = offlinePlayer.getName(); - } - } - if (name != null) { - usernameToUUID.put(name, uuid); - return name; - } - throw new Exception("Could not find username for " + uuid); - }); - } catch (ExecutionException e) { - return ""; + Player player = Bukkit.getPlayer(uuid); + if (player != null) { + return player.getName(); } + Account account = getAccount(uuid); + if (account != null) { + return account.getName(); + } + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); + if (offlinePlayer != null && offlinePlayer.hasPlayedBefore() && offlinePlayer.getName() != null) { + return offlinePlayer.getName(); + } + return null; } /** * Get the full username from another username that might be shortened * @param shortName The name of the player to get the full username for - * @return The full username, an empty string if none was found or null if an error occurred + * @return The full username or null if none was found * @throws IllegalArgumentException if the username is not a shortened name and longer than 15 chars + * @deprecated Use {@link NameManager#getAccountFromShortName(String)} */ + @Deprecated public static String getFullUsername(String shortName) { - Validate.isTrue(shortName.length() < 16, "Username is not a shortened name and longer than 15 chars!"); - if (ChestShopSign.isAdminShop(shortName)) { - return Properties.ADMIN_SHOP_NAME; + Account account = getAccountFromShortName(shortName); // first get the account associated with the short name + if (account != null) { + account = getAccount(account.getUuid()); // then get the last account that was online with that UUID + if (account != null) { + return account.getName(); + } } + return null; + } - try { - return shortToLongName.get(shortName, () -> { - try { - Account account = accounts.queryBuilder().selectColumns("lastSeenName").where().eq("shortName", shortName).queryForFirst(); - if (account != null) { - return account.getLastSeenName(); - } - } catch (SQLException e) { - ChestShop.getBukkitLogger().log(Level.WARNING, "Error while getting full name for " + shortName + ":", e); - } - throw new Exception("Could not find full name for " + shortName); - }); - } catch (ExecutionException ignored) { - return ""; - } + /** + * Get the short username from a full username + * @param fullName The name of the player to get the short username for + * @return The short username or null if none was found + * @deprecated Use {@link NameManager#getAccount(String)} + */ + @Deprecated + public static String getShortUsername(String fullName) { + Account account = getAccount(fullName); + return account != null ? account.getShortName() : null; } /** @@ -153,35 +202,9 @@ public class NameManager { public static void storeUsername(final PlayerDTO player) { final UUID uuid = player.getUniqueId(); - CloseableIterator existingAccounts = null; - try { - existingAccounts = accounts.queryBuilder().where().eq("uuid", uuid).ne("lastSeenName", player.getName()).iterator(); - while (existingAccounts.hasNext()) { - Account account = existingAccounts.next(); - account.setUuid(uuid); //HOW IS IT EVEN POSSIBLE THAT UUID IS NOT SET EVEN IF WE HAVE FOUND THE PLAYER?! - account.setLastSeenName(player.getName()); - try { - accounts.update(account); - } catch (SQLException e) { - ChestShop.getBukkitLogger().log(Level.WARNING, "Error while updating account " + account + ":", e); - } - } - } catch (SQLException e) { - ChestShop.getBukkitLogger().log(Level.WARNING, "Error getting all entries for " + uuid + ":", e); - return; - } finally { - if (existingAccounts != null) { - try { - existingAccounts.close(); - } catch (SQLException e) { - ChestShop.getBukkitLogger().log(Level.WARNING, "Error while closing query iterator for " + uuid + ":", e); - } - } - } - Account latestAccount = null; try { - latestAccount = accounts.queryBuilder().where().eq("uuid", uuid).eq("name", player.getName()).queryForFirst(); + latestAccount = accounts.queryBuilder().where().eq("uuid", uuid).and().eq("name", player.getName()).queryForFirst(); } catch (SQLException e) { ChestShop.getBukkitLogger().log(Level.WARNING, "Error while searching for latest account of " + player.getName() + "/" + uuid + ":", e); } @@ -189,18 +212,18 @@ public class NameManager { if (latestAccount == null) { latestAccount = new Account(player.getName(), player.getUniqueId()); latestAccount.setShortName(getNewShortenedName(player)); - - try { - accounts.create(latestAccount); - } catch (SQLException e) { - ChestShop.getBukkitLogger().log(Level.WARNING, "Error while updating account " + latestAccount + ":", e); - } } - usernameToUUID.put(latestAccount.getLastSeenName(), uuid); - uuidToUsername.put(uuid, latestAccount.getLastSeenName()); + latestAccount.setLastSeen(new Date()); + try { + accounts.createOrUpdate(latestAccount); + } catch (SQLException e) { + ChestShop.getBukkitLogger().log(Level.WARNING, "Error while updating account " + latestAccount + ":", e); + } - shortToLongName.put(latestAccount.getShortName(), latestAccount.getLastSeenName()); + usernameToAccount.put(latestAccount.getName(), latestAccount); + uuidToAccount.put(uuid, latestAccount); + shortToAccount.put(latestAccount.getShortName(), latestAccount); } /** @@ -211,27 +234,30 @@ public class NameManager { private static String getNewShortenedName(PlayerDTO player) { String shortenedName = NameUtil.stripUsername(player.getName()); - String fullName = getFullUsername(shortenedName); - if (fullName != null && fullName.isEmpty()) { + Account account = getAccountFromShortName(shortenedName); + if (account == null) { return shortenedName; } - for (int id = 0; fullName != null && !fullName.isEmpty(); id++) { + for (int id = 0; account != null; id++) { String baseId = Base62.encode(id); shortenedName = NameUtil.stripUsername(player.getName(), 15 - 1 - baseId.length()) + ":" + baseId; - fullName = getFullUsername(shortenedName); + account = getAccountFromShortName(shortenedName); } return shortenedName; } public static boolean canUseName(Player player, String name) { - String shortenedName = NameUtil.stripUsername(getUsername(player.getUniqueId())); - if (ChestShopSign.isAdminShop(name)) { return false; } - return shortenedName.equals(name) || Permission.otherName(player, name) || (!name.isEmpty() && player.getName().equals(getFullUsername(name))); + if (Permission.otherName(player, name)) { + return true; + } + + Account account = getAccountFromShortName(name); + return account != null && account.getUuid().equals(player.getUniqueId()); } public static boolean isAdminShop(UUID uuid) {