diff --git a/src/main/java/org/mvplugins/multiverse/inventories/listeners/InventoriesListener.java b/src/main/java/org/mvplugins/multiverse/inventories/listeners/InventoriesListener.java index 78a26eda..36a0eac0 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/listeners/InventoriesListener.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/listeners/InventoriesListener.java @@ -53,6 +53,7 @@ import java.io.File; import java.io.IOException; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; /** @@ -183,27 +184,9 @@ public void playerPreLogin(AsyncPlayerPreLoginEvent event) { if (event.getLoginResult() != Result.ALLOWED) { return; } - Logging.finer("Loading global profile for Player{name:'%s', uuid:'%s'}.", event.getName(), event.getUniqueId()); - - GlobalProfile globalProfile = profileDataSource.getGlobalProfile(event.getName(), event.getUniqueId()); - if (!globalProfile.getLastKnownName().equalsIgnoreCase(event.getName())) { - // Data must be migrated - Logging.info("Player %s changed name from '%s' to '%s'. Attempting to migrate playerdata...", - event.getUniqueId(), globalProfile.getLastKnownName(), event.getName()); - try { - profileDataSource.migratePlayerData(globalProfile.getLastKnownName(), event.getName(), - event.getUniqueId(), true); - } catch (IOException e) { - Logging.severe("An error occurred while trying to migrate playerdata."); - e.printStackTrace(); - } - - globalProfile.setLastKnownName(event.getName()); - profileDataSource.updateGlobalProfile(globalProfile); - Logging.info("Migration complete!"); - } + verifyCorrectPlayerName(event.getUniqueId(), event.getName()); } /** @@ -214,6 +197,9 @@ public void playerPreLogin(AsyncPlayerPreLoginEvent event) { @EventHandler public void playerJoin(final PlayerJoinEvent event) { final Player player = event.getPlayer(); + // Just in case AsyncPlayerPreLoginEvent was still the old name + verifyCorrectPlayerName(player.getUniqueId(), player.getName()); + final GlobalProfile globalProfile = profileDataSource.getGlobalProfile(player.getName(), player.getUniqueId()); final String world = globalProfile.getLastWorld(); if (config.usingLoggingSaveLoad() && globalProfile.shouldLoadOnLogin()) { @@ -228,6 +214,26 @@ public void playerJoin(final PlayerJoinEvent event) { verifyCorrectWorld(player, player.getWorld().getName(), globalProfile); } + private void verifyCorrectPlayerName(UUID uuid, String name) { + GlobalProfile globalProfile = profileDataSource.getGlobalProfile(name, uuid); + if (globalProfile.getLastKnownName().equals(name)) { + return; + } + + // Data must be migrated + Logging.info("Player %s changed name from '%s' to '%s'. Attempting to migrate playerdata...", + uuid, globalProfile.getLastKnownName(), name); + try { + profileDataSource.migratePlayerData(globalProfile.getLastKnownName(), name, uuid); + } catch (IOException e) { + Logging.severe("An error occurred while trying to migrate playerdata."); + e.printStackTrace(); + } + globalProfile.setLastKnownName(name); + profileDataSource.updateGlobalProfile(globalProfile); + Logging.info("Migration complete!"); + } + /** * Called when a player leaves the server. * diff --git a/src/main/java/org/mvplugins/multiverse/inventories/profile/FlatFileProfileDataSource.java b/src/main/java/org/mvplugins/multiverse/inventories/profile/FlatFileProfileDataSource.java index 666ee66b..a5c29634 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/profile/FlatFileProfileDataSource.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/profile/FlatFileProfileDataSource.java @@ -4,6 +4,7 @@ import com.dumptruckman.minecraft.util.Logging; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; +import com.google.common.collect.Sets; import net.minidev.json.parser.JSONParser; import net.minidev.json.parser.ParseException; import org.bukkit.configuration.InvalidConfigurationException; @@ -143,11 +144,26 @@ private File getFolder(ContainerType type, String folderName) { * @return The data file for a player. * @throws IOException if there was a problem creating the file. */ - File getPlayerFile(ContainerType type, String dataName, String playerName) throws IOException { + private File getPlayerFile(ContainerType type, String dataName, String playerName) throws IOException { + return getPlayerFile(type, dataName, playerName, true); + } + + /** + * Retrieves the data file for a player based on a given world/group name, creating it if necessary. + * + * @param type Indicates whether data is for group or world. + * @param dataName The name of the group or world. + * @param playerName The name of the player. + * @return The data file for a player. + * @throws IOException if there was a problem creating the file. + */ + private File getPlayerFile(ContainerType type, String dataName, String playerName, boolean createNew) throws IOException { File jsonPlayerFile = new File(this.getFolder(type, dataName), playerName + JSON); if (!jsonPlayerFile.exists()) { try { - jsonPlayerFile.createNewFile(); + if (createNew) { + jsonPlayerFile.createNewFile(); + } } catch (IOException e) { throw new IOException("Could not create necessary player data file: " + jsonPlayerFile.getPath() + ". Data for " + playerName + " in " + type.name().toLowerCase() + " " + dataName @@ -547,7 +563,9 @@ public void setLoadOnLogin(final String playerName, final boolean loadOnLogin) { } @Override - public void migratePlayerData(String oldName, String newName, UUID uuid, boolean removeOldData) throws IOException { + public void migratePlayerData(String oldName, String newName, UUID uuid) throws IOException { + clearPlayerCache(uuid); + File[] worldFolders = worldFolder.listFiles(File::isDirectory); if (worldFolders == null) { throw new IOException("Could not enumerate world folders"); @@ -557,36 +575,41 @@ public void migratePlayerData(String oldName, String newName, UUID uuid, boolean throw new IOException("Could not enumerate group folders"); } - for (File worldFolder : worldFolders) { - ProfileKey key = ProfileKey.createProfileKey(ContainerType.WORLD, worldFolder.getName(), - ProfileTypes.ADVENTURE, uuid, oldName); - updatePlayerData(getPlayerData(key)); - updatePlayerData(getPlayerData(ProfileKey.createProfileKey(key, ProfileTypes.CREATIVE))); - updatePlayerData(getPlayerData(ProfileKey.createProfileKey(key, ProfileTypes.SURVIVAL))); - } - - for (File groupFolder : groupFolders) { - ProfileKey key = ProfileKey.createProfileKey(ContainerType.GROUP, groupFolder.getName(), - ProfileTypes.ADVENTURE, uuid, oldName); - updatePlayerData(getPlayerData(key)); - updatePlayerData(getPlayerData(ProfileKey.createProfileKey(key, ProfileTypes.CREATIVE))); - updatePlayerData(getPlayerData(ProfileKey.createProfileKey(key, ProfileTypes.SURVIVAL))); - } + migrateForContainerType(worldFolders, ContainerType.WORLD, oldName, newName); + migrateForContainerType(groupFolders, ContainerType.GROUP, oldName, newName); + } - if (removeOldData) { - for (File worldFolder : worldFolders) { - removePlayerData(ContainerType.WORLD, worldFolder.getName(), ProfileTypes.ADVENTURE, oldName); - removePlayerData(ContainerType.WORLD, worldFolder.getName(), ProfileTypes.CREATIVE, oldName); - removePlayerData(ContainerType.WORLD, worldFolder.getName(), ProfileTypes.SURVIVAL, oldName); + private void migrateForContainerType(File[] folders, ContainerType containerType, String oldName, String newName) throws IOException { + for (File folder : folders) { + File oldNameFile = getPlayerFile(containerType, folder.getName(), oldName, false); + File newNameFile = getPlayerFile(containerType, folder.getName(), newName, false); + if (!oldNameFile.exists()) { + Logging.fine("No old data for player %s in %s %s to migrate.", + oldName, containerType.name(), folder.getName()); + continue; + } + if (newNameFile.exists()) { + Logging.warning("Data already exists for player %s in %s %s. Not migrating.", + newName, containerType.name(), folder.getName()); + continue; } - for (File groupFolder : groupFolders) { - removePlayerData(ContainerType.GROUP, groupFolder.getName(), ProfileTypes.ADVENTURE, oldName); - removePlayerData(ContainerType.GROUP, groupFolder.getName(), ProfileTypes.CREATIVE, oldName); - removePlayerData(ContainerType.GROUP, groupFolder.getName(), ProfileTypes.SURVIVAL, oldName); + if (!oldNameFile.renameTo(newNameFile)) { + Logging.warning("Could not rename old data file for player %s in %s %s to %s.", + oldName, containerType.name(), folder.getName(), newName); + continue; } + Logging.fine("Migrated data for player %s in %s %s to %s.", + oldName, containerType.name(), folder.getName(), newName); } } + void clearPlayerCache(UUID playerUUID) { + profileCache.invalidateAll(Sets.filter( + profileCache.asMap().keySet(), + key -> key.getPlayerUUID().equals(playerUUID) + )); + } + @Override public void clearProfileCache(ProfileKey key) { profileCache.invalidate(key); diff --git a/src/main/java/org/mvplugins/multiverse/inventories/profile/ProfileDataSource.java b/src/main/java/org/mvplugins/multiverse/inventories/profile/ProfileDataSource.java index c9922395..b87292ff 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/profile/ProfileDataSource.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/profile/ProfileDataSource.java @@ -93,10 +93,9 @@ public sealed interface ProfileDataSource permits FlatFileProfileDataSource { * @param oldName the previous name of the player. * @param newName the new name of the player. * @param playerUUID the UUID of the player. - * @param removeOldData whether or not to remove the data belonging to oldName. * @throws IOException Thrown if something goes wrong while migrating the files. */ - void migratePlayerData(String oldName, String newName, UUID playerUUID, boolean removeOldData) throws IOException; + void migratePlayerData(String oldName, String newName, UUID playerUUID) throws IOException; /** * Clears a single profile in cache.