mirror of
https://github.com/BentoBoxWorld/Challenges.git
synced 2024-12-31 21:48:00 +01:00
Implement customizable user panels.
Server owners can customize 3 panels: - main panel - gamemode selector - multiple completions Panel functions will be explained in docs later.
This commit is contained in:
parent
3bb0a30657
commit
09a30f00db
957
src/main/java/world/bentobox/challenges/panel/CommonPanel.java
Normal file
957
src/main/java/world/bentobox/challenges/panel/CommonPanel.java
Normal file
@ -0,0 +1,957 @@
|
||||
//
|
||||
// Created by BONNe
|
||||
// Copyright - 2021
|
||||
//
|
||||
|
||||
|
||||
package world.bentobox.challenges.panel;
|
||||
|
||||
|
||||
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 java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.*;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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();
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 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.
|
||||
final boolean isCompletedOnce = target != null &&
|
||||
this.manager.isChallengeComplete(target.getUniqueId(), this.world, challenge);
|
||||
|
||||
final long doneTimes = target != null && challenge.isRepeatable() ?
|
||||
this.manager.getChallengeTimes(target, this.world, challenge) : (isCompletedOnce ? 0 : 1);
|
||||
|
||||
boolean isCompletedAll = isCompletedOnce &&
|
||||
(!challenge.isRepeatable() ||
|
||||
challenge.getMaxTimes() > 0 && doneTimes >= challenge.getMaxTimes());
|
||||
|
||||
final String reference = Constants.DESCRIPTIONS + "challenge.";
|
||||
|
||||
// Get description in single string
|
||||
String description = Util.translateColorCodes(String.join("\n",
|
||||
challenge.getDescription()));
|
||||
// Non-memory optimal code used for easier debugging and nicer code layout for my eye :)
|
||||
// Get status in single string
|
||||
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);
|
||||
|
||||
if (!description.replaceAll("(?m)^[ \\t]*\\r?\\n", "").isEmpty())
|
||||
{
|
||||
String returnString = this.user.getTranslationOrNothing(reference + "lore",
|
||||
Constants.REQUIREMENTS, requirements,
|
||||
Constants.REWARDS, rewards,
|
||||
Constants.STATUS, status);
|
||||
|
||||
// remove empty lines from the generated text.
|
||||
List<String> collect =
|
||||
Arrays.stream(returnString.replaceAll("(?m)^[ \\t]*\\r?\\n", "").
|
||||
split("\n")).
|
||||
collect(Collectors.toList());
|
||||
|
||||
// find and replace description from collected blocks.
|
||||
|
||||
for (int i = 0; i < collect.size(); i++)
|
||||
{
|
||||
if (collect.get(i).contains(Constants.DESCRIPTION))
|
||||
{
|
||||
collect.set(i, collect.get(i).replace(Constants.DESCRIPTION, description));
|
||||
}
|
||||
}
|
||||
|
||||
return collect;
|
||||
}
|
||||
else
|
||||
{
|
||||
String returnString = this.user.getTranslationOrNothing(reference + "lore",
|
||||
Constants.DESCRIPTION, description,
|
||||
Constants.REQUIREMENTS, requirements,
|
||||
Constants.REWARDS, rewards,
|
||||
Constants.STATUS, status);
|
||||
|
||||
// Remove empty lines and returns as a list.
|
||||
|
||||
return Arrays.stream(returnString.replaceAll("(?m)^[ \\t]*\\r?\\n", "").
|
||||
split("\n")).
|
||||
collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
if (challenge.getEnvironment().isEmpty() || challenge.getEnvironment().size() == 3)
|
||||
{
|
||||
// If challenge can be completed everywhere, do not display requirement.
|
||||
environment = "";
|
||||
}
|
||||
else if (challenge.getEnvironment().size() == 1)
|
||||
{
|
||||
environment = this.user.getTranslationOrNothing(reference + "environment-single",
|
||||
Constants.ENVIRONMENT,
|
||||
Utils.prettifyObject(challenge.getEnvironment().iterator().next(), this.user));
|
||||
}
|
||||
else
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "environment-title"));
|
||||
challenge.getEnvironment().stream().sorted().forEach(en ->
|
||||
{
|
||||
builder.append("\n");
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "environment-single",
|
||||
Constants.ENVIRONMENT,
|
||||
Utils.prettifyObject(en, this.user)));
|
||||
});
|
||||
|
||||
environment = builder.toString();
|
||||
}
|
||||
|
||||
String permissions;
|
||||
|
||||
if (!challenge.getRequirements().getRequiredPermissions().isEmpty())
|
||||
{
|
||||
// Yes list duplication for complete menu.
|
||||
List<String> missingPermissions = challenge.getRequirements().getRequiredPermissions().stream().
|
||||
filter(permission -> target == null || !target.hasPermission(permission)).
|
||||
sorted().
|
||||
collect(Collectors.toList());
|
||||
|
||||
StringBuilder permissionBuilder = new StringBuilder();
|
||||
|
||||
if (missingPermissions.size() == 1)
|
||||
{
|
||||
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "permission-single",
|
||||
Constants.PERMISSION, missingPermissions.get(0)));
|
||||
}
|
||||
else if (!missingPermissions.isEmpty())
|
||||
{
|
||||
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "permissions-title"));
|
||||
missingPermissions.forEach(permission ->
|
||||
{
|
||||
permissionBuilder.append("\n");
|
||||
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "permissions-list",
|
||||
Constants.PERMISSION, permission));
|
||||
});
|
||||
}
|
||||
|
||||
permissions = permissionBuilder.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
permissions = "";
|
||||
}
|
||||
|
||||
String typeRequirement = switch (challenge.getChallengeType()) {
|
||||
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());
|
||||
};
|
||||
|
||||
return this.user.getTranslationOrNothing(reference + "lore",
|
||||
Constants.ENVIRONMENT, environment,
|
||||
Constants.TYPE_REQUIREMENT, typeRequirement,
|
||||
Constants.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;
|
||||
|
||||
if (!requirement.getRequiredBlocks().isEmpty())
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "blocks-title"));
|
||||
requirement.getRequiredBlocks().entrySet().stream().
|
||||
sorted(Map.Entry.comparingByKey()).
|
||||
forEach(entry ->
|
||||
{
|
||||
builder.append("\n");
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "blocks-value",
|
||||
Constants.NUMBER, String.valueOf(entry.getValue()),
|
||||
Constants.MATERIAL, Utils.prettifyObject(entry.getKey(), this.user)));
|
||||
});
|
||||
|
||||
blocks = builder.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
blocks = "";
|
||||
}
|
||||
|
||||
String entities;
|
||||
|
||||
if (!requirement.getRequiredEntities().isEmpty())
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "entities-title"));
|
||||
requirement.getRequiredEntities().entrySet().stream().
|
||||
sorted(Map.Entry.comparingByKey()).
|
||||
forEach(entry ->
|
||||
{
|
||||
builder.append("\n");
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "entities-value",
|
||||
Constants.NUMBER, String.valueOf(entry.getValue()),
|
||||
Constants.ENTITY, Utils.prettifyObject(entry.getKey(), this.user)));
|
||||
});
|
||||
|
||||
entities = builder.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
entities = "";
|
||||
}
|
||||
|
||||
String searchRadius = this.user.getTranslationOrNothing(reference + "search-radius",
|
||||
Constants.NUMBER, String.valueOf(requirement.getSearchRadius()));
|
||||
|
||||
String warningBlocks = requirement.isRemoveBlocks() ?
|
||||
this.user.getTranslationOrNothing(reference + "warning-block") : "";
|
||||
String warningEntities = requirement.isRemoveEntities() ?
|
||||
this.user.getTranslationOrNothing(reference + "warning-entity") : "";
|
||||
|
||||
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;
|
||||
|
||||
if (!requirement.getRequiredItems().isEmpty())
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "item-title"));
|
||||
Utils.groupEqualItems(requirement.getRequiredItems()).stream().
|
||||
sorted(Comparator.comparing(ItemStack::getType)).
|
||||
forEach(itemStack ->
|
||||
{
|
||||
builder.append("\n");
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "item-list",
|
||||
"[item]", Utils.prettifyObject(itemStack, this.user)));
|
||||
});
|
||||
|
||||
items = builder.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
items = "";
|
||||
}
|
||||
|
||||
String warning = requirement.isTakeItems() ?
|
||||
this.user.getTranslationOrNothing(reference + "warning") : "";
|
||||
|
||||
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.";
|
||||
|
||||
String experience = requirement.getRequiredExperience() <= 0 ? "" :
|
||||
this.user.getTranslationOrNothing(reference + "experience",
|
||||
"[number]", String.valueOf(requirement.getRequiredExperience()));
|
||||
|
||||
String experienceWarning = requirement.getRequiredExperience() > 0 && requirement.isTakeExperience() ?
|
||||
this.user.getTranslationOrNothing(reference + "experience-warning") : "";
|
||||
|
||||
String money = !this.addon.isEconomyProvided() || requirement.getRequiredMoney() <= 0 ? "" :
|
||||
this.user.getTranslationOrNothing(reference + "money",
|
||||
"[number]", String.valueOf(requirement.getRequiredMoney()));
|
||||
|
||||
String moneyWarning = this.addon.isEconomyProvided() &&
|
||||
requirement.getRequiredMoney() > 0 &&
|
||||
requirement.isTakeMoney() ?
|
||||
this.user.getTranslationOrNothing(reference + "money-warning") : "";
|
||||
|
||||
String level = !this.addon.isLevelProvided() || requirement.getRequiredIslandLevel() <= 0 ? "" :
|
||||
this.user.getTranslationOrNothing(reference,
|
||||
"[number]", String.valueOf(requirement.getRequiredIslandLevel()));
|
||||
|
||||
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;
|
||||
|
||||
if (requirement.getStatistic() == null)
|
||||
{
|
||||
// Challenges by default comes with empty statistic field.
|
||||
return "";
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
default -> {
|
||||
statistic = "";
|
||||
}
|
||||
}
|
||||
|
||||
String warning = requirement.isReduceStatistic() ?
|
||||
this.user.getTranslationOrNothing(reference + "warning") : "";
|
||||
|
||||
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,
|
||||
int maxCompletions)
|
||||
{
|
||||
final String reference = Constants.DESCRIPTIONS + "challenge.status.";
|
||||
|
||||
if (completedAll)
|
||||
{
|
||||
if (maxCompletions > 1)
|
||||
{
|
||||
return this.user.getTranslationOrNothing(reference + "completed-times-reached",
|
||||
Constants.MAX, String.valueOf(maxCompletions));
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.user.getTranslationOrNothing(reference + "completed");
|
||||
}
|
||||
}
|
||||
else if (completedOnce)
|
||||
{
|
||||
if (maxCompletions > 0)
|
||||
{
|
||||
return this.user.getTranslationOrNothing(reference + "completed-times-of",
|
||||
Constants.MAX, String.valueOf(maxCompletions),
|
||||
Constants.NUMBER, String.valueOf(completionCount));
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.user.getTranslationOrNothing(reference + "completed-times",
|
||||
Constants.NUMBER, String.valueOf(completionCount));
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (isRepeating)
|
||||
{
|
||||
return this.generateRepeatReward(challenge);
|
||||
}
|
||||
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;
|
||||
|
||||
if (!challenge.getRepeatItemReward().isEmpty())
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "item-title"));
|
||||
Utils.groupEqualItems(challenge.getRepeatItemReward()).stream().
|
||||
sorted(Comparator.comparing(ItemStack::getType)).
|
||||
forEach(itemStack ->
|
||||
{
|
||||
builder.append("\n");
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "item-list",
|
||||
"[item]", Utils.prettifyObject(itemStack, this.user)));
|
||||
});
|
||||
|
||||
items = builder.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
items = "";
|
||||
}
|
||||
|
||||
String experience = challenge.getRepeatExperienceReward() <= 0 ? "" :
|
||||
this.user.getTranslationOrNothing(reference + "experience",
|
||||
"[number]", String.valueOf(challenge.getRepeatExperienceReward()));
|
||||
|
||||
String money = !this.addon.isEconomyProvided() || challenge.getRepeatMoneyReward() <= 0 ? "" :
|
||||
this.user.getTranslationOrNothing(reference + "money",
|
||||
"[number]", String.valueOf(challenge.getRepeatMoneyReward()));
|
||||
|
||||
String commands;
|
||||
|
||||
if (!challenge.getRepeatRewardCommands().isEmpty())
|
||||
{
|
||||
StringBuilder permissionBuilder = new StringBuilder();
|
||||
|
||||
if (!challenge.getRepeatRewardCommands().isEmpty())
|
||||
{
|
||||
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "commands-title"));
|
||||
|
||||
challenge.getRepeatRewardCommands().forEach(command ->
|
||||
{
|
||||
permissionBuilder.append("\n");
|
||||
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "command",
|
||||
"[command]", command));
|
||||
});
|
||||
}
|
||||
|
||||
commands = permissionBuilder.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
commands = "";
|
||||
}
|
||||
|
||||
if (challenge.getRepeatRewardText().isEmpty() &&
|
||||
items.isEmpty() &&
|
||||
experience.isEmpty() &&
|
||||
money.isEmpty() &&
|
||||
commands.isEmpty())
|
||||
{
|
||||
// If everything is empty, do not return anything.
|
||||
return "";
|
||||
}
|
||||
|
||||
return this.user.getTranslationOrNothing(reference + "lore",
|
||||
"[text]", Util.translateColorCodes(String.join("\n", challenge.getRepeatRewardText())),
|
||||
"[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;
|
||||
|
||||
if (!challenge.getRewardItems().isEmpty())
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "item-title"));
|
||||
Utils.groupEqualItems(challenge.getRewardItems()).stream().
|
||||
sorted(Comparator.comparing(ItemStack::getType)).
|
||||
forEach(itemStack ->
|
||||
{
|
||||
builder.append("\n");
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "item-list",
|
||||
"[item]", Utils.prettifyObject(itemStack, this.user)));
|
||||
});
|
||||
|
||||
items = builder.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
items = "";
|
||||
}
|
||||
|
||||
String experience = challenge.getRewardExperience() <= 0 ? "" :
|
||||
this.user.getTranslationOrNothing(reference + "experience",
|
||||
"[number]", String.valueOf(challenge.getRewardExperience()));
|
||||
|
||||
String money = !this.addon.isEconomyProvided() || challenge.getRewardMoney() <= 0 ? "" :
|
||||
this.user.getTranslationOrNothing(reference + "money",
|
||||
"[number]", String.valueOf(challenge.getRewardMoney()));
|
||||
|
||||
String commands;
|
||||
|
||||
if (!challenge.getRewardCommands().isEmpty())
|
||||
{
|
||||
StringBuilder permissionBuilder = new StringBuilder();
|
||||
|
||||
if (!challenge.getRewardCommands().isEmpty())
|
||||
{
|
||||
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "commands-title"));
|
||||
|
||||
challenge.getRewardCommands().forEach(command ->
|
||||
{
|
||||
permissionBuilder.append("\n");
|
||||
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "command",
|
||||
"[command]", command));
|
||||
});
|
||||
}
|
||||
|
||||
commands = permissionBuilder.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
commands = "";
|
||||
}
|
||||
|
||||
if (challenge.getRewardText().isEmpty() &&
|
||||
items.isEmpty() &&
|
||||
experience.isEmpty() &&
|
||||
money.isEmpty() &&
|
||||
commands.isEmpty())
|
||||
{
|
||||
// If everything is empty, do not return anything.
|
||||
return "";
|
||||
}
|
||||
|
||||
return this.user.getTranslationOrNothing(reference + "lore",
|
||||
"[text]", Util.translateColorCodes(String.join("\n", challenge.getRewardText())),
|
||||
"[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.";
|
||||
|
||||
// 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
|
||||
String waiver = this.user.getTranslationOrNothing(reference + "waiver",
|
||||
"[number]", String.valueOf(level.getWaiverAmount()));
|
||||
// Get rewards in single string
|
||||
String rewards = this.generateReward(level);
|
||||
|
||||
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.
|
||||
|
||||
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.";
|
||||
|
||||
// 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
|
||||
String waiver = !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);
|
||||
|
||||
String returnString = this.user.getTranslation(reference + "lore",
|
||||
"[text]", Util.translateColorCodes(levelStatus.getLevel().getUnlockMessage()),
|
||||
"[waiver]", waiver,
|
||||
"[rewards]", rewards,
|
||||
"[status]", status);
|
||||
|
||||
// Remove empty lines and returns as a list.
|
||||
|
||||
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.";
|
||||
|
||||
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");
|
||||
}
|
||||
else
|
||||
{
|
||||
ChallengeLevel level = levelStatus.getLevel();
|
||||
// Check if unlock message should appear.
|
||||
int doneChallenges = (int) level.getChallenges().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(level.getChallenges().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;
|
||||
|
||||
if (!level.getRewardItems().isEmpty())
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "item-title"));
|
||||
Utils.groupEqualItems(level.getRewardItems()).stream().
|
||||
sorted(Comparator.comparing(ItemStack::getType)).
|
||||
forEach(itemStack ->
|
||||
{
|
||||
builder.append("\n");
|
||||
builder.append(this.user.getTranslationOrNothing(reference + "item-list",
|
||||
"[item]", Utils.prettifyObject(itemStack, this.user)));
|
||||
});
|
||||
|
||||
items = builder.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
items = "";
|
||||
}
|
||||
|
||||
String experience = level.getRewardExperience() <= 0 ? "" :
|
||||
this.user.getTranslationOrNothing(reference + "experience",
|
||||
"[number]", String.valueOf(level.getRewardExperience()));
|
||||
|
||||
String money = !this.addon.isEconomyProvided() || level.getRewardMoney() <= 0 ? "" :
|
||||
this.user.getTranslationOrNothing(reference + "money",
|
||||
"[number]", String.valueOf(level.getRewardMoney()));
|
||||
|
||||
String commands;
|
||||
|
||||
if (!level.getRewardCommands().isEmpty())
|
||||
{
|
||||
StringBuilder permissionBuilder = new StringBuilder();
|
||||
|
||||
if (!level.getRewardCommands().isEmpty())
|
||||
{
|
||||
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "commands-title"));
|
||||
|
||||
level.getRewardCommands().forEach(command ->
|
||||
{
|
||||
permissionBuilder.append("\n");
|
||||
permissionBuilder.append(this.user.getTranslationOrNothing(reference + "command",
|
||||
"[command]", command));
|
||||
});
|
||||
}
|
||||
|
||||
commands = permissionBuilder.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
commands = "";
|
||||
}
|
||||
|
||||
if (level.getRewardText().isEmpty() &&
|
||||
items.isEmpty() &&
|
||||
experience.isEmpty() &&
|
||||
money.isEmpty() &&
|
||||
commands.isEmpty())
|
||||
{
|
||||
// If everything is empty, do not return anything.
|
||||
return "";
|
||||
}
|
||||
|
||||
return this.user.getTranslationOrNothing(reference + "lore",
|
||||
"[text]", Util.translateColorCodes(String.join("\n", level.getRewardText())),
|
||||
"[items]", items,
|
||||
"[experience]", experience,
|
||||
"[money]", money,
|
||||
"[commands]", commands);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
@ -0,0 +1,751 @@
|
||||
//
|
||||
// Created by BONNe
|
||||
// Copyright - 2021
|
||||
//
|
||||
|
||||
|
||||
package world.bentobox.challenges.panel.user;
|
||||
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import world.bentobox.bentobox.api.panels.PanelItem;
|
||||
import world.bentobox.bentobox.api.panels.TemplatedPanel;
|
||||
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
|
||||
import world.bentobox.bentobox.api.panels.builders.TemplatedPanelBuilder;
|
||||
import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
import world.bentobox.challenges.ChallengesAddon;
|
||||
import world.bentobox.challenges.config.SettingsUtils;
|
||||
import world.bentobox.challenges.database.object.Challenge;
|
||||
import world.bentobox.challenges.panel.CommonPanel;
|
||||
import world.bentobox.challenges.tasks.TryToComplete;
|
||||
import world.bentobox.challenges.utils.Constants;
|
||||
import world.bentobox.challenges.utils.LevelStatus;
|
||||
|
||||
|
||||
/**
|
||||
* Main challenges panel builder.
|
||||
*/
|
||||
public class ChallengesPanel extends CommonPanel
|
||||
{
|
||||
private ChallengesPanel(ChallengesAddon addon,
|
||||
World world,
|
||||
User user,
|
||||
String topLabel,
|
||||
String permissionPrefix)
|
||||
{
|
||||
super(addon, user, world, topLabel, permissionPrefix);
|
||||
this.updateLevelList();
|
||||
this.containsChallenges = this.manager.hasAnyChallengeData(this.world);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open the Challenges GUI.
|
||||
*
|
||||
* @param addon the addon
|
||||
* @param world the world
|
||||
* @param user the user
|
||||
* @param topLabel the top label
|
||||
* @param permissionPrefix the permission prefix
|
||||
*/
|
||||
public static void open(ChallengesAddon addon,
|
||||
World world,
|
||||
User user,
|
||||
String topLabel,
|
||||
String permissionPrefix)
|
||||
{
|
||||
new ChallengesPanel(addon, world, user, topLabel, permissionPrefix).build();
|
||||
}
|
||||
|
||||
|
||||
protected void build()
|
||||
{
|
||||
// Do not open gui if there is no challenges.
|
||||
if (!this.containsChallenges)
|
||||
{
|
||||
this.addon.logError("There are no challenges set up!");
|
||||
this.user.sendMessage(Constants.ERRORS + "no-challenges");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create lists for builder.
|
||||
this.updateFreeChallengeList();
|
||||
this.updateChallengeList();
|
||||
// this.updateLevelList();
|
||||
|
||||
// Start building panel.
|
||||
TemplatedPanelBuilder panelBuilder = new TemplatedPanelBuilder();
|
||||
|
||||
// Set main template.
|
||||
panelBuilder.template("main_panel", new File(this.addon.getDataFolder(), "panels"));
|
||||
panelBuilder.user(this.user);
|
||||
panelBuilder.world(this.user.getWorld());
|
||||
|
||||
// Register button builders
|
||||
panelBuilder.registerTypeBuilder("CHALLENGE", this::createChallengeButton);
|
||||
panelBuilder.registerTypeBuilder("LEVEL", this::createLevelButton);
|
||||
|
||||
panelBuilder.registerTypeBuilder("UNASSIGNED_CHALLENGES", this::createFreeChallengesButton);
|
||||
|
||||
panelBuilder.registerTypeBuilder("NEXT", this::createNextButton);
|
||||
panelBuilder.registerTypeBuilder("PREVIOUS", this::createPreviousButton);
|
||||
|
||||
// Register unknown type builder.
|
||||
panelBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
private void updateFreeChallengeList()
|
||||
{
|
||||
this.freeChallengeList = this.manager.getFreeChallenges(this.world);
|
||||
|
||||
if (this.addon.getChallengesSettings().isRemoveCompleteOneTimeChallenges())
|
||||
{
|
||||
this.freeChallengeList.removeIf(challenge -> !challenge.isRepeatable() &&
|
||||
this.manager.isChallengeComplete(this.user, this.world, challenge));
|
||||
}
|
||||
|
||||
// Remove all undeployed challenges if VisibilityMode is set to Hidden.
|
||||
if (this.addon.getChallengesSettings().getVisibilityMode().equals(SettingsUtils.VisibilityMode.HIDDEN))
|
||||
{
|
||||
this.freeChallengeList.removeIf(challenge -> !challenge.isDeployed());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void updateChallengeList()
|
||||
{
|
||||
if (this.lastSelectedLevel != null)
|
||||
{
|
||||
this.challengeList = this.manager.getLevelChallenges(this.lastSelectedLevel.getLevel());
|
||||
|
||||
if (this.addon.getChallengesSettings().isRemoveCompleteOneTimeChallenges())
|
||||
{
|
||||
this.challengeList.removeIf(challenge -> !challenge.isRepeatable() &&
|
||||
this.manager.isChallengeComplete(this.user, this.world, challenge));
|
||||
}
|
||||
|
||||
// Remove all undeployed challenges if VisibilityMode is set to Hidden.
|
||||
if (this.addon.getChallengesSettings().getVisibilityMode().equals(SettingsUtils.VisibilityMode.HIDDEN))
|
||||
{
|
||||
this.challengeList.removeIf(challenge -> !challenge.isDeployed());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.challengeList = this.freeChallengeList;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void updateLevelList()
|
||||
{
|
||||
this.levelList = this.manager.getAllChallengeLevelStatus(this.user, this.world);
|
||||
|
||||
for (LevelStatus levelStatus : this.levelList)
|
||||
{
|
||||
if (levelStatus.isUnlocked())
|
||||
{
|
||||
this.lastSelectedLevel = levelStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private PanelItem createChallengeButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
if (this.challengeList.isEmpty())
|
||||
{
|
||||
// Does not contain any free challenges.
|
||||
return null;
|
||||
}
|
||||
|
||||
Challenge levelChallenge;
|
||||
|
||||
// Check if that is a specific free challenge
|
||||
if (template.dataMap().containsKey("id"))
|
||||
{
|
||||
String id = (String) template.dataMap().get("id");
|
||||
|
||||
// Find a challenge with given Id;
|
||||
levelChallenge = this.challengeList.stream().
|
||||
filter(challenge -> challenge.getUniqueId().equals(id)).
|
||||
findFirst().
|
||||
orElse(null);
|
||||
|
||||
if (levelChallenge == null)
|
||||
{
|
||||
// There is no challenge in the list with specific id.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = this.challengeIndex * slot.amountMap().getOrDefault("CHALLENGE", 1) + slot.slot();
|
||||
|
||||
if (index >= this.challengeList.size())
|
||||
{
|
||||
// Out of index.
|
||||
return null;
|
||||
}
|
||||
|
||||
levelChallenge = this.challengeList.get(index);
|
||||
}
|
||||
|
||||
return this.createChallengeButton(template, levelChallenge);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
private PanelItem createChallengeButton(ItemTemplateRecord template, @NonNull Challenge challenge)
|
||||
{
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
// Template specification are always more important than dynamic content.
|
||||
builder.icon(template.icon() != null ? template.icon().clone() : challenge.getIcon());
|
||||
|
||||
// Template specific title is always more important than challenge name.
|
||||
if (template.title() != null && !template.title().isBlank())
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.world, template.title(),
|
||||
Constants.CHALLENGE, challenge.getFriendlyName()));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.name(Util.translateColorCodes(challenge.getFriendlyName()));
|
||||
}
|
||||
|
||||
if (template.description() != null && !template.description().isBlank())
|
||||
{
|
||||
// TODO: adding parameters could be useful.
|
||||
builder.description(this.user.getTranslation(this.world, template.description()));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.description(this.generateChallengeDescription(challenge, this.user));
|
||||
}
|
||||
|
||||
// Add Click handler
|
||||
builder.clickHandler((panel, user, clickType, i) -> {
|
||||
for (ItemTemplateRecord.ActionRecords action : template.actions())
|
||||
{
|
||||
if (clickType == action.clickType())
|
||||
{
|
||||
switch (action.actionType().toUpperCase())
|
||||
{
|
||||
case "COMPLETE":
|
||||
if (TryToComplete.complete(this.addon,
|
||||
this.user,
|
||||
challenge,
|
||||
this.world,
|
||||
this.topLabel,
|
||||
this.permissionPrefix))
|
||||
{
|
||||
panel.getInventory().setItem(i,
|
||||
this.createChallengeButton(template, challenge).getItem());
|
||||
}
|
||||
break;
|
||||
case "COMPLETE_MAX":
|
||||
if (challenge.isRepeatable())
|
||||
{
|
||||
if (TryToComplete.complete(this.addon,
|
||||
this.user,
|
||||
challenge,
|
||||
this.world,
|
||||
this.topLabel,
|
||||
this.permissionPrefix,
|
||||
Integer.MAX_VALUE))
|
||||
{
|
||||
panel.getInventory().setItem(i,
|
||||
this.createChallengeButton(template, challenge).getItem());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "MULTIPLE_PANEL":
|
||||
if (challenge.isRepeatable())
|
||||
{
|
||||
MultiplePanel.open(this.addon, this.user, value ->
|
||||
{
|
||||
TryToComplete.complete(this.addon,
|
||||
this.user,
|
||||
challenge,
|
||||
this.world,
|
||||
this.topLabel,
|
||||
this.permissionPrefix,
|
||||
value);
|
||||
|
||||
this.build();
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
filter(action -> challenge.isRepeatable() || "COMPLETE".equalsIgnoreCase(action.actionType())).
|
||||
map(action -> this.user.getTranslation(this.world, action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
// Glow the icon.
|
||||
builder.glow(this.addon.getChallengesSettings().isAddCompletedGlow() &&
|
||||
this.manager.isChallengeComplete(this.user, this.world, challenge));
|
||||
|
||||
// Click Handlers are managed by custom addon buttons.
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private PanelItem createLevelButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
if (this.levelList.isEmpty())
|
||||
{
|
||||
// Does not contain any levels.
|
||||
return null;
|
||||
}
|
||||
|
||||
LevelStatus level;
|
||||
|
||||
// Check if that is a specific level
|
||||
if (template.dataMap().containsKey("id"))
|
||||
{
|
||||
String id = (String) template.dataMap().get("id");
|
||||
|
||||
// Find a challenge with given Id;
|
||||
level = this.levelList.stream().
|
||||
filter(levelStatus -> levelStatus.getLevel().getUniqueId().equals(id)).
|
||||
findFirst().
|
||||
orElse(null);
|
||||
|
||||
if (level == null)
|
||||
{
|
||||
// There is no challenge in the list with specific id.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = this.levelIndex * slot.amountMap().getOrDefault("LEVEL", 1) + slot.slot();
|
||||
|
||||
if (index >= this.levelList.size())
|
||||
{
|
||||
// Out of index.
|
||||
return null;
|
||||
}
|
||||
|
||||
level = this.levelList.get(index);
|
||||
}
|
||||
|
||||
return this.createLevelButton(template, level);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
private PanelItem createLevelButton(ItemTemplateRecord template, @NonNull LevelStatus level)
|
||||
{
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
// Template specification are always more important than dynamic content.
|
||||
if (template.icon() != null)
|
||||
{
|
||||
builder.icon(template.icon().clone());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (level.isUnlocked())
|
||||
{
|
||||
builder.icon(level.getLevel().getIcon());
|
||||
}
|
||||
else if (level.getLevel().getLockedIcon() != null)
|
||||
{
|
||||
// Clone will prevent issues with description storing.
|
||||
// It can be done only here as it can be null.
|
||||
builder.icon(level.getLevel().getLockedIcon().clone());
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.icon(this.addon.getChallengesSettings().getLockedLevelIcon());
|
||||
}
|
||||
}
|
||||
|
||||
if (template.title() != null && !template.title().isBlank())
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.world, template.title(),
|
||||
Constants.LEVEL, level.getLevel().getFriendlyName()));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.name(Util.translateColorCodes(level.getLevel().getFriendlyName()));
|
||||
}
|
||||
|
||||
if (template.description() != null && !template.description().isBlank())
|
||||
{
|
||||
// TODO: adding parameters could be useful.
|
||||
builder.description(this.user.getTranslation(this.world, template.description()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Complete description generate.
|
||||
builder.description(this.generateLevelDescription(level, this.user));
|
||||
}
|
||||
|
||||
// Add click handler
|
||||
builder.clickHandler((panel, user, clickType, i) -> {
|
||||
if (level != this.lastSelectedLevel && level.isUnlocked())
|
||||
{
|
||||
this.lastSelectedLevel = level;
|
||||
this.challengeIndex = 0;
|
||||
|
||||
this.build();
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
filter(action -> level != this.lastSelectedLevel && level.isUnlocked()).
|
||||
map(action -> this.user.getTranslation(this.world, action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
// Glow the icon.
|
||||
builder.glow(level == this.lastSelectedLevel ||
|
||||
level.isUnlocked() &&
|
||||
this.addon.getChallengesSettings().isAddCompletedGlow() &&
|
||||
this.manager.isLevelCompleted(this.user, this.world, level.getLevel()));
|
||||
|
||||
// Click Handlers are managed by custom addon buttons.
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private PanelItem createFreeChallengesButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
if (this.freeChallengeList.isEmpty())
|
||||
{
|
||||
// There are no free challenges for selection.
|
||||
return null;
|
||||
}
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
builder.icon(template.icon().clone());
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.world, template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(this.world, template.description()));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
if (this.lastSelectedLevel != null)
|
||||
{
|
||||
this.lastSelectedLevel = null;
|
||||
this.build();
|
||||
}
|
||||
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
filter(action -> this.lastSelectedLevel == null).
|
||||
map(action -> this.user.getTranslation(this.world, action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private PanelItem createNextButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
String target = template.dataMap().getOrDefault("target", "").toString().toUpperCase();
|
||||
|
||||
int nextPageIndex;
|
||||
|
||||
switch (target)
|
||||
{
|
||||
case "CHALLENGE" -> {
|
||||
int size = this.challengeList.size();
|
||||
|
||||
if (size <= slot.amountMap().getOrDefault("CHALLENGE", 1) ||
|
||||
1.0 * size / slot.amountMap().getOrDefault("CHALLENGE", 1) <= this.challengeIndex + 1)
|
||||
{
|
||||
// There are no next elements
|
||||
return null;
|
||||
}
|
||||
|
||||
nextPageIndex = this.challengeIndex + 2;
|
||||
}
|
||||
case "LEVEL" -> {
|
||||
int size = this.levelList.size();
|
||||
|
||||
if (size <= slot.amountMap().getOrDefault("LEVEL", 1) ||
|
||||
1.0 * size / slot.amountMap().getOrDefault("LEVEL", 1) <= this.levelIndex + 1)
|
||||
{
|
||||
// There are no next elements
|
||||
return null;
|
||||
}
|
||||
|
||||
nextPageIndex = this.levelIndex + 2;
|
||||
}
|
||||
default -> {
|
||||
// If not assigned to any type, return null.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
ItemStack clone = template.icon().clone();
|
||||
|
||||
if ((Boolean) template.dataMap().getOrDefault("indexing", false))
|
||||
{
|
||||
clone.setAmount(nextPageIndex);
|
||||
}
|
||||
|
||||
builder.icon(clone);
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.world, template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(this.world, template.description()),
|
||||
Constants.NUMBER, String.valueOf(nextPageIndex));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
// Next button ignores click type currently.
|
||||
switch (target)
|
||||
{
|
||||
case "CHALLENGE" -> this.challengeIndex++;
|
||||
case "LEVEL" -> this.levelIndex++;
|
||||
}
|
||||
|
||||
this.build();
|
||||
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(this.world, action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private PanelItem createPreviousButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
String target = template.dataMap().getOrDefault("target", "").toString().toUpperCase();
|
||||
|
||||
int previousPageIndex;
|
||||
|
||||
if ("CHALLENGE".equals(target))
|
||||
{
|
||||
if (this.challengeIndex == 0)
|
||||
{
|
||||
// There are no next elements
|
||||
return null;
|
||||
}
|
||||
|
||||
previousPageIndex = this.challengeIndex;
|
||||
}
|
||||
else if ("LEVEL".equals(target))
|
||||
{
|
||||
if (this.levelIndex == 0)
|
||||
{
|
||||
// There are no next elements
|
||||
return null;
|
||||
}
|
||||
|
||||
previousPageIndex = this.levelIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not assigned to any type, return null.
|
||||
return null;
|
||||
}
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
ItemStack clone = template.icon().clone();
|
||||
|
||||
if ((Boolean) template.dataMap().getOrDefault("indexing", false))
|
||||
{
|
||||
clone.setAmount(previousPageIndex);
|
||||
}
|
||||
|
||||
builder.icon(clone);
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.world, template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(this.world, template.description()),
|
||||
Constants.NUMBER, String.valueOf(previousPageIndex));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
// Next button ignores click type currently.
|
||||
switch (target)
|
||||
{
|
||||
case "CHALLENGE" -> this.challengeIndex--;
|
||||
case "LEVEL" -> this.levelIndex--;
|
||||
}
|
||||
|
||||
this.build();
|
||||
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(this.world, action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This boolean indicates if in the world there exist challenges for displaying in GUI.
|
||||
*/
|
||||
private final boolean containsChallenges;
|
||||
|
||||
/**
|
||||
* This list contains free challenges in current Panel.
|
||||
*/
|
||||
private List<Challenge> freeChallengeList;
|
||||
|
||||
/**
|
||||
* This will be used if levels are more than 18.
|
||||
*/
|
||||
private int levelIndex;
|
||||
|
||||
/**
|
||||
* This list contains all information about level completion in current world.
|
||||
*/
|
||||
private List<LevelStatus> levelList;
|
||||
|
||||
/**
|
||||
* This will be used if free challenges are more than 18.
|
||||
*/
|
||||
private int challengeIndex;
|
||||
|
||||
/**
|
||||
* This list contains challenges in current Panel.
|
||||
*/
|
||||
private List<Challenge> challengeList;
|
||||
|
||||
/**
|
||||
* This indicates last selected level.
|
||||
*/
|
||||
private LevelStatus lastSelectedLevel;
|
||||
}
|
@ -0,0 +1,388 @@
|
||||
//
|
||||
// Created by BONNe
|
||||
// Copyright - 2021
|
||||
//
|
||||
|
||||
|
||||
package world.bentobox.challenges.panel.user;
|
||||
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.panels.PanelItem;
|
||||
import world.bentobox.bentobox.api.panels.TemplatedPanel;
|
||||
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
|
||||
import world.bentobox.bentobox.api.panels.builders.TemplatedPanelBuilder;
|
||||
import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
import world.bentobox.challenges.ChallengesAddon;
|
||||
import world.bentobox.challenges.panel.CommonPanel;
|
||||
import world.bentobox.challenges.utils.Constants;
|
||||
|
||||
|
||||
/**
|
||||
* Main challenges panel builder.
|
||||
*/
|
||||
public class GameModePanel extends CommonPanel
|
||||
{
|
||||
private GameModePanel(ChallengesAddon addon,
|
||||
World world,
|
||||
User user,
|
||||
List<GameModeAddon> addonList,
|
||||
boolean adminMode)
|
||||
{
|
||||
super(addon, user, world, null, null);
|
||||
this.addonList = addonList;
|
||||
this.adminMode = adminMode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open the Challenges GUI.
|
||||
*
|
||||
* @param addon the addon
|
||||
* @param world the world
|
||||
* @param user the user
|
||||
* @param addonList List of gamemode addons
|
||||
* @param adminMode Indicate if admin mode.
|
||||
*/
|
||||
public static void open(ChallengesAddon addon,
|
||||
World world,
|
||||
User user,
|
||||
List<GameModeAddon> addonList,
|
||||
boolean adminMode)
|
||||
{
|
||||
new GameModePanel(addon, world, user, addonList, adminMode).build();
|
||||
}
|
||||
|
||||
|
||||
protected void build()
|
||||
{
|
||||
// Start building panel.
|
||||
TemplatedPanelBuilder panelBuilder = new TemplatedPanelBuilder();
|
||||
|
||||
// Set main template.
|
||||
panelBuilder.template("gamemode_panel", new File(this.addon.getDataFolder(), "panels"));
|
||||
panelBuilder.user(this.user);
|
||||
panelBuilder.world(this.user.getWorld());
|
||||
|
||||
// Register button builders
|
||||
panelBuilder.registerTypeBuilder("GAMEMODE", this::createGameModeButton);
|
||||
|
||||
panelBuilder.registerTypeBuilder("NEXT", this::createNextButton);
|
||||
panelBuilder.registerTypeBuilder("PREVIOUS", this::createPreviousButton);
|
||||
|
||||
// Register unknown type builder.
|
||||
panelBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private PanelItem createGameModeButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
if (this.addonList.isEmpty())
|
||||
{
|
||||
// Does not contain any free challenges.
|
||||
return null;
|
||||
}
|
||||
|
||||
GameModeAddon gameModeAddon;
|
||||
|
||||
// Check if that is a specific free challenge
|
||||
if (template.dataMap().containsKey("id"))
|
||||
{
|
||||
String id = (String) template.dataMap().get("id");
|
||||
|
||||
// Find a challenge with given Id;
|
||||
gameModeAddon = this.addonList.stream().
|
||||
filter(gamemode -> gamemode.getDescription().getName().equals(id)).
|
||||
findFirst().
|
||||
orElse(null);
|
||||
|
||||
if (gameModeAddon == null)
|
||||
{
|
||||
// There is no gamemode in the list with specific id.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = this.addonIndex * slot.amountMap().getOrDefault("GAMEMODE", 1) + slot.slot();
|
||||
|
||||
if (index >= this.addonList.size())
|
||||
{
|
||||
// Out of index.
|
||||
return null;
|
||||
}
|
||||
|
||||
gameModeAddon = this.addonList.get(index);
|
||||
}
|
||||
|
||||
return this.createGameModeButton(template, gameModeAddon);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
private PanelItem createGameModeButton(ItemTemplateRecord template, @NonNull GameModeAddon gameModeAddon)
|
||||
{
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
// Template specification are always more important than dynamic content.
|
||||
builder.icon(template.icon() != null ?
|
||||
template.icon().clone() :
|
||||
new ItemStack(gameModeAddon.getDescription().getIcon()));
|
||||
|
||||
// Template specific title is always more important than challenge name.
|
||||
if (template.title() != null && !template.title().isBlank())
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.world, template.title(),
|
||||
Constants.GAMEMODE, gameModeAddon.getDescription().getName()));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.name(Util.translateColorCodes(gameModeAddon.getDescription().getName()));
|
||||
}
|
||||
|
||||
if (template.description() != null && !template.description().isBlank())
|
||||
{
|
||||
// TODO: adding parameters could be useful.
|
||||
builder.description(this.user.getTranslation(this.world, template.description()));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.description(gameModeAddon.getDescription().getDescription());
|
||||
}
|
||||
|
||||
// Add Click handler
|
||||
builder.clickHandler((panel, user, clickType, i) -> {
|
||||
for (ItemTemplateRecord.ActionRecords action : template.actions())
|
||||
{
|
||||
if (clickType == action.clickType())
|
||||
{
|
||||
Optional<CompositeCommand> command;
|
||||
|
||||
if (this.adminMode)
|
||||
{
|
||||
command = gameModeAddon.getAdminCommand();
|
||||
}
|
||||
else
|
||||
{
|
||||
command = gameModeAddon.getPlayerCommand();
|
||||
}
|
||||
|
||||
command.ifPresent(compositeCommand ->
|
||||
user.performCommand(compositeCommand.getTopLabel() + " challenges"));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(this.world, action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
// Glow the icon.
|
||||
builder.glow(gameModeAddon.inWorld(this.user.getWorld()));
|
||||
|
||||
// Click Handlers are managed by custom addon buttons.
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private PanelItem createNextButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
String target = template.dataMap().getOrDefault("target", "").toString().toUpperCase();
|
||||
|
||||
int nextPageIndex;
|
||||
|
||||
if ("GAMEMODE".equals(target))
|
||||
{
|
||||
int size = this.addonList.size();
|
||||
|
||||
if (size <= slot.amountMap().getOrDefault("GAMEMODE", 1) ||
|
||||
1.0 * size / slot.amountMap().getOrDefault("GAMEMODE", 1) <= this.addonIndex + 1)
|
||||
{
|
||||
// There are no next elements
|
||||
return null;
|
||||
}
|
||||
|
||||
nextPageIndex = this.addonIndex + 2;
|
||||
}
|
||||
else
|
||||
{// If not assigned to any type, return null.
|
||||
return null;
|
||||
}
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
ItemStack clone = template.icon().clone();
|
||||
|
||||
if ((Boolean) template.dataMap().getOrDefault("indexing", false))
|
||||
{
|
||||
clone.setAmount(nextPageIndex);
|
||||
}
|
||||
|
||||
builder.icon(clone);
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.world, template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(this.world, template.description()),
|
||||
Constants.NUMBER, String.valueOf(nextPageIndex));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
this.addonIndex++;
|
||||
this.build();
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(this.world, action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private PanelItem createPreviousButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
String target = template.dataMap().getOrDefault("target", "").toString().toUpperCase();
|
||||
|
||||
int previousPageIndex;
|
||||
|
||||
if ("GAMEMODE".equals(target))
|
||||
{
|
||||
if (this.addonIndex == 0)
|
||||
{
|
||||
// There are no next elements
|
||||
return null;
|
||||
}
|
||||
|
||||
previousPageIndex = this.addonIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not assigned to any type, return null.
|
||||
return null;
|
||||
}
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
ItemStack clone = template.icon().clone();
|
||||
|
||||
if ((Boolean) template.dataMap().getOrDefault("indexing", false))
|
||||
{
|
||||
clone.setAmount(previousPageIndex);
|
||||
}
|
||||
|
||||
builder.icon(clone);
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.world, template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(this.world, template.description()),
|
||||
Constants.NUMBER, String.valueOf(previousPageIndex));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
// Next button ignores click type currently.
|
||||
this.addonIndex--;
|
||||
this.build();
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(this.world, action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This will be used if free challenges are more than 18.
|
||||
*/
|
||||
private int addonIndex;
|
||||
|
||||
/**
|
||||
* This list contains challenges in current Panel.
|
||||
*/
|
||||
private final List<GameModeAddon> addonList;
|
||||
|
||||
/**
|
||||
* Indicate if gui is for players or admins.
|
||||
*/
|
||||
private final boolean adminMode;
|
||||
}
|
@ -0,0 +1,282 @@
|
||||
//
|
||||
// Created by BONNe
|
||||
// Copyright - 2021
|
||||
//
|
||||
|
||||
|
||||
package world.bentobox.challenges.panel.user;
|
||||
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import world.bentobox.bentobox.api.panels.PanelItem;
|
||||
import world.bentobox.bentobox.api.panels.TemplatedPanel;
|
||||
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
|
||||
import world.bentobox.bentobox.api.panels.builders.TemplatedPanelBuilder;
|
||||
import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.challenges.ChallengesAddon;
|
||||
import world.bentobox.challenges.panel.ConversationUtils;
|
||||
import world.bentobox.challenges.utils.Constants;
|
||||
|
||||
|
||||
public class MultiplePanel
|
||||
{
|
||||
private MultiplePanel(ChallengesAddon addon, User user, Consumer<Integer> action)
|
||||
{
|
||||
this.addon = addon;
|
||||
this.user = user;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
|
||||
public static void open(ChallengesAddon addon, User user, Consumer<Integer> action)
|
||||
{
|
||||
new MultiplePanel(addon, user, action).build();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
private void build()
|
||||
{
|
||||
// Start building panel.
|
||||
TemplatedPanelBuilder panelBuilder = new TemplatedPanelBuilder();
|
||||
|
||||
// Set main template.
|
||||
panelBuilder.template("multiple_panel", new File(this.addon.getDataFolder(), "panels"));
|
||||
panelBuilder.user(this.user);
|
||||
panelBuilder.world(this.user.getWorld());
|
||||
|
||||
// Register button builders
|
||||
panelBuilder.registerTypeBuilder("INCREASE", this::createIncreaseButton);
|
||||
panelBuilder.registerTypeBuilder("REDUCE", this::createReduceButton);
|
||||
panelBuilder.registerTypeBuilder("ACCEPT", this::createValueButton);
|
||||
|
||||
// Register unknown type builder.
|
||||
panelBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
private PanelItem createIncreaseButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot itemSlot)
|
||||
{
|
||||
int increaseValue = (int) template.dataMap().getOrDefault("value", 1);
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
ItemStack clone = template.icon().clone();
|
||||
clone.setAmount(increaseValue);
|
||||
builder.icon(clone);
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(template.description(),
|
||||
Constants.NUMBER, String.valueOf(increaseValue)));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
this.completionValue += increaseValue;
|
||||
this.build();
|
||||
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
private PanelItem createReduceButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot itemSlot)
|
||||
{
|
||||
int decreaseValue = (int) template.dataMap().getOrDefault("value", 1);
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
ItemStack clone = template.icon().clone();
|
||||
clone.setAmount(decreaseValue);
|
||||
builder.icon(clone);
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(template.description(),
|
||||
Constants.NUMBER, String.valueOf(decreaseValue)));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
this.completionValue = Math.max(this.completionValue - decreaseValue, 1);
|
||||
this.build();
|
||||
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
private PanelItem createValueButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot itemSlot)
|
||||
{
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
ItemStack clone = template.icon().clone();
|
||||
clone.setAmount(this.completionValue);
|
||||
builder.icon(clone);
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(template.description(),
|
||||
Constants.NUMBER, String.valueOf(completionValue)));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
for (ItemTemplateRecord.ActionRecords actionRecords : template.actions())
|
||||
{
|
||||
if (clickType == actionRecords.clickType())
|
||||
{
|
||||
if (actionRecords.actionType().equalsIgnoreCase("input"))
|
||||
{
|
||||
// Input consumer.
|
||||
Consumer<Number> numberConsumer = number ->
|
||||
{
|
||||
if (number != null)
|
||||
{
|
||||
this.completionValue = number.intValue();
|
||||
}
|
||||
|
||||
// reopen panel
|
||||
this.build();
|
||||
};
|
||||
|
||||
ConversationUtils.createNumericInput(numberConsumer,
|
||||
this.user,
|
||||
this.user.getTranslation(Constants.CONVERSATIONS + "input-number"),
|
||||
1,
|
||||
2000);
|
||||
}
|
||||
else if (actionRecords.actionType().equalsIgnoreCase("accept"))
|
||||
{
|
||||
this.action.accept(this.completionValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Variable stores user who created this panel.
|
||||
*/
|
||||
private final User user;
|
||||
|
||||
/**
|
||||
* This variable holds action that will be performed on accept.
|
||||
*/
|
||||
private final Consumer<Integer> action;
|
||||
|
||||
/**
|
||||
* Variable stores Challenges addon.
|
||||
*/
|
||||
protected final ChallengesAddon addon;
|
||||
|
||||
/**
|
||||
* Local storing of selected value.
|
||||
*/
|
||||
private int completionValue = 1;
|
||||
}
|
49
src/main/resources/panels/gamemode_panel.yml
Normal file
49
src/main/resources/panels/gamemode_panel.yml
Normal file
@ -0,0 +1,49 @@
|
||||
gamemode_panel:
|
||||
title: challenges.gui.titles.gamemode-gui
|
||||
type: INVENTORY
|
||||
background:
|
||||
icon: BLACK_STAINED_GLASS_PANE
|
||||
title: "&b&r" # Empty text
|
||||
border:
|
||||
icon: BLACK_STAINED_GLASS_PANE
|
||||
title: "&b&r" # Empty text
|
||||
force-shown: []
|
||||
content:
|
||||
2:
|
||||
1:
|
||||
icon: TIPPED_ARROW:INSTANT_HEAL::::1
|
||||
title: challenges.gui.buttons.previous.name
|
||||
description: challenges.gui.buttons.previous.description
|
||||
data:
|
||||
type: PREVIOUS
|
||||
target: GAMEMODE
|
||||
indexing: true
|
||||
action:
|
||||
left:
|
||||
tooltip: challenges.gui.tips.click-to-select
|
||||
2: gamemode
|
||||
3: gamemode
|
||||
4: gamemode
|
||||
5: gamemode
|
||||
6: gamemode
|
||||
7: gamemode
|
||||
8: gamemode
|
||||
9:
|
||||
icon: TIPPED_ARROW:JUMP::::1
|
||||
title: challenges.gui.buttons.next.name
|
||||
description: challenges.gui.buttons.next.description
|
||||
data:
|
||||
type: NEXT
|
||||
target: GAMEMODE
|
||||
indexing: true
|
||||
action:
|
||||
left:
|
||||
tooltip: challenges.gui.tips.click-to-select
|
||||
reusable:
|
||||
gamemode:
|
||||
data:
|
||||
type: GAMEMODE
|
||||
actions:
|
||||
left:
|
||||
type: SELECT
|
||||
tooltip: challenges.gui.tips.click-to-select
|
110
src/main/resources/panels/main_panel.yml
Normal file
110
src/main/resources/panels/main_panel.yml
Normal file
@ -0,0 +1,110 @@
|
||||
main_panel:
|
||||
title: challenges.gui.titles.player-gui
|
||||
type: INVENTORY
|
||||
background:
|
||||
icon: BLACK_STAINED_GLASS_PANE
|
||||
title: "&b&r" # Empty text
|
||||
border:
|
||||
icon: BLACK_STAINED_GLASS_PANE
|
||||
title: "&b&r" # Empty text
|
||||
force-shown: [4]
|
||||
content:
|
||||
2:
|
||||
2: challenge_button
|
||||
3: challenge_button
|
||||
4: challenge_button
|
||||
5: challenge_button
|
||||
6: challenge_button
|
||||
7: challenge_button
|
||||
8: challenge_button
|
||||
3:
|
||||
1:
|
||||
icon: TIPPED_ARROW:INSTANT_HEAL::::1
|
||||
title: challenges.gui.buttons.previous.name
|
||||
description: challenges.gui.buttons.previous.description
|
||||
data:
|
||||
type: PREVIOUS
|
||||
target: CHALLENGE
|
||||
indexing: true
|
||||
action:
|
||||
left:
|
||||
tooltip: challenges.gui.tips.click-to-select
|
||||
2: challenge_button
|
||||
3: challenge_button
|
||||
4: challenge_button
|
||||
5: challenge_button
|
||||
6: challenge_button
|
||||
7: challenge_button
|
||||
8: challenge_button
|
||||
9:
|
||||
icon: TIPPED_ARROW:JUMP::::1
|
||||
title: challenges.gui.buttons.next.name
|
||||
description: challenges.gui.buttons.next.description
|
||||
data:
|
||||
type: NEXT
|
||||
target: CHALLENGE
|
||||
indexing: true
|
||||
action:
|
||||
left:
|
||||
tooltip: challenges.gui.tips.click-to-select
|
||||
5:
|
||||
1:
|
||||
icon: TIPPED_ARROW:INSTANT_HEAL::::1
|
||||
title: challenges.gui.buttons.previous.name
|
||||
description: challenges.gui.buttons.previous.description
|
||||
data:
|
||||
type: PREVIOUS
|
||||
target: LEVEL
|
||||
indexing: true
|
||||
action:
|
||||
left:
|
||||
tooltip: challenges.gui.tips.click-to-select
|
||||
2: level_button
|
||||
3: level_button
|
||||
4: level_button
|
||||
5: level_button
|
||||
6: level_button
|
||||
7: level_button
|
||||
8: level_button
|
||||
9:
|
||||
icon: TIPPED_ARROW:JUMP::::1
|
||||
title: challenges.gui.buttons.next.name
|
||||
description: challenges.gui.buttons.next.description
|
||||
data:
|
||||
type: NEXT
|
||||
target: LEVEL
|
||||
indexing: true
|
||||
action:
|
||||
left:
|
||||
tooltip: challenges.gui.tips.click-to-select
|
||||
6:
|
||||
5:
|
||||
icon: IRON_BARS
|
||||
title: challenges.gui.buttons.free-challenges.name
|
||||
description: challenges.gui.buttons.free-challenges.description
|
||||
data:
|
||||
type: UNASSIGNED_CHALLENGES
|
||||
action:
|
||||
left:
|
||||
tooltip: challenges.gui.tips.click-to-select
|
||||
reusable:
|
||||
challenge_button:
|
||||
data:
|
||||
type: CHALLENGE
|
||||
actions:
|
||||
left:
|
||||
type: COMPLETE
|
||||
tooltip: challenges.gui.tips.click-to-complete
|
||||
right:
|
||||
type: MULTIPLE_PANEL
|
||||
tooltip: challenges.gui.tips.right-click-multiple-open
|
||||
shift_left:
|
||||
type: COMPLETE_MAX
|
||||
tooltip: challenges.gui.tips.shift-left-click-to-complete-all
|
||||
level_button:
|
||||
data:
|
||||
type: LEVEL
|
||||
actions:
|
||||
left:
|
||||
type: SELECT
|
||||
tooltip: challenges.gui.tips.click-to-select
|
58
src/main/resources/panels/multiple_panel.yml
Normal file
58
src/main/resources/panels/multiple_panel.yml
Normal file
@ -0,0 +1,58 @@
|
||||
multiple_panel:
|
||||
title: challenges.gui.titles.multiple-gui
|
||||
type: HOPPER
|
||||
content:
|
||||
1:
|
||||
1:
|
||||
icon: RED_STAINED_GLASS_PANE
|
||||
title: challenges.gui.buttons.reduce.name
|
||||
description: challenges.gui.buttons.reduce.description
|
||||
data:
|
||||
type: REDUCE
|
||||
value: 5
|
||||
actions:
|
||||
left:
|
||||
tooltip: challenges.gui.tips.click-to-reduce
|
||||
2:
|
||||
icon: ORANGE_STAINED_GLASS_PANE
|
||||
title: challenges.gui.buttons.reduce.name
|
||||
description: challenges.gui.buttons.reduce.description
|
||||
data:
|
||||
type: REDUCE
|
||||
value: 1
|
||||
actions:
|
||||
left:
|
||||
tooltip: challenges.gui.tips.click-to-reduce
|
||||
3:
|
||||
icon: GREEN_STAINED_GLASS_PANE
|
||||
title: challenges.gui.buttons.accept.name
|
||||
description: challenges.gui.buttons.accept.description
|
||||
data:
|
||||
type: ACCEPT
|
||||
actions:
|
||||
left:
|
||||
type: ACCEPT
|
||||
tooltip: challenges.gui.tips.left-click-to-accept
|
||||
right:
|
||||
type: INPUT
|
||||
tooltip: challenges.gui.tips.right-click-to-write
|
||||
4:
|
||||
icon: BLUE_STAINED_GLASS_PANE
|
||||
title: challenges.gui.buttons.increase.name
|
||||
description: challenges.gui.buttons.increase.description
|
||||
data:
|
||||
type: INCREASE
|
||||
value: 1
|
||||
actions:
|
||||
left:
|
||||
tooltip: challenges.gui.tips.click-to-increase
|
||||
5:
|
||||
icon: MAGENTA_STAINED_GLASS_PANE
|
||||
title: challenges.gui.buttons.increase.name
|
||||
description: challenges.gui.buttons.increase.description
|
||||
data:
|
||||
type: INCREASE
|
||||
value: 5
|
||||
actions:
|
||||
left:
|
||||
tooltip: challenges.gui.tips.click-to-increase
|
Loading…
Reference in New Issue
Block a user