Implement option that excludes undeployed challenges

The new option allows to toggle if undeployed challenges should be included in level completion count. Disabling option will not include these challenges for level completion.

Fixes #315
This commit is contained in:
BONNe 2023-04-02 14:47:10 +03:00
parent de7172ef75
commit 5ab4237df4
9 changed files with 138 additions and 30 deletions

View File

@ -32,7 +32,7 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>16</java.version> <java.version>17</java.version>
<powermock.version>2.0.9</powermock.version> <powermock.version>2.0.9</powermock.version>
<!-- More visible way how to change dependency versions --> <!-- More visible way how to change dependency versions -->
<spigot.version>1.17.1-R0.1-SNAPSHOT</spigot.version> <spigot.version>1.17.1-R0.1-SNAPSHOT</spigot.version>

View File

@ -408,8 +408,18 @@ public class ChallengesAddon extends Addon {
addonName + "_latest_level_uncompleted_count", addonName + "_latest_level_uncompleted_count",
user -> { user -> {
ChallengeLevel level = this.challengesManager.getLatestUnlockedLevel(user, world); ChallengeLevel level = this.challengesManager.getLatestUnlockedLevel(user, world);
return String.valueOf(level != null ?
level.getChallenges().size() - this.challengesManager.getLevelCompletedChallengeCount(user, world, level) : 0); if (level == null)
{
return "0";
}
int challengeCount = this.getChallengesSettings().isIncludeUndeployed() ?
level.getChallenges().size() :
this.challengesManager.getLevelChallenges(level, false).size();
return String.valueOf(challengeCount -
this.challengesManager.getLevelCompletedChallengeCount(user, world, level));
}); });
} }

View File

@ -106,11 +106,10 @@ public class Settings implements ConfigObject
@ConfigComment("Valid values are:") @ConfigComment("Valid values are:")
@ConfigComment(" 'VISIBLE' - there will be no hidden challenges. All challenges will be viewable in GUI.") @ConfigComment(" 'VISIBLE' - there will be no hidden challenges. All challenges will be viewable in GUI.")
@ConfigComment(" 'HIDDEN' - shows only deployed challenges.") @ConfigComment(" 'HIDDEN' - shows only deployed challenges.")
@ConfigComment(" 'TOGGLEABLE' - there will be button in GUI that allows users to switch from ALL modes.")
@ConfigComment("TOGGLEABLE - Currently not implemented.")
@ConfigEntry(path = "gui-settings.undeployed-view-mode") @ConfigEntry(path = "gui-settings.undeployed-view-mode")
private VisibilityMode visibilityMode = VisibilityMode.VISIBLE; private VisibilityMode visibilityMode = VisibilityMode.VISIBLE;
@ConfigComment("") @ConfigComment("")
@ConfigComment("This allows to change default locked level icon. This option may be") @ConfigComment("This allows to change default locked level icon. This option may be")
@ConfigComment("overwritten by each challenge level. If challenge level has specified") @ConfigComment("overwritten by each challenge level. If challenge level has specified")
@ -130,6 +129,13 @@ public class Settings implements ConfigObject
@ConfigEntry(path = "reset-challenges") @ConfigEntry(path = "reset-challenges")
private boolean resetChallenges = true; private boolean resetChallenges = true;
@ConfigComment("")
@ConfigComment("This option indicates if undepolyed challenges should be counted to level completion.")
@ConfigComment("Disabling this option will make it so that only deployed challenges will be counted.")
@ConfigComment("Default: true")
@ConfigEntry(path = "include-undeployed")
private boolean includeUndeployed = true;
@ConfigComment("") @ConfigComment("")
@ConfigComment("Broadcast 1st time challenge completion messages to all players.") @ConfigComment("Broadcast 1st time challenge completion messages to all players.")
@ConfigComment("Change to false if the spam becomes too much.") @ConfigComment("Change to false if the spam becomes too much.")
@ -165,7 +171,7 @@ public class Settings implements ConfigObject
* Configuration version * Configuration version
*/ */
@ConfigComment("") @ConfigComment("")
private String configVersion = "v3"; private String configVersion = "v4";
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -597,4 +603,26 @@ public class Settings implements ConfigObject
{ {
this.visibilityMode = visibilityMode; this.visibilityMode = visibilityMode;
} }
/**
* Is count undeployed to completion boolean.
*
* @return the boolean
*/
public boolean isIncludeUndeployed()
{
return includeUndeployed;
}
/**
* Sets count undeployed to completion.
*
* @param includeUndeployed the count undeployed to completion
*/
public void setIncludeUndeployed(boolean includeUndeployed)
{
this.includeUndeployed = includeUndeployed;
}
} }

