Merge branch 'develop' into master

# Conflicts:
#	pom.xml
#	src/main/java/world/bentobox/challenges/commands/admin/ChallengesGlobalAdminCommand.java
#	src/main/java/world/bentobox/challenges/managers/ChallengesImportManager.java
#	src/main/java/world/bentobox/challenges/managers/ChallengesManager.java
#	src/main/java/world/bentobox/challenges/panel/CommonPanel.java
#	src/main/java/world/bentobox/challenges/panel/user/ChallengesPanel.java
#	src/main/java/world/bentobox/challenges/tasks/TryToComplete.java
#	src/main/resources/locales/en-US.yml
#	src/main/resources/locales/pl.yml
#	src/main/resources/locales/zh-CN.yml
#	src/main/resources/template.yml
This commit is contained in:
BONNe 2023-01-05 21:40:14 +02:00
commit 7f58af7588
14 changed files with 3306 additions and 1239 deletions

View File

@ -1,6 +0,0 @@
Contributions are welcome but acceptance is completely up to tastybento. Do not be offended if your contribution is rejected.
I will not accept any contributions that are formatting only, or mostly formatting.
Automated code cleanup is also not a valid contribution as a first Pull Request. If a tool is doing your job,
the submit an issue that recommends we use a specific tool.
Contributions are accepted under the license terms and conditions. Note that this means we may use them elsewhere.
Thank you!

View File

@ -1,5 +0,0 @@
Thanks for submitting a pull request. Do not use this form for bug reports!
Your submission must meet the minimum requirements of a contribution, i.e., add code, refactor code or fix code.
It takes time and effort to review submissions, so please do not waste our time.
Note: formatting/spacing-only submissions will be rejected!
For submissions, we want you to use spaces, not tabs (4 spaces) - thank you.

View File

@ -37,14 +37,14 @@
<!-- More visible way how to change dependency versions --> <!-- More visible way how to change dependency versions -->
<spigot.version>1.17.1-R0.1-SNAPSHOT</spigot.version> <spigot.version>1.17.1-R0.1-SNAPSHOT</spigot.version>
<spigot-annotations.version>1.2.3-SNAPSHOT</spigot-annotations.version> <spigot-annotations.version>1.2.3-SNAPSHOT</spigot-annotations.version>
<bentobox.version>1.20.0</bentobox.version> <bentobox.version>1.21.0</bentobox.version>
<level.version>2.6.3</level.version> <level.version>2.6.3</level.version>
<vault.version>1.7</vault.version> <vault.version>1.7</vault.version>
<panelutils.version>1.0.0</panelutils.version> <panelutils.version>1.1.0</panelutils.version>
<!-- Revision variable removes warning about dynamic version --> <!-- Revision variable removes warning about dynamic version -->
<revision>${build.version}-SNAPSHOT</revision> <revision>${build.version}-SNAPSHOT</revision>
<!-- This allows to change between versions and snapshots. --> <!-- This allows to change between versions and snapshots. -->
<build.version>1.0.0</build.version> <build.version>1.1.0</build.version>
<build.number>-LOCAL</build.number> <build.number>-LOCAL</build.number>
<!-- Sonar Cloud --> <!-- Sonar Cloud -->
<sonar.projectKey>BentoBoxWorld_Challenges</sonar.projectKey> <sonar.projectKey>BentoBoxWorld_Challenges</sonar.projectKey>

View File

@ -37,7 +37,7 @@ public class ChallengesGlobalAdminCommand extends CompositeCommand
@Override @Override
public void setup() public void setup()
{ {
this.setPermission("addon.admin.challenges"); this.setPermission("admin.challenges");
this.setParametersHelp("challenges.commands.admin.main.parameters"); this.setParametersHelp("challenges.commands.admin.main.parameters");
this.setDescription("challenges.commands.admin.main.description"); this.setDescription("challenges.commands.admin.main.description");
} }

View File

