addon-challenges/src/main/java/world/bentobox/challenges/panel/CommonPanel.java

899 lines
39 KiB
Java
Raw Normal View History

//
// Created by BONNe
// Copyright - 2021
//
package world.bentobox.challenges.panel;
import java.time.Duration;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.util.Util;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.database.object.requirements.InventoryRequirements;
import world.bentobox.challenges.database.object.requirements.IslandRequirements;
import world.bentobox.challenges.database.object.requirements.OtherRequirements;
import world.bentobox.challenges.database.object.requirements.StatisticRequirements;
import world.bentobox.challenges.managers.ChallengesManager;
import world.bentobox.challenges.utils.Constants;
import world.bentobox.challenges.utils.LevelStatus;
import world.bentobox.challenges.utils.Utils;
/**
* This class contains common methods for all panels.
*/
public abstract class CommonPanel {
/**
* This is default constructor for all classes that extends CommonPanel.
*
* @param addon ChallengesAddon instance.
* @param user User who opens panel.
*/
protected CommonPanel(ChallengesAddon addon, User user, World world, String topLabel, String permissionPrefix) {
this.addon = addon;
this.world = world;
this.manager = addon.getChallengesManager();
this.user = user;
this.topLabel = topLabel;
this.permissionPrefix = permissionPrefix;
this.parentPanel = null;
2024-03-11 02:44:57 +01:00
this.returnButton = new PanelItemBuilder().name(this.user.getTranslation(Constants.BUTTON + "quit.name"))
.description(this.user.getTranslationOrNothing(Constants.BUTTON + "quit.description")).description("")
.description(this.user.getTranslationOrNothing(Constants.TIPS + "click-to-quit"))
.icon(Material.OAK_DOOR).clickHandler((panel, user1, clickType, i) -> {
this.user.closeInventory();
return true;
}).build();
}
/**
* This is default constructor for all classes that extends CommonPanel.
*
* @param parentPanel Parent panel of current panel.
*/
protected CommonPanel(@NonNull CommonPanel parentPanel) {
this.addon = parentPanel.addon;
this.manager = parentPanel.manager;
this.user = parentPanel.user;
this.world = parentPanel.world;
this.topLabel = parentPanel.topLabel;
this.permissionPrefix = parentPanel.permissionPrefix;
this.parentPanel = parentPanel;
2024-03-11 02:44:57 +01:00
this.returnButton = new PanelItemBuilder().name(this.user.getTranslation(Constants.BUTTON + "return.name"))
.description(this.user.getTranslationOrNothing(Constants.BUTTON + "return.description")).description("")
.description(this.user.getTranslationOrNothing(Constants.TIPS + "click-to-return"))
.icon(Material.OAK_DOOR).clickHandler((panel, user1, clickType, i) -> {
this.parentPanel.build();
return true;
}).build();
}
/**
* This method allows building panel.
*/
protected abstract void build();
/**
* This method reopens given panel.
*
* @param panel Panel that must be reopened.
*/
public static void reopen(CommonPanel panel) {
panel.build();
}
2024-03-11 02:44:57 +01:00
// ---------------------------------------------------------------------
// Section: Common methods
// ---------------------------------------------------------------------
/**
* This method generates and returns given challenge description. It is used
* here to avoid multiple duplicates, as it would be nice to have single place
* where challenge could be generated.
*
* @param challenge Challenge which description must be generated.
* @param target target player.
* @return List of strings that will be used in challenges description.
*/
protected List<String> generateChallengeDescription(Challenge challenge, @Nullable User target) {
// Some values to avoid over checking.
2024-03-11 02:44:57 +01:00
final boolean isCompletedOnce = target != null
&& this.manager.isChallengeComplete(target.getUniqueId(), this.world, challenge);
2024-03-11 02:44:57 +01:00
final long doneTimes = target != null && challenge.isRepeatable()
? this.manager.getChallengeTimes(target, this.world, challenge)
: (isCompletedOnce ? 0 : 1);
2024-03-11 02:44:57 +01:00
boolean isCompletedAll = isCompletedOnce
&& (!challenge.isRepeatable() || challenge.getMaxTimes() > 0 && doneTimes >= challenge.getMaxTimes());
final String reference = Constants.DESCRIPTIONS + "challenge.";
// Get description from custom translations
2024-03-11 02:44:57 +01:00
String description = this.user
.getTranslationOrNothing("challenges.challenges." + challenge.getUniqueId() + ".description");
2024-03-11 02:44:57 +01:00
if (description.isEmpty()) {
// Get data from object in single string.
description = Util.translateColorCodes(String.join("\n", challenge.getDescription()));
}
2024-03-11 02:44:57 +01:00
// Non-memory optimal code used for easier debugging and nicer code layout for
// my eye :)
// Get status in single string
2024-03-11 02:44:57 +01:00
String status = this.generateChallengeStatus(isCompletedOnce, isCompletedAll, doneTimes,
challenge.getMaxTimes());
// Get requirements in single string
String requirements = isCompletedAll ? "" : this.generateRequirements(challenge, target);
// Get rewards in single string
String rewards = isCompletedAll ? "" : this.generateRewards(challenge, isCompletedOnce);
// Get coolDown in singe string
2024-03-11 02:44:57 +01:00
String coolDown = isCompletedAll || challenge.getTimeout() <= 0 ? "" : this.generateCoolDown(challenge, target);
2024-03-11 02:44:57 +01:00
if (!description.replaceAll("(?m)^[ \\t]*\\r?\\n", "").isEmpty()) {
String returnString = this.user.getTranslationOrNothing(reference + "lore", "[requirements]", requirements,
"[rewards]", rewards, "[status]", status, "[cooldown]", coolDown);
// remove empty lines from the generated text.
2024-03-11 02:44:57 +01:00
List<String> collect = Arrays.stream(returnString.replaceAll("(?m)^[ \\t]*\\r?\\n", "").split("\n"))
.collect(Collectors.toList());
// find and replace description from collected blocks.
2024-03-11 02:44:57 +01:00
for (int i = 0; i < collect.size(); i++) {
if (collect.get(i).contains(Constants.PARAMETER_DESCRIPTION)) {
2021-09-19 20:04:09 +02:00
collect.set(i, collect.get(i).replace(Constants.PARAMETER_DESCRIPTION, description));
}
}
return collect;
2024-03-11 02:44:57 +01:00
} else {
String returnString = this.user.getTranslationOrNothing(reference + "lore", Constants.PARAMETER_DESCRIPTION,
description, "[requirements]", requirements, "[rewards]", rewards, "[status]", status, "[cooldown]",
coolDown);
// Remove empty lines and returns as a list.
2024-03-11 02:44:57 +01:00
return Arrays.stream(returnString.replaceAll("(?m)^[ \\t]*\\r?\\n", "").split("\n"))
.collect(Collectors.toList());
}
}
/**
* Generate cool down string.
*
* @param challenge the challenge
* @param target the target
* @return the string
*/
private String generateCoolDown(Challenge challenge, @Nullable User target) {
final String reference = Constants.DESCRIPTIONS + "challenge.cooldown.";
String coolDown;
2024-03-11 02:44:57 +01:00
if (target != null && this.manager.isBreachingTimeOut(target, this.world, challenge)) {
long missing = this.manager.getLastCompletionDate(this.user, this.world, challenge) + challenge.getTimeout()
- System.currentTimeMillis();
2024-03-11 02:44:57 +01:00
coolDown = this.user.getTranslation(reference + "wait-time", "[time]",
Utils.parseDuration(Duration.ofMillis(missing), this.user));
} else {
coolDown = "";
}
2024-03-11 02:44:57 +01:00
String timeout = this.user.getTranslation(reference + "timeout", "[time]",
Utils.parseDuration(Duration.ofMillis(challenge.getTimeout()), this.user));
2024-03-11 02:44:57 +01:00
return this.user.getTranslation(reference + "lore", "[timeout]", timeout, "[wait-time]", coolDown);
}
/**
* This method generate requirements description for given challenge.
*
* @param challenge Challenge which requirements must be generated.
* @return Lore message with requirements.
*/
private String generateRequirements(Challenge challenge, @Nullable User target) {
final String reference = Constants.DESCRIPTIONS + "challenge.requirements.";
String environment;
2024-03-11 02:44:57 +01:00
if (challenge.getEnvironment().isEmpty() || challenge.getEnvironment().size() == 3) {
// If challenge can be completed everywhere, do not display requirement.
environment = "";
2024-03-11 02:44:57 +01:00
} else if (challenge.getEnvironment().size() == 1) {
environment = this.user.getTranslationOrNothing(reference + "environment-single",
2024-03-11 02:44:57 +01:00
Constants.PARAMETER_ENVIRONMENT,
Utils.prettifyObject(challenge.getEnvironment().iterator().next(), this.user));
} else {
StringBuilder builder = new StringBuilder();
builder.append(this.user.getTranslationOrNothing(reference + "environment-title"));
2024-03-11 02:44:57 +01:00
challenge.getEnvironment().stream().sorted().forEach(en -> {
builder.append("\n");
builder.append(this.user.getTranslationOrNothing(reference + "environment-single",
2024-03-11 02:44:57 +01:00
Constants.PARAMETER_ENVIRONMENT, Utils.prettifyObject(en, this.user)));
});
environment = builder.toString();
}
String permissions;
2024-03-11 02:44:57 +01:00
if (!challenge.getRequirements().getRequiredPermissions().isEmpty()) {
// Yes list duplication for complete menu.
2024-03-11 02:44:57 +01:00
List<String> missingPermissions = challenge.getRequirements().getRequiredPermissions().stream()
.filter(permission -> target == null || !target.hasPermission(permission)).sorted().toList();
StringBuilder permissionBuilder = new StringBuilder();
2024-03-11 02:44:57 +01:00
if (missingPermissions.size() == 1) {
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "permission-single",
2024-03-11 02:44:57 +01:00
Constants.PARAMETER_PERMISSION, missingPermissions.get(0)));
} else if (!missingPermissions.isEmpty()) {
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "permissions-title"));
2024-03-11 02:44:57 +01:00
missingPermissions.forEach(permission -> {
permissionBuilder.append("\n");
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "permissions-list",
2024-03-11 02:44:57 +01:00
Constants.PARAMETER_PERMISSION, permission));
});
}
permissions = permissionBuilder.toString();
2024-03-11 02:44:57 +01:00
} else {
permissions = "";
}
String typeRequirement = switch (challenge.getChallengeType()) {
2024-03-11 02:44:57 +01:00
case INVENTORY_TYPE -> this.generateInventoryChallenge(challenge.getRequirements());
case ISLAND_TYPE -> this.generateIslandChallenge(challenge.getRequirements());
case OTHER_TYPE -> this.generateOtherChallenge(challenge.getRequirements());
case STATISTIC_TYPE -> this.generateStatisticChallenge(challenge.getRequirements());
};
2024-03-11 02:44:57 +01:00
return this.user.getTranslationOrNothing(reference + "lore", Constants.PARAMETER_ENVIRONMENT, environment,
"[type-requirement]", typeRequirement, "[permissions]", permissions);
}
/**
* This method generates lore message for island requirement.
*
* @param requirement Island Requirement.
* @return Requirement lore message.
*/
private String generateIslandChallenge(IslandRequirements requirement) {
final String reference = Constants.DESCRIPTIONS + "challenge.requirements.island.";
String blocks;
2024-03-11 02:44:57 +01:00
if (!requirement.getRequiredBlocks().isEmpty()) {
StringBuilder builder = new StringBuilder();
builder.append(this.user.getTranslationOrNothing(reference + "blocks-title"));
2024-03-11 02:44:57 +01:00
requirement.getRequiredBlocks().entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry -> {
builder.append("\n");
if (entry.getValue() > 1) {
builder.append(this.user.getTranslationOrNothing(reference + "blocks-value",
Constants.PARAMETER_NUMBER, String.valueOf(entry.getValue()), Constants.PARAMETER_MATERIAL,
Utils.prettifyObject(entry.getKey(), this.user)));
} else {
builder.append(this.user.getTranslationOrNothing(reference + "block-value",
2021-09-19 20:04:09 +02:00
Constants.PARAMETER_MATERIAL, Utils.prettifyObject(entry.getKey(), this.user)));
2024-03-11 02:44:57 +01:00
}
});
blocks = builder.toString();
2024-03-11 02:44:57 +01:00
} else {
blocks = "";
}
String entities;
2024-03-11 02:44:57 +01:00
if (!requirement.getRequiredEntities().isEmpty()) {
StringBuilder builder = new StringBuilder();
builder.append(this.user.getTranslationOrNothing(reference + "entities-title"));
2024-03-11 02:44:57 +01:00
requirement.getRequiredEntities().entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry -> {
builder.append("\n");
if (entry.getValue() > 1) {
builder.append(this.user.getTranslationOrNothing(reference + "entities-value",
Constants.PARAMETER_NUMBER, String.valueOf(entry.getValue()), Constants.PARAMETER_ENTITY,
Utils.prettifyObject(entry.getKey(), this.user)));
} else {
builder.append(this.user.getTranslationOrNothing(reference + "entity-value",
2021-09-19 20:04:09 +02:00
Constants.PARAMETER_ENTITY, Utils.prettifyObject(entry.getKey(), this.user)));
2024-03-11 02:44:57 +01:00
}
});
entities = builder.toString();
2024-03-11 02:44:57 +01:00
} else {
entities = "";
}
2024-03-11 02:44:57 +01:00
String searchRadius = this.user.getTranslationOrNothing(reference + "search-radius", Constants.PARAMETER_NUMBER,
String.valueOf(requirement.getSearchRadius()));
2024-03-11 02:44:57 +01:00
String warningBlocks = requirement.isRemoveBlocks()
? this.user.getTranslationOrNothing(reference + "warning-block")
: "";
String warningEntities = requirement.isRemoveEntities()
? this.user.getTranslationOrNothing(reference + "warning-entity")
: "";
2024-03-11 02:44:57 +01:00
return this.user.getTranslationOrNothing(reference + "lore", "[blocks]", blocks, "[entities]", entities,
"[warning-block]", warningBlocks, "[warning-entity]", warningEntities, "[search-radius]", searchRadius);
}
/**
* This method generates lore message for inventory requirement.
*
* @param requirement Inventory Requirement.
* @return Requirement lore message.
*/
private String generateInventoryChallenge(InventoryRequirements requirement) {
final String reference = Constants.DESCRIPTIONS + "challenge.requirements.inventory.";
String items;
2024-03-11 02:44:57 +01:00
if (!requirement.getRequiredItems().isEmpty()) {
StringBuilder builder = new StringBuilder();
builder.append(this.user.getTranslationOrNothing(reference + "item-title"));
2024-03-11 02:44:57 +01:00
Utils.groupEqualItems(requirement.getRequiredItems(), requirement.getIgnoreMetaData()).stream()
.sorted(Comparator.comparing(ItemStack::getType)).forEach(itemStack -> {
builder.append("\n");
if (itemStack.getAmount() > 1) {
builder.append(this.user.getTranslationOrNothing(reference + "items-value", "[number]",
String.valueOf(itemStack.getAmount()), "[item]",
Utils.prettifyObject(itemStack, this.user)));
} else {
builder.append(this.user.getTranslationOrNothing(reference + "item-value", "[item]",
Utils.prettifyObject(itemStack, this.user)));
}
});
items = builder.toString();
2024-03-11 02:44:57 +01:00
} else {
items = "";
}
2024-03-11 02:44:57 +01:00
String warning = requirement.isTakeItems() ? this.user.getTranslationOrNothing(reference + "warning") : "";
2024-03-11 02:44:57 +01:00
return this.user.getTranslationOrNothing(reference + "lore", "[items]", items, "[warning]", warning);
}
/**
* This method generates lore message for other requirement.
*
* @param requirement Other Requirement.
* @return Requirement lore message.
*/
private String generateOtherChallenge(OtherRequirements requirement) {
final String reference = Constants.DESCRIPTIONS + "challenge.requirements.other.";
2024-03-11 02:44:57 +01:00
String experience = requirement.getRequiredExperience() <= 0 ? ""
: this.user.getTranslationOrNothing(reference + "experience", "[number]",
String.valueOf(requirement.getRequiredExperience()));
2024-03-11 02:44:57 +01:00
String experienceWarning = requirement.getRequiredExperience() > 0 && requirement.isTakeExperience()
? this.user.getTranslationOrNothing(reference + "experience-warning")
: "";
2024-03-11 02:44:57 +01:00
String money = !this.addon.isEconomyProvided() || requirement.getRequiredMoney() <= 0 ? ""
: this.user.getTranslationOrNothing(reference + "money", "[number]",
String.valueOf(requirement.getRequiredMoney()));
2024-03-11 02:44:57 +01:00
String moneyWarning = this.addon.isEconomyProvided() && requirement.getRequiredMoney() > 0
&& requirement.isTakeMoney() ? this.user.getTranslationOrNothing(reference + "money-warning") : "";
2024-03-11 02:44:57 +01:00
String level = !this.addon.isLevelProvided() || requirement.getRequiredIslandLevel() <= 0 ? ""
: this.user.getTranslationOrNothing(reference + "level", "[number]",
String.valueOf(requirement.getRequiredIslandLevel()));
2024-03-11 02:44:57 +01:00
return this.user.getTranslationOrNothing(reference + "lore", "[experience]", experience, "[experience-warning]",
experienceWarning, "[money]", money, "[money-warning]", moneyWarning, "[level]", level);
}
/**
* This method generates lore message for Statistic requirement.
*
* @param requirement Statistic Requirement.
* @return Requirement lore message.
*/
private String generateStatisticChallenge(StatisticRequirements requirement) {
final String reference = Constants.DESCRIPTIONS + "challenge.requirements.statistic.";
String statistic;
2024-03-11 02:44:57 +01:00
if (requirement.getStatistic() == null) {
// Challenges by default comes with empty statistic field.
return "";
}
2024-03-11 02:44:57 +01:00
switch (requirement.getStatistic().getType()) {
case UNTYPED -> statistic = this.user.getTranslationOrNothing(reference + "statistic", "[statistic]",
Utils.prettifyObject(requirement.getStatistic(), this.user), "[number]",
String.valueOf(requirement.getAmount()));
case ITEM, BLOCK -> {
if (requirement.getAmount() > 1) {
statistic = this.user.getTranslationOrNothing(reference + "multiple-target", "[statistic]",
Utils.prettifyObject(requirement.getStatistic(), this.user), "[number]",
String.valueOf(requirement.getAmount()), "[target]",
Utils.prettifyObject(requirement.getMaterial(), this.user));
} else {
statistic = this.user.getTranslationOrNothing(reference + "single-target", "[statistic]",
Utils.prettifyObject(requirement.getStatistic(), this.user), "[target]",
Utils.prettifyObject(requirement.getMaterial(), this.user));
}
2024-03-11 02:44:57 +01:00
}
case ENTITY -> {
if (requirement.getAmount() > 1) {
statistic = this.user.getTranslationOrNothing(reference + "multiple-target", "[statistic]",
Utils.prettifyObject(requirement.getStatistic(), this.user), "[number]",
String.valueOf(requirement.getAmount()), "[target]",
Utils.prettifyObject(requirement.getEntity(), this.user));
} else {
statistic = this.user.getTranslationOrNothing(reference + "single-target", "[statistic]",
Utils.prettifyObject(requirement.getStatistic(), this.user), "[target]",
Utils.prettifyObject(requirement.getEntity(), this.user));
}
2024-03-11 02:44:57 +01:00
}
default -> statistic = "";
}
2024-03-11 02:44:57 +01:00
String warning = requirement.isReduceStatistic() ? this.user.getTranslationOrNothing(reference + "warning")
: "";
2024-03-11 02:44:57 +01:00
return this.user.getTranslationOrNothing(reference + "lore", "[statistic]", statistic, "[warning]", warning);
}
/**
* This message generates challenge status description.
*
* @param completedOnce Indicate that challenge is completed at least one
* time.
* @param completedAll Indicate that challenge is not repeatable anymore.
* @param completionCount Number of completion count.
* @param maxCompletions Number of max completion count.
* @return String with a text that will be generated for status.
*/
private String generateChallengeStatus(boolean completedOnce, boolean completedAll, long completionCount,
2024-03-11 02:44:57 +01:00
int maxCompletions) {
final String reference = Constants.DESCRIPTIONS + "challenge.status.";
2024-03-11 02:44:57 +01:00
if (completedAll) {
if (maxCompletions > 1) {
return this.user.getTranslationOrNothing(reference + "completed-times-reached", Constants.PARAMETER_MAX,
String.valueOf(maxCompletions));
} else {
return this.user.getTranslationOrNothing(reference + "completed");
}
2024-03-11 02:44:57 +01:00
} else if (completedOnce) {
if (maxCompletions > 0) {
return this.user.getTranslationOrNothing(reference + "completed-times-of", Constants.PARAMETER_MAX,
String.valueOf(maxCompletions), Constants.PARAMETER_NUMBER, String.valueOf(completionCount));
} else {
return this.user.getTranslationOrNothing(reference + "completed-times", Constants.PARAMETER_NUMBER,
String.valueOf(completionCount));
}
2024-03-11 02:44:57 +01:00
} else {
return "";
}
}
/**
* This method creates reward lore text.
*
* @param challenge Challenge which reward lore must be generated.
* @param isRepeating Boolean that indicate if it is repeating reward or first
* time.
* @return Reward text.
*/
private String generateRewards(Challenge challenge, boolean isRepeating) {
2024-03-11 02:44:57 +01:00
if (isRepeating) {
return this.generateRepeatReward(challenge);
2024-03-11 02:44:57 +01:00
} else {
return this.generateReward(challenge);
}
}
/**
* This method creates repeat reward lore text.
*
* @param challenge Challenge which reward lore must be generated.
* @return Reward text.
*/
private String generateRepeatReward(Challenge challenge) {
final String reference = Constants.DESCRIPTIONS + "challenge.rewards.";
String items;
2024-03-11 02:44:57 +01:00
if (!challenge.getRepeatItemReward().isEmpty()) {
StringBuilder builder = new StringBuilder();
builder.append(this.user.getTranslationOrNothing(reference + "item-title"));
2024-03-11 02:44:57 +01:00
Utils.groupEqualItems(challenge.getRepeatItemReward(), challenge.getIgnoreRewardMetaData()).stream()
.sorted(Comparator.comparing(ItemStack::getType)).forEach(itemStack -> {
builder.append("\n");
if (itemStack.getAmount() > 1) {
builder.append(this.user.getTranslationOrNothing(reference + "items-value", "[number]",
String.valueOf(itemStack.getAmount()), "[item]",
Utils.prettifyObject(itemStack, this.user)));
} else {
builder.append(this.user.getTranslationOrNothing(reference + "item-value", "[item]",
Utils.prettifyObject(itemStack, this.user)));
}
});
items = builder.toString();
2024-03-11 02:44:57 +01:00
} else {
items = "";
}
2024-03-11 02:44:57 +01:00
String experience = challenge.getRepeatExperienceReward() <= 0 ? ""
: this.user.getTranslationOrNothing(reference + "experience", "[number]",
String.valueOf(challenge.getRepeatExperienceReward()));
2024-03-11 02:44:57 +01:00
String money = !this.addon.isEconomyProvided() || challenge.getRepeatMoneyReward() <= 0 ? ""
: this.user.getTranslationOrNothing(reference + "money", "[number]",
addon.getPlugin().getVault().map(v -> v.format(challenge.getRepeatMoneyReward()))
.orElse(String.valueOf(challenge.getRepeatMoneyReward())));
String commands;
2024-03-11 02:44:57 +01:00
if (!challenge.getRepeatRewardCommands().isEmpty()) {
StringBuilder permissionBuilder = new StringBuilder();
2024-03-11 02:44:57 +01:00
if (!challenge.getRepeatRewardCommands().isEmpty()) {
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "commands-title"));
2024-03-11 02:44:57 +01:00
challenge.getRepeatRewardCommands().forEach(command -> {
permissionBuilder.append("\n");
2024-03-11 02:44:57 +01:00
permissionBuilder
.append(this.user.getTranslationOrNothing(reference + "command", "[command]", command));
});
}
commands = permissionBuilder.toString();
2024-03-11 02:44:57 +01:00
} else {
commands = "";
}
2024-03-11 02:44:57 +01:00
if (challenge.getRepeatRewardText().isEmpty() && items.isEmpty() && experience.isEmpty() && money.isEmpty()
&& commands.isEmpty()) {
// If everything is empty, do not return anything.
return "";
}
2024-03-11 02:44:57 +01:00
String rewardText = this.user
.getTranslationOrNothing("challenges.challenges." + challenge.getUniqueId() + ".repeat-reward-text");
2024-03-11 02:44:57 +01:00
if (rewardText.isEmpty()) {
rewardText = Util.translateColorCodes(String.join("\n", challenge.getRepeatRewardText()));
}
2024-03-11 02:44:57 +01:00
return this.user.getTranslationOrNothing(reference + "lore", "[text]", rewardText, "[items]", items,
"[experience]", experience, "[money]", money, "[commands]", commands);
}
/**
* This method creates reward lore text.
*
* @param challenge Challenge which reward lore must be generated.
* @return Reward text.
*/
private String generateReward(Challenge challenge) {
final String reference = Constants.DESCRIPTIONS + "challenge.rewards.";
String items;
2024-03-11 02:44:57 +01:00
if (!challenge.getRewardItems().isEmpty()) {
StringBuilder builder = new StringBuilder();
builder.append(this.user.getTranslationOrNothing(reference + "item-title"));
2024-03-11 02:44:57 +01:00
Utils.groupEqualItems(challenge.getRewardItems(), challenge.getIgnoreRewardMetaData()).stream()
.sorted(Comparator.comparing(ItemStack::getType)).forEach(itemStack -> {
builder.append("\n");
if (itemStack.getAmount() > 1) {
builder.append(this.user.getTranslationOrNothing(reference + "items-value", "[number]",
String.valueOf(itemStack.getAmount()), "[item]",
Utils.prettifyObject(itemStack, this.user)));
} else {
builder.append(this.user.getTranslationOrNothing(reference + "item-value", "[item]",
Utils.prettifyObject(itemStack, this.user)));
}
});
items = builder.toString();
2024-03-11 02:44:57 +01:00
} else {
items = "";
}
2024-03-11 02:44:57 +01:00
String experience = challenge.getRewardExperience() <= 0 ? ""
: this.user.getTranslationOrNothing(reference + "experience", "[number]",
String.valueOf(challenge.getRewardExperience()));
2024-03-11 02:44:57 +01:00
String money = !this.addon.isEconomyProvided() || challenge.getRewardMoney() <= 0 ? ""
: this.user.getTranslationOrNothing(reference + "money", "[number]",
addon.getPlugin().getVault().map(v -> v.format(challenge.getRewardMoney()))
.orElse(String.valueOf(challenge.getRewardMoney())));
String commands;
2024-03-11 02:44:57 +01:00
if (!challenge.getRewardCommands().isEmpty()) {
StringBuilder permissionBuilder = new StringBuilder();
2024-03-11 02:44:57 +01:00
if (!challenge.getRewardCommands().isEmpty()) {
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "commands-title"));
2024-03-11 02:44:57 +01:00
challenge.getRewardCommands().forEach(command -> {
permissionBuilder.append("\n");
2024-03-11 02:44:57 +01:00
permissionBuilder
.append(this.user.getTranslationOrNothing(reference + "command", "[command]", command));
});
}
commands = permissionBuilder.toString();
2024-03-11 02:44:57 +01:00
} else {
commands = "";
}
2024-03-11 02:44:57 +01:00
if (challenge.getRewardText().isEmpty() && items.isEmpty() && experience.isEmpty() && money.isEmpty()
&& commands.isEmpty()) {
// If everything is empty, do not return anything.
return "";
}
2024-03-11 02:44:57 +01:00
String rewardText = this.user
.getTranslationOrNothing("challenges.challenges." + challenge.getUniqueId() + ".reward-text");
2024-03-11 02:44:57 +01:00
if (rewardText.isEmpty()) {
rewardText = Util.translateColorCodes(String.join("\n", challenge.getRewardText()));
}
2024-03-11 02:44:57 +01:00
return this.user.getTranslationOrNothing(reference + "lore", "[text]", rewardText, "[items]", items,
"[experience]", experience, "[money]", money, "[commands]", commands);
}
/**
* This method generates level description string.
*
* @param level Level which string must be generated.
* @return List with generated description.
*/
protected List<String> generateLevelDescription(ChallengeLevel level) {
final String reference = Constants.DESCRIPTIONS + "level.";
2024-03-11 02:44:57 +01:00
// Non-memory optimal code used for easier debugging and nicer code layout for
// my eye :)
// Get status in single string
String status = "";
// Get requirements in single string
2024-03-11 02:44:57 +01:00
String waiver = this.manager.isLastLevel(level, this.world) ? ""
: this.user.getTranslationOrNothing(reference + "waiver", "[number]",
String.valueOf(level.getWaiverAmount()));
// Get rewards in single string
String rewards = this.generateReward(level);
2024-03-11 02:44:57 +01:00
String returnString = this.user.getTranslation(reference + "lore", "[text]",
Util.translateColorCodes(level.getUnlockMessage()), "[waiver]", waiver, "[rewards]", rewards,
"[status]", status);
// Remove empty lines and returns as a list.
2024-03-11 02:44:57 +01:00
return Arrays.stream(returnString.replaceAll("(?m)^[ \\t]*\\r?\\n", "").split("\n"))
.collect(Collectors.toList());
}
/**
* This method generates level description string.
*
* @param levelStatus Level which string must be generated.
* @param user User who calls generation.
* @return List with generated description.
*/
protected List<String> generateLevelDescription(LevelStatus levelStatus, User user) {
ChallengeLevel level = levelStatus.getLevel();
final String reference = Constants.DESCRIPTIONS + "level.";
2024-03-11 02:44:57 +01:00
// Non-memory optimal code used for easier debugging and nicer code layout for
// my eye :)
// Get status in single string
String status = this.generateLevelStatus(levelStatus);
// Get requirements in single string
2024-03-11 02:44:57 +01:00
String waiver = this.manager.isLastLevel(level, this.world) || !levelStatus.isUnlocked()
|| levelStatus.isComplete() ? ""
: this.user.getTranslationOrNothing(reference + "waiver", "[number]",
String.valueOf(level.getWaiverAmount()));
// Get rewards in single string
String rewards = !levelStatus.isUnlocked() ? "" : this.generateReward(level);
2024-03-11 02:44:57 +01:00
String description = this.user
.getTranslationOrNothing("challenges.levels." + level.getUniqueId() + ".description");
2024-03-11 02:44:57 +01:00
if (description.isEmpty()) {
description = Util.translateColorCodes(String.join("\n", level.getUnlockMessage()));
}
2024-03-11 02:44:57 +01:00
String returnString = this.user.getTranslation(reference + "lore", "[text]", description, "[waiver]", waiver,
"[rewards]", rewards, "[status]", status);
// Remove empty lines and returns as a list.
2024-03-11 02:44:57 +01:00
return Arrays.stream(returnString.replaceAll("(?m)^[ \\t]*\\r?\\n", "").split("\n"))
.collect(Collectors.toList());
}
/**
* This method generates level status description.
*
* @param levelStatus Level status which description must be generated.
* @return Level status text.
*/
private String generateLevelStatus(LevelStatus levelStatus) {
final String reference = Constants.DESCRIPTIONS + "level.status.";
2024-03-11 02:44:57 +01:00
if (!levelStatus.isUnlocked()) {
return this.user.getTranslationOrNothing(reference + "locked") + "\n"
+ this.user.getTranslationOrNothing(reference + "missing-challenges", "[number]",
String.valueOf(levelStatus.getNumberOfChallengesStillToDo()));
} else if (levelStatus.isComplete()) {
return this.user.getTranslationOrNothing(reference + "completed");
2024-03-11 02:44:57 +01:00
} else {
ChallengeLevel level = levelStatus.getLevel();
Release 1.2.0 (#317) * Init 1.2.0 version * Fixes #311 localization errors in zn-CN. Original translation author translated `[]` placeholders which broke locale * Init 1.2.0 version * Edit some unfit translation (#312) Edit some unfit translation * Fixes a regex bug that replaced every [player] char instead of whole word. * Fixes a crash that prevented STATISTICS entity and material/item challenges to be completed. * Add requirement-not-met-material and requirement-not-met-entity to display statistic required item on error. * Add locale of Chinese-Hong Kong (zh-HK) (#313) Addition of locale updated to latest version * Add ${argLine} to get jacoco coverage * Updated Jacoco POM section * Update build.yml Java 17 for Surefire * Updated pladdon annotations * Add support for gamemode-specific translations. This was a request from Floris * Update ChallengesManagerTest methods with world parameter. * 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 * Create plugin.yml (#316) * Create plugin.yml * Update pom.xml * Update ChallengesPladdon.java * Remove dependency to org.apache.commons Replace org.apache.commons.lang.ArrayUtils to a default Java implementation. --------- Co-authored-by: EpicMo <1982742309@qq.com> Co-authored-by: JamesMCL44 <epicquarters@gmail.com> Co-authored-by: tastybento <tastybento@users.noreply.github.com> Co-authored-by: tastybento <tastybento@wasteofplastic.com>
2023-04-15 21:55:34 +02:00
List<Challenge> challengeList = this.addon.getChallengesManager().getLevelChallenges(level);
// Check if unlock message should appear.
2024-03-11 02:44:57 +01:00
int doneChallenges = (int) challengeList.stream().filter(challenge -> this.addon.getChallengesManager()
.isChallengeComplete(user.getUniqueId(), world, challenge)).count();
return this.user.getTranslation(reference + "completed-challenges-of", "[number]",
String.valueOf(doneChallenges), "[max]", String.valueOf(challengeList.size()));
}
}
/**
* This method creates reward lore text.
*
* @param level ChallengeLevel which reward lore must be generated.
* @return Reward text.
*/
private String generateReward(ChallengeLevel level) {
final String reference = Constants.DESCRIPTIONS + "level.rewards.";
String items;
2024-03-11 02:44:57 +01:00
if (!level.getRewardItems().isEmpty()) {
StringBuilder builder = new StringBuilder();
builder.append(this.user.getTranslationOrNothing(reference + "item-title"));
2024-03-11 02:44:57 +01:00
Utils.groupEqualItems(level.getRewardItems(), level.getIgnoreRewardMetaData()).stream()
.sorted(Comparator.comparing(ItemStack::getType)).forEach(itemStack -> {
builder.append("\n");
if (itemStack.getAmount() > 1) {
builder.append(this.user.getTranslationOrNothing(reference + "items-value", "[number]",
String.valueOf(itemStack.getAmount()), "[item]",
Utils.prettifyObject(itemStack, this.user)));
} else {
builder.append(this.user.getTranslationOrNothing(reference + "item-value", "[item]",
Utils.prettifyObject(itemStack, this.user)));
}
});
items = builder.toString();
2024-03-11 02:44:57 +01:00
} else {
items = "";
}
2024-03-11 02:44:57 +01:00
String experience = level.getRewardExperience() <= 0 ? ""
: this.user.getTranslationOrNothing(reference + "experience", "[number]",
String.valueOf(level.getRewardExperience()));
2024-03-11 02:44:57 +01:00
String money = !this.addon.isEconomyProvided() || level.getRewardMoney() <= 0 ? ""
: this.user.getTranslationOrNothing(reference + "money", "[number]",
String.valueOf(level.getRewardMoney()));
String commands;
2024-03-11 02:44:57 +01:00
if (!level.getRewardCommands().isEmpty()) {
StringBuilder permissionBuilder = new StringBuilder();
2024-03-11 02:44:57 +01:00
if (!level.getRewardCommands().isEmpty()) {
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "commands-title"));
2024-03-11 02:44:57 +01:00
level.getRewardCommands().forEach(command -> {
permissionBuilder.append("\n");
2024-03-11 02:44:57 +01:00
permissionBuilder
.append(this.user.getTranslationOrNothing(reference + "command", "[command]", command));
});
}
commands = permissionBuilder.toString();
2024-03-11 02:44:57 +01:00
} else {
commands = "";
}
2024-03-11 02:44:57 +01:00
if (level.getRewardText().isEmpty() && items.isEmpty() && experience.isEmpty() && money.isEmpty()
&& commands.isEmpty()) {
// If everything is empty, do not return anything.
return "";
}
2024-03-11 02:44:57 +01:00
String rewardText = this.user
.getTranslationOrNothing("challenges.levels." + level.getUniqueId() + ".reward-text");
2024-03-11 02:44:57 +01:00
if (rewardText.isEmpty()) {
rewardText = Util.translateColorCodes(String.join("\n", level.getRewardText()));
}
2024-03-11 02:44:57 +01:00
return this.user.getTranslationOrNothing(reference + "lore", "[text]", rewardText, "[items]", items,
"[experience]", experience, "[money]", money, "[commands]", commands);
}
2024-03-11 02:44:57 +01:00
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* This variable stores parent gui.
*/
@Nullable
protected final CommonPanel parentPanel;
/**
* Variable stores Challenges addon.
*/
protected final ChallengesAddon addon;
/**
* Variable stores Challenges addon manager.
*/
protected final ChallengesManager manager;
/**
* Variable stores world in which panel is referred to.
*/
protected final World world;
/**
* Variable stores user who created this panel.
*/
protected final User user;
/**
* Variable stores top label of command from which panel was called.
*/
protected final String topLabel;
/**
* Variable stores permission prefix of command from which panel was called.
*/
protected final String permissionPrefix;
/**
* This object holds PanelItem that allows to return to previous panel.
*/
protected PanelItem returnButton;
}