View File

@ -1126,11 +1126,20 @@ public class ChallengesManager
// know how many challenges there were and how many has been done. Then // know how many challenges there were and how many has been done. Then
// remove waiver amount to get count of challenges that still necessary to do. // remove waiver amount to get count of challenges that still necessary to do.
List<Challenge> previousChallengeList = previousLevel == null ?
Collections.emptyList() :
this.getLevelChallenges(previousLevel);
int challengesToDo = previousLevel == null ? 0 : int challengesToDo = previousLevel == null ? 0 :
(previousLevel.getChallenges().size() - doneChallengeCount - previousLevel.getWaiverAmount()); (previousChallengeList.size() - doneChallengeCount - previousLevel.getWaiverAmount());
List<Challenge> challengeList = this.getLevelChallenges(level);
// As level already contains unique ids of challenges, just iterate through them. // As level already contains unique ids of challenges, just iterate through them.
doneChallengeCount = (int) level.getChallenges().stream().filter(playerData::isChallengeDone).count(); doneChallengeCount = (int) challengeList.stream().
map(Challenge::getUniqueId).
filter(playerData::isChallengeDone).
count();
// Mark if level is unlocked // Mark if level is unlocked
boolean unlocked = previousUnlocked && challengesToDo <= 0; boolean unlocked = previousUnlocked && challengesToDo <= 0;
@ -1139,7 +1148,7 @@ public class ChallengesManager
level, level,
previousLevel, previousLevel,
challengesToDo, challengesToDo,
level.getChallenges().size() == doneChallengeCount, challengeList.size() == doneChallengeCount,
unlocked)); unlocked));
previousLevel = level; previousLevel = level;
@ -1175,18 +1184,27 @@ public class ChallengesManager
{ {
ChallengeLevel previousLevel = levelIndex < 1 ? null : challengeLevelList.get(levelIndex - 1); ChallengeLevel previousLevel = levelIndex < 1 ? null : challengeLevelList.get(levelIndex - 1);
List<Challenge> previousChallengeList = previousLevel == null ? Collections.emptyList() :
this.getLevelChallenges(previousLevel);
int challengesToDo = previousLevel == null ? 0 : int challengesToDo = previousLevel == null ? 0 :
(previousLevel.getChallenges().size() - previousLevel.getWaiverAmount()) - (previousChallengeList.size() - previousLevel.getWaiverAmount()) -
(int) previousLevel.getChallenges().stream().filter(playerData::isChallengeDone).count(); (int) previousChallengeList.stream().map(Challenge::getUniqueId).
filter(playerData::isChallengeDone).count();
List<Challenge> challengeList = this.getLevelChallenges(level);
// As level already contains unique ids of challenges, just iterate through them. // As level already contains unique ids of challenges, just iterate through them.
int doneChallengeCount = (int) level.getChallenges().stream().filter(playerData::isChallengeDone).count(); int doneChallengeCount = (int) challengeList.stream().
map(Challenge::getUniqueId).
filter(playerData::isChallengeDone).
count();
return new LevelStatus( return new LevelStatus(
level, level,
previousLevel, previousLevel,
challengesToDo, challengesToDo,
level.getChallenges().size() == doneChallengeCount, challengeList.size() == doneChallengeCount,
challengesToDo <= 0); challengesToDo <= 0);
} }
} }
@ -1214,9 +1232,15 @@ public class ChallengesManager
{ {
this.addPlayerData(storageDataID); this.addPlayerData(storageDataID);
ChallengesPlayerData playerData = this.playerCacheData.get(storageDataID); ChallengesPlayerData playerData = this.playerCacheData.get(storageDataID);
long doneChallengeCount = level.getChallenges().stream().filter(playerData::isChallengeDone).count();
return level.getChallenges().size() == doneChallengeCount; List<Challenge> challengeList = this.getLevelChallenges(level);
long doneChallengeCount = challengeList.stream().
map(Challenge::getUniqueId).
filter(playerData::isChallengeDone).
count();
return challengeList.size() == doneChallengeCount;
} }
@ -1775,11 +1799,11 @@ public class ChallengesManager
{ {
// Free Challenges hides under FREE level. // Free Challenges hides under FREE level.
return this.islandWorldManager.getAddon(world).map(gameMode -> return this.islandWorldManager.getAddon(world).map(gameMode ->
this.challengeCacheData.values().stream(). this.challengeCacheData.values().stream().
filter(challenge -> challenge.getLevel().equals(FREE) && filter(challenge -> challenge.getLevel().equals(FREE) &&
challenge.matchGameMode(gameMode.getDescription().getName())). challenge.matchGameMode(gameMode.getDescription().getName())).
sorted(Comparator.comparing(Challenge::getOrder)). sorted(Comparator.comparing(Challenge::getOrder)).
collect(Collectors.toList())). collect(Collectors.toList())).
orElse(Collections.emptyList()); orElse(Collections.emptyList());
} }
@ -1790,10 +1814,24 @@ public class ChallengesManager
* @return List with challenges in given level. * @return List with challenges in given level.
*/ */
public List<Challenge> getLevelChallenges(ChallengeLevel level) public List<Challenge> getLevelChallenges(ChallengeLevel level)
{
return this.getLevelChallenges(level,
this.addon.getChallengesSettings().isIncludeUndeployed());
}
/**
* Level which challenges must be received
* @param level Challenge level.
* @param includeUndeployed if true, then include challenges that are not deployed.
* @return List with challenges in given level.
*/
public List<Challenge> getLevelChallenges(ChallengeLevel level, boolean includeUndeployed)
{ {
return level.getChallenges().stream(). return level.getChallenges().stream().
map(this::getChallenge). map(this::getChallenge).
filter(Objects::nonNull). filter(Objects::nonNull).
filter(challenge -> includeUndeployed || challenge.isDeployed()).
sorted(Comparator.comparing(Challenge::getOrder)). sorted(Comparator.comparing(Challenge::getOrder)).
collect(Collectors.toList()); collect(Collectors.toList());
} }
@ -1912,7 +1950,9 @@ public class ChallengesManager
*/ */
public int getChallengeCount(World world) public int getChallengeCount(World world)
{ {
return this.getAllChallenges(world).size(); return (int) this.getAllChallenges(world).stream().
filter(challenge -> this.settings.isIncludeUndeployed() || challenge.isDeployed()).
count();
} }

