diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java index f8bca18..137b196 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesManager.java +++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java @@ -107,82 +107,11 @@ public class ChallengesManager this.playersDatabase = new Database<>(addon, ChallengesPlayerData.class); // Init all cache objects. - this.challengeCacheData = new HashMap<>(); - this.levelCacheData = new HashMap<>(); - this.playerCacheData = new HashMap<>(); + this.challengeCacheData = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + this.levelCacheData = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + this.playerCacheData = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); this.load(); - - // TODO: Remove this code after some time, as this is just a protective code against invalid world names. - if (Bukkit.getBukkitVersion().startsWith("1.14")) - { - Set updatedChallenges = new HashSet<>(); - - this.challengeCacheData.values().forEach(challengeObject -> { - if (challengeObject.getUniqueId().matches(".*[A-Z]+.*")) - { - challengeObject.setUniqueId(challengeObject.getUniqueId().toLowerCase()); - challengeObject.setLevel(challengeObject.getLevel().toLowerCase()); - - updatedChallenges.add(challengeObject); - - this.addon.logWarning("Challenge addon fixed your data for Challenge " + - challengeObject.getUniqueId() + - ". 1.14 does not allow to use capital letters in world names."); - } - }); - - Set updatedLevels = new HashSet<>(); - - this.levelCacheData.values().forEach(levelObject -> { - if (levelObject.getUniqueId().matches(".*[A-Z]+.*")) - { - levelObject.setUniqueId(levelObject.getUniqueId().toLowerCase()); - levelObject.setWorld(levelObject.getWorld().toLowerCase()); - - Set correctNames = levelObject.getChallenges().stream(). - map(String::toLowerCase). - collect(Collectors.toSet()); - - levelObject.setChallenges(correctNames); - - updatedLevels.add(levelObject); - - this.addon.logWarning("Challenge addon fixed your data for Challenge Level " + - levelObject.getUniqueId() + - ". 1.14 does not allow to use capital letters in world names."); - } - }); - - // As at least one challenge or level was corrupted we must update all player data objects! - if (!updatedLevels.isEmpty() || !updatedChallenges.isEmpty()) - { - List playerDataList = this.playersDatabase.loadObjects(); - - playerDataList.forEach(challengesPlayerData -> { - - Map fixedChallengeStatus = new HashMap<>(); - challengesPlayerData.getChallengeStatus().forEach((challenge, count) -> - fixedChallengeStatus.put(challenge.toLowerCase(), count)); - challengesPlayerData.setChallengeStatus(fixedChallengeStatus); - - Map fixedChallengeTimestamp = new HashMap<>(); - challengesPlayerData.getChallengesTimestamp().forEach((challenge, count) -> - fixedChallengeTimestamp.put(challenge.toLowerCase(), count)); - challengesPlayerData.setChallengesTimestamp(fixedChallengeTimestamp); - - Set fixedLevelsDone = new HashSet<>(); - challengesPlayerData.getLevelsDone().forEach(level -> fixedLevelsDone.add(level.toLowerCase())); - challengesPlayerData.setLevelsDone(fixedLevelsDone); - - this.playersDatabase.saveObject(challengesPlayerData); - - this.addon.logWarning("Challenge addon fixed your data for PlayerData " + - challengesPlayerData.getUniqueId() + - ". 1.14 does not allow to use capital letters in world names."); - }); - } - } } @@ -1263,7 +1192,7 @@ public class ChallengesManager // TODO: Probably need to check also database. return this.challengeCacheData.values().stream(). sorted(Comparator.comparing(Challenge::getOrder)). - filter(challenge -> challenge.getUniqueId().startsWith(gameWorld.getName())). + filter(challenge -> challenge.matchWorld(gameWorld.getName())). map(Challenge::getUniqueId). collect(Collectors.toList()); } @@ -1286,7 +1215,7 @@ public class ChallengesManager // TODO: Probably need to check also database. return this.challengeCacheData.values().stream(). - filter(challenge -> challenge.getUniqueId().startsWith(gameWorld.getName())). + filter(challenge -> challenge.matchWorld(gameWorld.getName())). sorted(Comparator.comparing(Challenge::getOrder)). collect(Collectors.toList()); } @@ -1464,7 +1393,7 @@ public class ChallengesManager // TODO: Probably need to check also database. return this.levelCacheData.values().stream(). sorted(ChallengeLevel::compareTo). - filter(challenge -> challenge.getUniqueId().startsWith(world)). + filter(level -> level.matchWorld(world)). collect(Collectors.toList()); } @@ -1685,8 +1614,8 @@ public class ChallengesManager public boolean hasAnyChallengeData(@NonNull String worldName) { return this.challengeDatabase.loadObjects().stream().anyMatch( - challenge -> challenge.getUniqueId().startsWith(worldName)) || + challenge -> challenge.matchWorld(worldName)) || this.levelDatabase.loadObjects().stream().anyMatch( - level -> level.getUniqueId().startsWith(worldName)); + level -> level.matchWorld(worldName)); } } \ No newline at end of file diff --git a/src/main/java/world/bentobox/challenges/database/object/Challenge.java b/src/main/java/world/bentobox/challenges/database/object/Challenge.java index 20ae133..f7d3a19 100644 --- a/src/main/java/world/bentobox/challenges/database/object/Challenge.java +++ b/src/main/java/world/bentobox/challenges/database/object/Challenge.java @@ -978,6 +978,20 @@ public class Challenge implements DataObject // --------------------------------------------------------------------- + /** + * This method match if given worldName relates to current challenge. It is detected + * via challenge uniqueId, as it always must start with world name. + * This method is created to avoid issues with capital letters in world names in 1.14 + * @param worldName Name that must be checked. + * @return {@code true} if current challenge relates to given world name, otherwise + * {@code false}. + */ + public boolean matchWorld(String worldName) + { + return this.uniqueId.regionMatches(true, 0, worldName, 0, worldName.length()); + } + + /** * @see java.lang.Object#hashCode() * @return int @@ -1018,7 +1032,7 @@ public class Challenge implements DataObject } else { - return uniqueId.equals(other.uniqueId); + return uniqueId.equalsIgnoreCase(other.uniqueId); } } diff --git a/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java b/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java index 37fe1a9..7cbf761 100644 --- a/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java +++ b/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java @@ -425,6 +425,20 @@ public class ChallengeLevel implements DataObject, Comparable // --------------------------------------------------------------------- + /** + * This method match if given worldName relates to current level. It is detected + * via level uniqueId, as it always must start with world name. + * This method is created to avoid issues with capital letters in world names in 1.14 + * @param worldName Name that must be checked. + * @return {@code true} if current level relates to given world name, otherwise + * {@code false}. + */ + public boolean matchWorld(String worldName) + { + return this.uniqueId.regionMatches(true, 0, worldName, 0, worldName.length()); + } + + /** * {@inheritDoc} */ @@ -494,7 +508,7 @@ public class ChallengeLevel implements DataObject, Comparable } else { - return uniqueId.equals(other.uniqueId); + return uniqueId.equalsIgnoreCase(other.uniqueId); } } diff --git a/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java b/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java index e8984c7..5ff36a8 100644 --- a/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java +++ b/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java @@ -53,20 +53,20 @@ public class ChallengesPlayerData implements DataObject * completed */ @Expose - private Map challengeStatus = new HashMap<>(); + private Map challengeStatus = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); /** * Map of challenges completion time where key is challenges unique id and value is * timestamp when challenge was completed last time. */ @Expose - private Map challengesTimestamp = new HashMap<>(); + private Map challengesTimestamp = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); /** * Set of Strings that contains all challenge levels that are completed. */ @Expose - private Set levelsDone = new HashSet<>(); + private Set levelsDone = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); /** * Stores history about challenge completion. @@ -203,9 +203,9 @@ public class ChallengesPlayerData implements DataObject */ public void reset(@NonNull String worldName) { - challengeStatus.keySet().removeIf(n -> n.startsWith(worldName)); - challengesTimestamp.keySet().removeIf(n -> n.startsWith(worldName)); - levelsDone.removeIf(n -> n.startsWith(worldName)); + challengeStatus.keySet().removeIf(n -> n.regionMatches(true, 0, worldName, 0, worldName.length())); + challengesTimestamp.keySet().removeIf(n -> n.regionMatches(true, 0, worldName, 0, worldName.length())); + levelsDone.removeIf(n -> n.regionMatches(true, 0, worldName, 0, worldName.length())); } @@ -345,7 +345,7 @@ public class ChallengesPlayerData implements DataObject } else { - return uniqueId.equals(other.uniqueId); + return uniqueId.equalsIgnoreCase(other.uniqueId); } } } \ No newline at end of file diff --git a/src/main/java/world/bentobox/challenges/tasks/TryToComplete.java b/src/main/java/world/bentobox/challenges/tasks/TryToComplete.java index ee1aaed..8c630fa 100644 --- a/src/main/java/world/bentobox/challenges/tasks/TryToComplete.java +++ b/src/main/java/world/bentobox/challenges/tasks/TryToComplete.java @@ -516,7 +516,7 @@ public class TryToComplete result = EMPTY_RESULT; } else if (Util.getWorld(this.world) != Util.getWorld(this.user.getWorld()) || - !this.challenge.getUniqueId().startsWith(Util.getWorld(this.world).getName())) + !this.challenge.matchWorld(Util.getWorld(this.world).getName())) { this.user.sendMessage("general.errors.wrong-world"); result = EMPTY_RESULT;