@ -101,10 +101,8 @@ public class ChallengesImportManager
Utils.sendMessage(user, user.getTranslation(Constants.ERRORS + "no-load", Utils.sendMessage(user, user.getTranslation(Constants.ERRORS + "no-load",
Constants.PARAMETER_FILE, file, TextVariables.DESCRIPTION, e.getMessage())); Constants.PARAMETER_FILE, file, TextVariables.DESCRIPTION, e.getMessage()));
} }
else
{ this.addon.logError("Exception when loading file. " + e.getMessage());
this.addon.logError("Exception when loading file. " + e.getMessage());
}
return; return;
} }
@ -119,10 +117,8 @@ public class ChallengesImportManager
user.getTranslation(Constants.ERRORS + "not-a-gamemode-world", user.getTranslation(Constants.ERRORS + "not-a-gamemode-world",
Constants.PARAMETER_WORLD, world.getName())); Constants.PARAMETER_WORLD, world.getName()));
} }
else
{ this.addon.logWarning("Given world is not a gamemode world.");
this.addon.logWarning("Given world is not a gamemode world.");
}
return; return;
} }

View File

@ -113,41 +113,28 @@ public class ChallengesManager
* This comparator orders challenges by their level, order and name. * This comparator orders challenges by their level, order and name.
*/ */
private final Comparator<Challenge> challengeComparator = (o1, o2) -> { private final Comparator<Challenge> challengeComparator = (o1, o2) -> {
if (o1.getLevel().equals(o2.getLevel())) ChallengeLevel o1Level = this.getLevel(o1.getLevel());
ChallengeLevel o2Level = this.getLevel(o2.getLevel());
if (o1Level == null && o2Level == null)
{ {
if (o1.getOrder() == o2.getOrder()) return Integer.compare(o1.getOrder(), o2.getOrder());
{ }
// If orders are equal, sort by unique id else if (o1Level == null)
return o1.getUniqueId().compareToIgnoreCase(o2.getUniqueId()); {
} return -1;
else }
{ else if (o2Level == null)
// If levels are equal, sort them by order numbers. {
return Integer.compare(o1.getOrder(), o2.getOrder()); return 1;
} }
else if (o1Level.equals(o2Level))
{
return Integer.compare(o1.getOrder(), o2.getOrder());
} }
else else
{ {
if (o1.getLevel().isEmpty() || o2.getLevel().isEmpty()) return Integer.compare(o1Level.getOrder(), o2Level.getOrder());
{
// If exist free level challenge, then it should be at the start.
return Boolean.compare(o2.getLevel().isEmpty(), o1.getLevel().isEmpty());
}
else
{
ChallengeLevel o1Level = this.getLevel(o1.getLevel());
ChallengeLevel o2Level = this.getLevel(o2.getLevel());
if (o1Level == null || o2Level == null)
{
return Boolean.compare(o1Level == null, o2Level == null);
}
else
{
// Sort by challenges level order numbers
return Integer.compare(o1Level.getOrder(), o2Level.getOrder());
}
}
} }
}; };

View File