View File

@ -942,14 +942,17 @@ public abstract class CommonPanel
else else
{ {
ChallengeLevel level = levelStatus.getLevel(); ChallengeLevel level = levelStatus.getLevel();
List<Challenge> challengeList = this.addon.getChallengesManager().getLevelChallenges(level);
// Check if unlock message should appear. // Check if unlock message should appear.
int doneChallenges = (int) level.getChallenges().stream(). int doneChallenges = (int) challengeList.
stream().
filter(challenge -> this.addon.getChallengesManager().isChallengeComplete(user.getUniqueId(), world, challenge)). filter(challenge -> this.addon.getChallengesManager().isChallengeComplete(user.getUniqueId(), world, challenge)).
count(); count();
return this.user.getTranslation(reference + "completed-challenges-of", return this.user.getTranslation(reference + "completed-challenges-of",
"[number]", String.valueOf(doneChallenges), "[number]", String.valueOf(doneChallenges),
"[max]", String.valueOf(level.getChallenges().size())); "[max]", String.valueOf(challengeList.size()));
} }
} }

View File

@ -212,7 +212,7 @@ public class EditLevelPanel extends CommonPagedPanel<Challenge>
private void buildChallengesPanel(PanelBuilder panelBuilder) private void buildChallengesPanel(PanelBuilder panelBuilder)
{ {
List<Challenge> challengeList = this.addon.getChallengesManager(). List<Challenge> challengeList = this.addon.getChallengesManager().
getLevelChallenges(this.challengeLevel).stream(). getLevelChallenges(this.challengeLevel, true).stream().
filter(challenge -> this.searchString.isBlank() || filter(challenge -> this.searchString.isBlank() ||
challenge.getFriendlyName().toLowerCase().contains(this.searchString.toLowerCase()) || challenge.getFriendlyName().toLowerCase().contains(this.searchString.toLowerCase()) ||
challenge.getUniqueId().toLowerCase().contains(this.searchString.toLowerCase()) || challenge.getUniqueId().toLowerCase().contains(this.searchString.toLowerCase()) ||
@ -784,7 +784,7 @@ public class EditLevelPanel extends CommonPagedPanel<Challenge>
// Get all challenge that is not in current level. // Get all challenge that is not in current level.
List<Challenge> challengeList = manager.getAllChallenges(this.world); List<Challenge> challengeList = manager.getAllChallenges(this.world);
challengeList.removeAll(manager.getLevelChallenges(this.challengeLevel)); challengeList.removeAll(manager.getLevelChallenges(this.challengeLevel, true));
// Generate descriptions for these challenges // Generate descriptions for these challenges
Map<Challenge, List<String>> challengeDescriptionMap = challengeList.stream(). Map<Challenge, List<String>> challengeDescriptionMap = challengeList.stream().
@ -820,7 +820,7 @@ public class EditLevelPanel extends CommonPagedPanel<Challenge>
ChallengesManager manager = this.addon.getChallengesManager(); ChallengesManager manager = this.addon.getChallengesManager();
// Get all challenge that is in current level. // Get all challenge that is in current level.
List<Challenge> challengeList = manager.getLevelChallenges(this.challengeLevel); List<Challenge> challengeList = manager.getLevelChallenges(this.challengeLevel, true);
// Generate descriptions for these challenges // Generate descriptions for these challenges
Map<Challenge, List<String>> challengeDescriptionMap = challengeList.stream(). Map<Challenge, List<String>> challengeDescriptionMap = challengeList.stream().

View File

@ -119,6 +119,7 @@ public class EditSettingsPanel extends CommonPanel
panelBuilder.item(11, this.getSettingsButton(Button.GLOW_COMPLETED)); panelBuilder.item(11, this.getSettingsButton(Button.GLOW_COMPLETED));
panelBuilder.item(20, this.getSettingsButton(Button.REMOVE_COMPLETED)); panelBuilder.item(20, this.getSettingsButton(Button.REMOVE_COMPLETED));
panelBuilder.item(29, this.getSettingsButton(Button.VISIBILITY_MODE)); panelBuilder.item(29, this.getSettingsButton(Button.VISIBILITY_MODE));
panelBuilder.item(30, this.getSettingsButton(Button.INCLUDE_UNDEPLOYED));
panelBuilder.item(21, this.getSettingsButton(Button.LOCKED_LEVEL_ICON)); panelBuilder.item(21, this.getSettingsButton(Button.LOCKED_LEVEL_ICON));
@ -414,9 +415,6 @@ public class EditSettingsPanel extends CommonPanel
description.add(this.user.getTranslation(reference + description.add(this.user.getTranslation(reference +
(this.settings.getVisibilityMode().equals(VisibilityMode.HIDDEN) ? "enabled" : "disabled")) + (this.settings.getVisibilityMode().equals(VisibilityMode.HIDDEN) ? "enabled" : "disabled")) +
this.user.getTranslation(reference + "hidden")); this.user.getTranslation(reference + "hidden"));
description.add(this.user.getTranslation(reference +
(this.settings.getVisibilityMode().equals(VisibilityMode.TOGGLEABLE) ? "enabled" : "disabled")) +
this.user.getTranslation(reference + "toggleable"));
if (this.settings.getVisibilityMode().equals(VisibilityMode.VISIBLE)) if (this.settings.getVisibilityMode().equals(VisibilityMode.VISIBLE))
{ {
@ -454,6 +452,22 @@ public class EditSettingsPanel extends CommonPanel
description.add(this.user.getTranslation(Constants.TIPS + "left-click-to-cycle")); description.add(this.user.getTranslation(Constants.TIPS + "left-click-to-cycle"));
description.add(this.user.getTranslation(Constants.TIPS + "right-click-to-cycle")); description.add(this.user.getTranslation(Constants.TIPS + "right-click-to-cycle"));
} }
case INCLUDE_UNDEPLOYED -> {
description.add(this.user.getTranslation(reference +
(this.settings.isIncludeUndeployed() ? "enabled" : "disabled")));
icon = new ItemStack(Material.BARREL);
clickHandler = (panel, user1, clickType, i) -> {
this.settings.setIncludeUndeployed(!this.settings.isIncludeUndeployed());
panel.getInventory().setItem(i, this.getSettingsButton(button).getItem());
this.addon.saveSettings();
return true;
};
glow = this.settings.isIncludeUndeployed();
description.add("");
description.add(this.user.getTranslation(Constants.TIPS + "click-to-toggle"));
}
default -> { default -> {
icon = new ItemStack(Material.PAPER); icon = new ItemStack(Material.PAPER);
clickHandler = null; clickHandler = null;
@ -557,6 +571,10 @@ public class EditSettingsPanel extends CommonPanel
LOCKED_LEVEL_ICON, LOCKED_LEVEL_ICON,
SHOW_TITLE, SHOW_TITLE,
TITLE_SHOWTIME, TITLE_SHOWTIME,
/**
* This allows to switch between counting/not couting undeployed challenges.
*/
INCLUDE_UNDEPLOYED,
/** /**
* This allows to switch between different challenges visibility modes. * This allows to switch between different challenges visibility modes.
*/ */

View File

@ -130,7 +130,7 @@ public class ChallengesPanel extends CommonPanel
{ {
if (this.lastSelectedLevel != null) if (this.lastSelectedLevel != null)
{ {
this.challengeList = this.manager.getLevelChallenges(this.lastSelectedLevel.getLevel()); this.challengeList = this.manager.getLevelChallenges(this.lastSelectedLevel.getLevel(), true);
if (this.addon.getChallengesSettings().isRemoveCompleteOneTimeChallenges()) if (this.addon.getChallengesSettings().isRemoveCompleteOneTimeChallenges())
{ {

View File

@ -683,6 +683,15 @@ challenges:
visible: "Show visible challenges" visible: "Show visible challenges"
hidden: "Show all challenges" hidden: "Show all challenges"
toggleable: "Allow toggling" toggleable: "Allow toggling"
include_undeployed:
name: "&f&l Include Undeployed Challenges"
description: |-
&7 Indicates if undeployed
&7 challenges should be
&7 counted towards level
&7 completion.
enabled: "&2 Enabled"
disabled: "&c Disabled"
download: download:
name: "&f&l Download Libraries" name: "&f&l Download Libraries"
description: |- description: |-