Skip to content

Commit

Permalink
Fix issue with wrongly applied world name lowercasing.
Browse files Browse the repository at this point in the history
It looks like, exist plugins that keep capital letters in world names. That mean, it is not correct to lowercasing any id's.
To fix it, now, instead of lowercasing, challenges should be case insensitive.
  • Loading branch information
BONNe committed Jul 24, 2019
1 parent 2a30185 commit 9681494
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 89 deletions.
87 changes: 8 additions & 79 deletions src/main/java/world/bentobox/challenges/ChallengesManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,82 +107,11 @@ public ChallengesManager(ChallengesAddon addon)
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<Challenge> 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<ChallengeLevel> 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<String> 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<ChallengesPlayerData> playerDataList = this.playersDatabase.loadObjects();

playerDataList.forEach(challengesPlayerData -> {

Map<String, Integer> fixedChallengeStatus = new HashMap<>();
challengesPlayerData.getChallengeStatus().forEach((challenge, count) ->
fixedChallengeStatus.put(challenge.toLowerCase(), count));
challengesPlayerData.setChallengeStatus(fixedChallengeStatus);

Map<String, Long> fixedChallengeTimestamp = new HashMap<>();
challengesPlayerData.getChallengesTimestamp().forEach((challenge, count) ->
fixedChallengeTimestamp.put(challenge.toLowerCase(), count));
challengesPlayerData.setChallengesTimestamp(fixedChallengeTimestamp);

Set<String> 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.");
});
}
}
}


Expand Down Expand Up @@ -1263,7 +1192,7 @@ public List<String> getAllChallengesNames(@NonNull World world)
// 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());
}
Expand All @@ -1286,7 +1215,7 @@ public List<Challenge> getAllChallenges(@NonNull World world)

// 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());
}
Expand Down Expand Up @@ -1464,7 +1393,7 @@ public List<ChallengeLevel> getLevels(String world)
// 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());
}

Expand Down Expand Up @@ -1685,8 +1614,8 @@ public boolean hasAnyChallengeData(@NonNull World world)
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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,20 @@ public void setRepeatRewardCommands(List<String> repeatRewardCommands)
// ---------------------------------------------------------------------


/**
* 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
Expand Down Expand Up @@ -1018,7 +1032,7 @@ public boolean equals(Object obj)
}
else
{
return uniqueId.equals(other.uniqueId);
return uniqueId.equalsIgnoreCase(other.uniqueId);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,20 @@ public void setChallenges(Set<String> challenges)
// ---------------------------------------------------------------------


/**
* 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}
*/
Expand Down Expand Up @@ -494,7 +508,7 @@ public boolean equals(Object obj)
}
else
{
return uniqueId.equals(other.uniqueId);
return uniqueId.equalsIgnoreCase(other.uniqueId);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,20 @@ public ChallengesPlayerData(String uniqueId)
* completed
*/
@Expose
private Map<String, Integer> challengeStatus = new HashMap<>();
private Map<String, Integer> 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<String, Long> challengesTimestamp = new HashMap<>();
private Map<String, Long> challengesTimestamp = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);

/**
* Set of Strings that contains all challenge levels that are completed.
*/
@Expose
private Set<String> levelsDone = new HashSet<>();
private Set<String> levelsDone = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);

/**
* Stores history about challenge completion.
Expand Down Expand Up @@ -203,9 +203,9 @@ public void setHistory(List<LogEntry> history)
*/
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()));
}


Expand Down Expand Up @@ -345,7 +345,7 @@ public boolean equals(Object obj)
}
else
{
return uniqueId.equals(other.uniqueId);
return uniqueId.equalsIgnoreCase(other.uniqueId);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ else if (maxTimes < 1)
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;
Expand Down

0 comments on commit 9681494

Please sign in to comment.