@ -496,7 +496,7 @@ public abstract class CommonPanel
this.user.getTranslationOrNothing(reference + "money-warning") : ""; this.user.getTranslationOrNothing(reference + "money-warning") : "";
String level = !this.addon.isLevelProvided() || requirement.getRequiredIslandLevel() <= 0 ? "" : String level = !this.addon.isLevelProvided() || requirement.getRequiredIslandLevel() <= 0 ? "" :
this.user.getTranslationOrNothing(reference, this.user.getTranslationOrNothing(reference + "level",
"[number]", String.valueOf(requirement.getRequiredIslandLevel())); "[number]", String.valueOf(requirement.getRequiredIslandLevel()));
return this.user.getTranslationOrNothing(reference + "lore", return this.user.getTranslationOrNothing(reference + "lore",

View File

@ -8,6 +8,7 @@ package world.bentobox.challenges.panel.user;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
@ -274,11 +275,43 @@ public class ChallengesPanel extends CommonPanel
builder.description(this.generateChallengeDescription(challenge, this.user)); builder.description(this.generateChallengeDescription(challenge, this.user));
} }
// If challenge is not repeatable, remove all other actions beside "COMPLETE".
// If challenge is completed all possible times, remove action.
List<ItemTemplateRecord.ActionRecords> actions = template.actions().stream().
filter(action -> challenge.isRepeatable() || "COMPLETE".equalsIgnoreCase(action.actionType())).
filter(action ->
{
boolean isCompletedOnce =
this.manager.isChallengeComplete(this.user.getUniqueId(), this.world, challenge);
if (!isCompletedOnce)
{
// Is not completed once, then it must appear.
return true;
}
else if (challenge.isRepeatable() && challenge.getMaxTimes() <= 0)
{
// Challenge is unlimited. Must appear in the list.
return true;
}
else
{
// Challenge still have some opened slots.
long doneTimes = challenge.isRepeatable() ?
this.manager.getChallengeTimes(this.user, this.world, challenge) : 1;
return challenge.isRepeatable() && doneTimes < challenge.getMaxTimes();
}
}).
toList();
// Add Click handler // Add Click handler
builder.clickHandler((panel, user, clickType, i) -> { builder.clickHandler((panel, user, clickType, i) -> {
for (ItemTemplateRecord.ActionRecords action : template.actions()) for (ItemTemplateRecord.ActionRecords action : actions)
{ {
if (clickType == action.clickType()) if (clickType == action.clickType() || clickType.equals(ClickType.UNKNOWN))
{ {
switch (action.actionType().toUpperCase()) switch (action.actionType().toUpperCase())
{ {
@ -368,9 +401,8 @@ public class ChallengesPanel extends CommonPanel
}); });
// Collect tooltips. // Collect tooltips.
List<String> tooltips = template.actions().stream(). List<String> tooltips = actions.stream().
filter(action -> action.tooltip() != null). filter(action -> action.tooltip() != null).
filter(action -> challenge.isRepeatable() || "COMPLETE".equalsIgnoreCase(action.actionType())).
map(action -> this.user.getTranslation(this.world, action.tooltip())). map(action -> this.user.getTranslation(this.world, action.tooltip())).
filter(text -> !text.isBlank()). filter(text -> !text.isBlank()).
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size()))); collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));

View File

@ -791,17 +791,25 @@ public class TryToComplete
private void runCommands(List<String> commands) private void runCommands(List<String> commands)
{ {
// Ignore commands with this perm // Ignore commands with this perm
if (user.hasPermission(this.permissionPrefix + "command.challengeexempt") && !user.isOp()) if (this.user.hasPermission(this.permissionPrefix + "command.challengeexempt") && !this.user.isOp())
{ {
return; return;
} }
final Island island = this.addon.getIslandsManager().getIsland(this.world, this.user);
final String owner = island == null ? "" : this.addon.getPlayers().getName(island.getOwner());
for (String cmd : commands) for (String cmd : commands)
{ {
if (cmd.startsWith("[SELF]")) if (cmd.startsWith("[SELF]"))
{ {
String alert = "Running command '" + cmd + "' as " + this.user.getName(); String alert = "Running command '" + cmd + "' as " + this.user.getName();
this.addon.getLogger().info(alert); this.addon.getLogger().info(alert);
cmd = cmd.substring(6).replace(Constants.PARAMETER_PLAYER, this.user.getName()).trim(); cmd = cmd.substring(6).
replaceAll(Constants.PARAMETER_PLAYER, this.user.getName()).
replaceAll(Constants.PARAMETER_OWNER, owner).
replaceAll(Constants.PARAMETER_NAME, island == null || island.getName() == null ? "" : island.getName()).
trim();
try try
{ {
if (!user.performCommand(cmd)) if (!user.performCommand(cmd))
@ -816,11 +824,17 @@ public class TryToComplete
continue; continue;
} }
// Substitute in any references to player // Substitute in any references to player
try try
{ {
if (!this.addon.getServer().dispatchCommand(this.addon.getServer().getConsoleSender(), cmd = cmd.replaceAll(Constants.PARAMETER_PLAYER, this.user.getName()).
cmd.replace(Constants.PARAMETER_PLAYER, this.user.getName()))) replaceAll(Constants.PARAMETER_OWNER, owner).
replaceAll(Constants.PARAMETER_NAME, island == null || island.getName() == null ? "" : island.getName()).
trim();
if (!this.addon.getServer().dispatchCommand(this.addon.getServer().getConsoleSender(), cmd))
{ {
this.showError(cmd); this.showError(cmd);
} }
@ -1428,6 +1442,7 @@ public class TryToComplete
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.requirement-not-met", Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.requirement-not-met",
TextVariables.NUMBER, String.valueOf(requirements.getAmount()), TextVariables.NUMBER, String.valueOf(requirements.getAmount()),
"[statistic]", Utils.prettifyObject(requirements.getStatistic(), this.user),
"[value]", String.valueOf(currentValue))); "[value]", String.valueOf(currentValue)));
} }
else else

View File

@ -1189,7 +1189,7 @@ challenges:
not-enough-money: '&c It is necessary to have [value] on your account to complete the challenge.' not-enough-money: '&c It is necessary to have [value] on your account to complete the challenge.'
not-enough-experience: '&c It is necessary to have [value] EXP to complete this challenge.' not-enough-experience: '&c It is necessary to have [value] EXP to complete this challenge.'
island-level: '&c Your island must be level [number] or greater to complete this challenge!' island-level: '&c Your island must be level [number] or greater to complete this challenge!'
no-load: '&c Error: Could not load file. [message]' no-load: '&c Error: Could not load [file]. Error [message]'
load-error: '&c Error: Cannot load [value].' load-error: '&c Error: Cannot load [value].'
no-rank: "&c You do not have rank that is high enough to do that." no-rank: "&c You do not have rank that is high enough to do that."
cannot-remove-items: '&c Some items cannot be removed from your inventory!' cannot-remove-items: '&c Some items cannot be removed from your inventory!'
@ -1203,6 +1203,7 @@ challenges:
no-library-entries: "&c Cannot find any library entries. Nothing to show." no-library-entries: "&c Cannot find any library entries. Nothing to show."
not-hooked: "&c Challenges Addon could not find any GameMode." not-hooked: "&c Challenges Addon could not find any GameMode."
timeout: "&c This challenge requires to wait [timeout] between completions. You must wait [wait-time] till complete it again." timeout: "&c This challenge requires to wait [timeout] between completions. You must wait [wait-time] till complete it again."
requirement-not-met: "&c This challenge requires [statistic] to have [number]. You have only [value]. "
# # Showcase for manual material translation # # Showcase for manual material translation
# materials: # materials:
# # Names should be lowercase. # # Names should be lowercase.
@ -1238,7 +1239,27 @@ challenges:
# # This will overwrite generic translation. # # This will overwrite generic translation.
# name: "[type] [upgraded] [extended]" # name: "[type] [upgraded] [extended]"
# # Type is either specific translation or potion effect. # # Type is either specific translation or potion effect.
# uncraftable: "Uncraftable"
# water: "Water"
# mundane: "Mundane"
# thick: "Thick"
# awkward: "Awkward"
# night_vision: "Potion of Night Vision"
# invisibility: "Potion of Invisibility"
# jump: "Potion of Leaping"
# fire_resistance: "Potion of Fire Resistance"
# speed: "Potion of Swiftness"
# slowness: "Potion of Slowness"
# water_breathing: "Potion of Water Breathing" # water_breathing: "Potion of Water Breathing"
# instant_heal: "Potion of Healing"
# instant_damage: "Potion of Harming"
# poison: "Potion of Poison"
# regen: "Potion of Regeneration"
# strength: "Potion of Strength"
# weakness: "Potion of Weakness"
# luck: "Potion of Luck"
# turtle_master: "Potion of Turtle Master"
# slow_falling: "Potion of Slow Falling"
# stone_shovel: # stone_shovel:
# # This will mean that only stone shovels will not show # # This will mean that only stone shovels will not show
# # meta information. # # meta information.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -88,6 +88,10 @@ challenges:
# It is not necessary to writhe `/`. # It is not necessary to writhe `/`.
# This examples first command will force player to execute `/island` command, # This examples first command will force player to execute `/island` command,
# While second command will run `/kill [player]` from the server console. # While second command will run `/kill [player]` from the server console.
# There are 3 available parameters for commands:
# - [player] - player who completed the challenge
# - [owner] - the island owner
# - [name] - the name of the island.
commands: commands:
- island - island
- kill [player] - kill [player]
@ -122,6 +126,10 @@ challenges:
# It is not necessary to writhe `/`. # It is not necessary to writhe `/`.
# This examples first command will force player to execute `/island` command, # This examples first command will force player to execute `/island` command,
# While second command will run `/kill [player]` from the server console. # While second command will run `/kill [player]` from the server console.
# There are 3 available parameters for commands:
# - [player] - player who completed the challenge
# - [owner] - the island owner
# - [name] - the name of the island.
commands: commands:
- island - island
- kill [player] - kill [player]
@ -220,6 +228,10 @@ challenges:
# It is not necessary to writhe `/`. # It is not necessary to writhe `/`.
# This examples first command will force player to execute `/island` command, # This examples first command will force player to execute `/island` command,
# While second command will run `/kill [player]` from the server console. # While second command will run `/kill [player]` from the server console.
# There are 3 available parameters for commands:
# - [player] - player who completed the challenge
# - [owner] - the island owner
# - [name] - the name of the island.
commands: commands:
- island - island
- kill [player] - kill [player]
@ -254,6 +266,10 @@ challenges:
# It is not necessary to writhe `/`. # It is not necessary to writhe `/`.
# This examples first command will force player to execute `/island` command, # This examples first command will force player to execute `/island` command,
# While second command will run `/kill [player]` from the server console. # While second command will run `/kill [player]` from the server console.
# There are 3 available parameters for commands:
# - [player] - player who completed the challenge
# - [owner] - the island owner
# - [name] - the name of the island.
commands: commands:
- island - island
- kill [player] - kill [player]
@ -339,6 +355,10 @@ challenges:
# It is not necessary to writhe `/`. # It is not necessary to writhe `/`.
# This examples first command will force player to execute `/island` command, # This examples first command will force player to execute `/island` command,
# While second command will run `/kill [player]` from the server console. # While second command will run `/kill [player]` from the server console.
# There are 3 available parameters for commands:
# - [player] - player who completed the challenge
# - [owner] - the island owner
# - [name] - the name of the island.
commands: commands:
- island - island
- kill [player] - kill [player]
@ -373,6 +393,10 @@ challenges:
# It is not necessary to writhe `/`. # It is not necessary to writhe `/`.
# This examples first command will force player to execute `/island` command, # This examples first command will force player to execute `/island` command,
# While second command will run `/kill [player]` from the server console. # While second command will run `/kill [player]` from the server console.
# There are 3 available parameters for commands:
# - [player] - player who completed the challenge
# - [owner] - the island owner
# - [name] - the name of the island.
commands: commands:
- island - island
- kill [player] - kill [player]
@ -464,6 +488,10 @@ challenges:
# It is not necessary to writhe `/`. # It is not necessary to writhe `/`.
# This examples first command will force player to execute `/island` command, # This examples first command will force player to execute `/island` command,
# While second command will run `/kill [player]` from the server console. # While second command will run `/kill [player]` from the server console.
# There are 3 available parameters for commands:
# - [player] - player who completed the challenge
# - [owner] - the island owner
# - [name] - the name of the island.
commands: commands:
- island - island
- kill [player] - kill [player]
@ -498,6 +526,10 @@ challenges:
# It is not necessary to writhe `/`. # It is not necessary to writhe `/`.
# This examples first command will force player to execute `/island` command, # This examples first command will force player to execute `/island` command,
# While second command will run `/kill [player]` from the server console. # While second command will run `/kill [player]` from the server console.
# There are 3 available parameters for commands:
# - [player] - player who completed the challenge
# - [owner] - the island owner
# - [name] - the name of the island.
commands: commands:
- island - island
- kill [player] - kill [player]
@ -551,6 +583,10 @@ levels:
# It is not necessary to writhe `/`. # It is not necessary to writhe `/`.
# This examples first command will force player to execute `/island` command, # This examples first command will force player to execute `/island` command,
# While second command will run `/kill [player]` from the server console. # While second command will run `/kill [player]` from the server console.
# There are 3 available parameters for commands:
# - [player] - player who completed the challenge
# - [owner] - the island owner
# - [name] - the name of the island.
commands: commands:
- island - island
- kill [player] - kill [player]