Release 1.2.0 (#317)

* Init 1.2.0 version

* Fixes #311 localization errors in zn-CN.

Original translation author translated `[]` placeholders which broke locale

* Init 1.2.0 version

* Edit some unfit translation (#312)

Edit some unfit translation

* Fixes a regex bug that replaced every [player] char instead of whole word.

* Fixes a crash that prevented STATISTICS entity and material/item challenges to be completed.

* Add requirement-not-met-material and requirement-not-met-entity to display statistic required item on error.

* Add locale of Chinese-Hong Kong (zh-HK) (#313)

Addition of locale updated to latest version

* Add ${argLine} to get jacoco coverage

* Updated Jacoco POM section

* Update build.yml

Java 17 for Surefire

* Updated pladdon annotations

* Add support for gamemode-specific translations.

This was a request from Floris

* Update ChallengesManagerTest methods with world parameter.

* Implement option that excludes undeployed challenges

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

Fixes #315

* Create plugin.yml (#316)

* Create plugin.yml

* Update pom.xml

* Update ChallengesPladdon.java

* Remove dependency to org.apache.commons

Replace org.apache.commons.lang.ArrayUtils to a default Java implementation.

---------

Co-authored-by: EpicMo <1982742309@qq.com>
Co-authored-by: JamesMCL44 <epicquarters@gmail.com>
Co-authored-by: tastybento <tastybento@users.noreply.github.com>
Co-authored-by: tastybento <tastybento@wasteofplastic.com>
This commit is contained in:
BONNe 2023-04-15 22:55:34 +03:00 committed by GitHub
parent 7f58af7588
commit b1fa9a9da7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1869 additions and 504 deletions

View File

@ -14,10 +14,10 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK 16 - name: Set up JDK 17
uses: actions/setup-java@v1 uses: actions/setup-java@v1
with: with:
java-version: 16 java-version: 17
- name: Cache SonarCloud packages - name: Cache SonarCloud packages
uses: actions/cache@v1 uses: actions/cache@v1
with: with:
@ -34,4 +34,4 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar

55
pom.xml
View File

@ -32,7 +32,7 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>16</java.version> <java.version>17</java.version>
<powermock.version>2.0.9</powermock.version> <powermock.version>2.0.9</powermock.version>
<!-- More visible way how to change dependency versions --> <!-- More visible way how to change dependency versions -->
<spigot.version>1.17.1-R0.1-SNAPSHOT</spigot.version> <spigot.version>1.17.1-R0.1-SNAPSHOT</spigot.version>
@ -44,7 +44,7 @@
<!-- 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.1.0</build.version> <build.version>1.2.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>
@ -127,12 +127,6 @@
<version>${spigot.version}</version> <version>${spigot.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>plugin-annotations</artifactId>
<version>1.2.3-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- Vault API --> <!-- Vault API -->
<dependency> <dependency>
<groupId>net.milkbowl.vault</groupId> <groupId>net.milkbowl.vault</groupId>
@ -249,6 +243,7 @@
<version>3.0.0-M5</version> <version>3.0.0-M5</version>
<configuration> <configuration>
<argLine> <argLine>
${argLine}
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.math=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED
--add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED
@ -355,35 +350,35 @@
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.jacoco</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>3.3.1-SNAPSHOT</version> <version>0.8.7</version>
<configuration> <configuration>
<minimizeJar>true</minimizeJar> <append>true</append>
<artifactSet> <excludes>
<includes> <!-- This is required to prevent Jacoco from adding
<include>lv.id.bonne:panelutils:*</include> synthetic fields to a JavaBean class (causes errors in testing) -->
</includes> <exclude>**/*Names*</exclude>
</artifactSet> </excludes>
<transformers>
<!-- Add a transformer to exclude any other manifest files (possibly from dependencies). -->
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
<resource>MANIFEST.MF</resource>
</transformer>
<!-- Add a transformer to include your custom manifest file. -->
<transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
<resource>META-INF/MANIFEST.MF</resource>
<file>src/main/resources/META-INF/MANIFEST.MF</file>
</transformer>
</transformers>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <id>prepare-agent</id>
<goals> <goals>
<goal>shade</goal> <goal>prepare-agent</goal>
</goals> </goals>
</execution> </execution>
<execution>
<id>report</id>
<goals>
<goal>report</goal>
</goals>
<configuration>
<formats>
<format>XML</format>
</formats>
</configuration>
</execution>
</executions> </executions>
</plugin> </plugin>
</plugins> </plugins>

View File

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

View File

@ -7,19 +7,12 @@
package world.bentobox.challenges; package world.bentobox.challenges;
import org.bukkit.plugin.java.annotation.dependency.Dependency;
import org.bukkit.plugin.java.annotation.plugin.ApiVersion;
import org.bukkit.plugin.java.annotation.plugin.Plugin;
import world.bentobox.bentobox.api.addons.Addon; import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.Pladdon; import world.bentobox.bentobox.api.addons.Pladdon;
/** /**
* @author tastybento * @author tastybento
*/ */
@Plugin(name="Pladdon", version="1.0")
@ApiVersion(ApiVersion.Target.v1_17)
@Dependency(value = "BentoBox")
public class ChallengesPladdon extends Pladdon public class ChallengesPladdon extends Pladdon
{ {
@Override @Override
@ -27,4 +20,4 @@ public class ChallengesPladdon extends Pladdon
{ {
return new ChallengesAddon(); return new ChallengesAddon();
} }
} }

View File

@ -55,7 +55,7 @@ public class ChallengesGlobalPlayerCommand extends CompositeCommand
if (this.gameModeAddons.isEmpty()) if (this.gameModeAddons.isEmpty())
{ {
Utils.sendMessage(user, user.getTranslation(Constants.ERRORS + "not-hooked")); Utils.sendMessage(user, user.getWorld(), Constants.ERRORS + "not-hooked");
return false; return false;
} }
else if (this.gameModeAddons.size() == 1) else if (this.gameModeAddons.size() == 1)
@ -80,7 +80,7 @@ public class ChallengesGlobalPlayerCommand extends CompositeCommand
} }
} }
Utils.sendMessage(user, user.getTranslation("general.errors.wrong-world")); Utils.sendMessage(user, user.getWorld(), "general.errors.wrong-world");
} }
else if (this.<ChallengesAddon>getAddon().getChallengesSettings().getUserGuiMode() == GuiMode.GAMEMODE_LIST) else if (this.<ChallengesAddon>getAddon().getChallengesSettings().getUserGuiMode() == GuiMode.GAMEMODE_LIST)
{ {

View File

@ -8,6 +8,7 @@ import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.util.Util; import world.bentobox.bentobox.util.Util;
import world.bentobox.challenges.ChallengesAddon; import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.panel.user.ChallengesPanel; import world.bentobox.challenges.panel.user.ChallengesPanel;
import world.bentobox.challenges.utils.Constants;
import world.bentobox.challenges.utils.Utils; import world.bentobox.challenges.utils.Utils;
@ -31,7 +32,7 @@ public class ChallengesPlayerCommand extends CompositeCommand
if (!this.getIWM().inWorld(user.getWorld()) || if (!this.getIWM().inWorld(user.getWorld()) ||
!Util.sameWorld(this.getWorld(), user.getWorld())) { !Util.sameWorld(this.getWorld(), user.getWorld())) {
// Not a GameMode world. // Not a GameMode world.
Utils.sendMessage(user, user.getTranslation("general.errors.wrong-world")); Utils.sendMessage(user, user.getWorld(), "general.errors.wrong-world");
return false; return false;
} }
@ -47,13 +48,13 @@ public class ChallengesPlayerCommand extends CompositeCommand
map(GameModeAddon::getAdminCommand). map(GameModeAddon::getAdminCommand).
map(optionalAdminCommand -> optionalAdminCommand.map(CompositeCommand::getTopLabel).orElse(this.getTopLabel())). map(optionalAdminCommand -> optionalAdminCommand.map(CompositeCommand::getTopLabel).orElse(this.getTopLabel())).
orElse(this.getTopLabel()); orElse(this.getTopLabel());
Utils.sendMessage(user, user.getTranslation("challenges.errors.no-challenges-admin", Utils.sendMessage(user, this.getWorld(), Constants.ERRORS + "no-challenges-admin",
"[command]", "[command]",
topLabel + " " + this.<ChallengesAddon>getAddon().getChallengesSettings().getAdminMainCommand().split(" ")[0])); topLabel + " " + this.<ChallengesAddon>getAddon().getChallengesSettings().getAdminMainCommand().split(" ")[0]);
} }
else else
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.no-challenges")); Utils.sendMessage(user, this.getWorld(), Constants.ERRORS + "no-challenges");
} }
return false; return false;
@ -62,14 +63,14 @@ public class ChallengesPlayerCommand extends CompositeCommand
if (this.getIslands().getIsland(this.getWorld(), user) == null) if (this.getIslands().getIsland(this.getWorld(), user) == null)
{ {
// Do not open gui if there is no island for this player. // Do not open gui if there is no island for this player.
Utils.sendMessage(user, user.getTranslation("general.errors.no-island")); Utils.sendMessage(user, this.getWorld(), "general.errors.no-island");
return false; return false;
} else if (ChallengesAddon.CHALLENGES_WORLD_PROTECTION.isSetForWorld(this.getWorld()) && } else if (ChallengesAddon.CHALLENGES_WORLD_PROTECTION.isSetForWorld(this.getWorld()) &&
!this.getIslands().locationIsOnIsland(user.getPlayer(), user.getLocation())) !this.getIslands().locationIsOnIsland(user.getPlayer(), user.getLocation()))
{ {
// Do not open gui if player is not on the island, but challenges requires island for // Do not open gui if player is not on the island, but challenges requires island for
// completion. // completion.
Utils.sendMessage(user, user.getTranslation("challenges.errors.not-on-island")); Utils.sendMessage(user, this.getWorld(), Constants.ERRORS + "not-on-island");
return false; return false;
} }

View File

@ -11,6 +11,7 @@ import world.bentobox.bentobox.util.Util;
import world.bentobox.challenges.ChallengesAddon; import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.database.object.Challenge; import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.tasks.TryToComplete; import world.bentobox.challenges.tasks.TryToComplete;
import world.bentobox.challenges.utils.Constants;
import world.bentobox.challenges.utils.Utils; import world.bentobox.challenges.utils.Utils;
@ -54,7 +55,7 @@ public class CompleteChallengeCommand extends CompositeCommand
{ {
if (args.isEmpty()) if (args.isEmpty())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.no-name")); Utils.sendMessage(user, this.getWorld(), Constants.ERRORS + "no-name");
this.showHelp(this, user); this.showHelp(this, user);
return false; return false;
} }
@ -73,7 +74,7 @@ public class CompleteChallengeCommand extends CompositeCommand
if (!canMultipleTimes && count > 1) if (!canMultipleTimes && count > 1)
{ {
Utils.sendMessage(user, user.getTranslation("challenges.error.no-multiple-permission")); Utils.sendMessage(user, this.getWorld(), Constants.ERRORS + "no-multiple-permission");
count = 1; count = 1;
} }
@ -87,7 +88,7 @@ public class CompleteChallengeCommand extends CompositeCommand
} }
else else
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.unknown-challenge")); Utils.sendMessage(user, this.getWorld(), Constants.ERRORS + "unknown-challenge");
this.showHelp(this, user); this.showHelp(this, user);
return false; return false;
} }

View File

@ -53,7 +53,7 @@ public class ChallengesGlobalAdminCommand extends CompositeCommand
if (this.gameModeAddons.isEmpty()) if (this.gameModeAddons.isEmpty())
{ {
Utils.sendMessage(user, user.getTranslation(Constants.ERRORS + "not-hooked")); Utils.sendMessage(user, this.getWorld(), Constants.ERRORS + "not-hooked");
return false; return false;
} }
else if (this.gameModeAddons.size() == 1) else if (this.gameModeAddons.size() == 1)

View File

@ -56,7 +56,7 @@ public class CompleteCommand extends CompositeCommand
{ {
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.no-name")); Utils.sendMessage(user, this.getWorld(), Constants.ERRORS + "no-name");
} }
else else
{ {
@ -67,7 +67,7 @@ public class CompleteCommand extends CompositeCommand
{ {
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.missing-arguments")); Utils.sendMessage(user, this.getWorld(), Constants.ERRORS + "missing-arguments");
} }
else else
{ {
@ -82,9 +82,11 @@ public class CompleteCommand extends CompositeCommand
{ {
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("general.errors.unknown-player", Utils.sendMessage(user,
this.getWorld(),
"general.errors.unknown-player",
TextVariables.NAME, TextVariables.NAME,
args.get(0))); args.get(0));
} }
else else
{ {
@ -109,9 +111,11 @@ public class CompleteCommand extends CompositeCommand
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.completed", Utils.sendMessage(user,
this.getWorld(),
Constants.MESSAGES + "completed",
Constants.PARAMETER_NAME, challenge.getFriendlyName(), Constants.PARAMETER_NAME, challenge.getFriendlyName(),
Constants.PARAMETER_PLAYER, target.getName())); Constants.PARAMETER_PLAYER, target.getName());
} }
else else
{ {
@ -123,7 +127,9 @@ public class CompleteCommand extends CompositeCommand
{ {
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.already-completed")); Utils.sendMessage(user,
this.getWorld(),
Constants.MESSAGES + "already-completed");
} }
else else
{ {
@ -137,7 +143,9 @@ public class CompleteCommand extends CompositeCommand
{ {
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.unknown-challenge")); Utils.sendMessage(user,
this.getWorld(),
Constants.ERRORS + "unknown-challenge");
} }
else else
{ {

View File

@ -49,13 +49,13 @@ public class ReloadChallenges extends CompositeCommand
if (args.isEmpty()) if (args.isEmpty())
{ {
this.manager.load(); this.manager.load();
Utils.sendMessage(user, user.getTranslation("general.success")); Utils.sendMessage(user, this.getWorld(), "general.success");
return true; return true;
} }
else if (args.get(0).equalsIgnoreCase("hard")) else if (args.get(0).equalsIgnoreCase("hard"))
{ {
this.manager.reload(); this.manager.reload();
Utils.sendMessage(user, user.getTranslation("general.success")); Utils.sendMessage(user, this.getWorld(), "general.success");
return true; return true;
} }
else else

View File

@ -56,7 +56,7 @@ public class ResetCommand extends CompositeCommand
{ {
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.no-name")); Utils.sendMessage(user, this.getWorld(), Constants.ERRORS + "no-name");
} }
else else
{ {
@ -67,7 +67,7 @@ public class ResetCommand extends CompositeCommand
{ {
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.missing-arguments")); Utils.sendMessage(user, this.getWorld(), Constants.ERRORS + "missing-arguments");
} }
else else
{ {
@ -82,8 +82,11 @@ public class ResetCommand extends CompositeCommand
{ {
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("general.errors.unknown-player", Utils.sendMessage(user,
TextVariables.NAME, args.get(0))); this.getWorld(),
Constants.ERRORS + "unknown-player",
TextVariables.NAME,
args.get(0));
} }
else else
{ {
@ -102,8 +105,11 @@ public class ResetCommand extends CompositeCommand
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.reset-all", Utils.sendMessage(user,
Constants.PARAMETER_PLAYER, target.getName())); this.getWorld(),
Constants.MESSAGES + "reset-all",
Constants.PARAMETER_PLAYER,
target.getName());
} }
else else
{ {
@ -125,9 +131,11 @@ public class ResetCommand extends CompositeCommand
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.reset", Utils.sendMessage(user,
this.getWorld(),
Constants.MESSAGES + "reset",
Constants.PARAMETER_NAME, challenge.getFriendlyName(), Constants.PARAMETER_NAME, challenge.getFriendlyName(),
Constants.PARAMETER_PLAYER, target.getName())); Constants.PARAMETER_PLAYER, target.getName());
} }
else else
{ {
@ -139,7 +147,9 @@ public class ResetCommand extends CompositeCommand
{ {
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.not-completed")); Utils.sendMessage(user,
this.getWorld(),
Constants.MESSAGES + "not-completed");
} }
else else
{ {
@ -153,7 +163,9 @@ public class ResetCommand extends CompositeCommand
{ {
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.unknown-challenge")); Utils.sendMessage(user,
this.getWorld(),
Constants.ERRORS + "unknown-challenge");
} }
else else
{ {

View File

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

View File

@ -82,7 +82,11 @@ public class ChallengesImportManager
{ {
if (user != null) if (user != null)
{ {
Utils.sendMessage(user, user.getTranslation(Constants.ERRORS + "no-file", Constants.PARAMETER_FILE, file)); Utils.sendMessage(user,
world,
Constants.ERRORS + "no-file",
Constants.PARAMETER_FILE,
file);
} }
return; return;
@ -98,8 +102,11 @@ public class ChallengesImportManager
{ {
if (user != null) if (user != null)
{ {
Utils.sendMessage(user, user.getTranslation(Constants.ERRORS + "no-load", Utils.sendMessage(user,
Constants.PARAMETER_FILE, file, TextVariables.DESCRIPTION, e.getMessage())); world,
Constants.ERRORS + "no-load",
Constants.PARAMETER_FILE, file,
TextVariables.DESCRIPTION, e.getMessage());
} }
this.addon.logError("Exception when loading file. " + e.getMessage()); this.addon.logError("Exception when loading file. " + e.getMessage());
@ -114,8 +121,9 @@ public class ChallengesImportManager
if (user != null) if (user != null)
{ {
Utils.sendMessage(user, Utils.sendMessage(user,
user.getTranslation(Constants.ERRORS + "not-a-gamemode-world", world,
Constants.PARAMETER_WORLD, world.getName())); Constants.ERRORS + "not-a-gamemode-world",
Constants.PARAMETER_WORLD, world.getName());
} }
this.addon.logWarning("Given world is not a gamemode world."); this.addon.logWarning("Given world is not a gamemode world.");
@ -151,6 +159,7 @@ public class ChallengesImportManager
challengeCount = reader.getKeys(false).stream(). challengeCount = reader.getKeys(false).stream().
mapToInt(challengeId -> this.createChallenge(challengeId, mapToInt(challengeId -> this.createChallenge(challengeId,
prefix, prefix,
world,
reader.getConfigurationSection(challengeId))). reader.getConfigurationSection(challengeId))).
sum(); sum();
} }
@ -174,9 +183,10 @@ public class ChallengesImportManager
if (user != null) if (user != null)
{ {
Utils.sendMessage(user, Utils.sendMessage(user,
user.getTranslation(Constants.MESSAGES + "import-count", world,
"[levels]", String.valueOf(levelCount), Constants.MESSAGES + "import-count",
"[challenges]", String.valueOf(challengeCount))); "[levels]", String.valueOf(levelCount),
"[challenges]", String.valueOf(challengeCount));
} }
this.addon.log("Imported " + challengeCount + " challenges and " + this.addon.log("Imported " + challengeCount + " challenges and " +
@ -188,11 +198,13 @@ public class ChallengesImportManager
* This method creates challenge from given config section. * This method creates challenge from given config section.
* @param challengeId Challenge ID. * @param challengeId Challenge ID.
* @param prefix GameMode prefix. * @param prefix GameMode prefix.
* @param world world where challenge is created.
* @param section Configuration Section that contains information. * @param section Configuration Section that contains information.
* @return 1 if challenge is created, otherwise 0. * @return 1 if challenge is created, otherwise 0.
*/ */
private int createChallenge(String challengeId, private int createChallenge(String challengeId,
String prefix, String prefix,
World world,
@Nullable ConfigurationSection section) @Nullable ConfigurationSection section)
{ {
if (section == null) if (section == null)
@ -266,7 +278,7 @@ public class ChallengesImportManager
} }
this.addon.getChallengesManager().saveChallenge(challenge); this.addon.getChallengesManager().saveChallenge(challenge);
this.addon.getChallengesManager().loadChallenge(challenge, true, null, true); this.addon.getChallengesManager().loadChallenge(challenge, world, true, null, true);
} }
catch (Exception e) catch (Exception e)
{ {
@ -632,7 +644,7 @@ public class ChallengesImportManager
} }
this.addon.getChallengesManager().saveLevel(level); this.addon.getChallengesManager().saveLevel(level);
this.addon.getChallengesManager().loadLevel(level, true, null, true); this.addon.getChallengesManager().loadLevel(level, world,true, null, true);
} }
catch (Exception ignored) catch (Exception ignored)
{ {
@ -696,7 +708,7 @@ public class ChallengesImportManager
challenge.setLevel(uniqueIDPrefix + challenge.getLevel()); challenge.setLevel(uniqueIDPrefix + challenge.getLevel());
} }
// Load challenge in memory // Load challenge in memory
manager.loadChallenge(challenge, false, user, user == null); manager.loadChallenge(challenge, world, false, user, user == null);
}); });
downloadedChallenges.getLevelList().forEach(challengeLevel -> { downloadedChallenges.getLevelList().forEach(challengeLevel -> {
@ -709,7 +721,7 @@ public class ChallengesImportManager
map(challenge -> uniqueIDPrefix + challenge). map(challenge -> uniqueIDPrefix + challenge).
collect(Collectors.toSet())); collect(Collectors.toSet()));
// Load level in memory // Load level in memory
manager.loadLevel(challengeLevel, false, user, user == null); manager.loadLevel(challengeLevel, world, false, user, user == null);
}); });
} }
catch (Exception e) catch (Exception e)
@ -746,7 +758,7 @@ public class ChallengesImportManager
{ {
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.exist-challenges-or-levels")); Utils.sendMessage(user, world, Constants.ERRORS + "exist-challenges-or-levels");
} }
else else
{ {
@ -773,7 +785,7 @@ public class ChallengesImportManager
challenge.setLevel(uniqueIDPrefix + challenge.getLevel()); challenge.setLevel(uniqueIDPrefix + challenge.getLevel());
} }
// Load challenge in memory // Load challenge in memory
manager.loadChallenge(challenge, false, user, user == null); manager.loadChallenge(challenge, world, false, user, user == null);
}); });
downloadedChallenges.getLevelList().forEach(challengeLevel -> { downloadedChallenges.getLevelList().forEach(challengeLevel -> {
@ -786,7 +798,7 @@ public class ChallengesImportManager
map(challenge -> uniqueIDPrefix + challenge). map(challenge -> uniqueIDPrefix + challenge).
collect(Collectors.toSet())); collect(Collectors.toSet()));
// Load level in memory // Load level in memory
manager.loadLevel(challengeLevel, false, user, user == null); manager.loadLevel(challengeLevel, world, false, user, user == null);
}); });
} }
catch (Exception e) catch (Exception e)
@ -815,8 +827,9 @@ public class ChallengesImportManager
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, Utils.sendMessage(user,
user.getTranslation(Constants.ERRORS + "file-exist", world,
Constants.PARAMETER_FILE, fileName)); Constants.ERRORS + "file-exist",
Constants.PARAMETER_FILE, fileName);
} }
else else
{ {
@ -882,9 +895,10 @@ public class ChallengesImportManager
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, Utils.sendMessage(user,
user.getTranslation(Constants.ERRORS + "no-load", world,
Constants.PARAMETER_FILE, fileName, Constants.ERRORS + "no-load",
TextVariables.DESCRIPTION, e.getMessage())); Constants.PARAMETER_FILE, fileName,
TextVariables.DESCRIPTION, e.getMessage());
} }
this.addon.logError("Could not save json file: " + e.getMessage()); this.addon.logError("Could not save json file: " + e.getMessage());
@ -894,9 +908,10 @@ public class ChallengesImportManager
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, Utils.sendMessage(user,
user.getTranslation(Constants.CONVERSATIONS + "database-export-completed", world,
Constants.PARAMETER_WORLD, world.getName(), Constants.CONVERSATIONS + "database-export-completed",
Constants.PARAMETER_FILE, fileName)); Constants.PARAMETER_WORLD, world.getName(),
Constants.PARAMETER_FILE, fileName);
} }
else else
{ {

View File

@ -28,6 +28,7 @@ import world.bentobox.challenges.events.ChallengeCompletedEvent;
import world.bentobox.challenges.events.ChallengeResetAllEvent; import world.bentobox.challenges.events.ChallengeResetAllEvent;
import world.bentobox.challenges.events.ChallengeResetEvent; import world.bentobox.challenges.events.ChallengeResetEvent;
import world.bentobox.challenges.events.LevelCompletedEvent; import world.bentobox.challenges.events.LevelCompletedEvent;
import world.bentobox.challenges.utils.Constants;
import world.bentobox.challenges.utils.LevelStatus; import world.bentobox.challenges.utils.LevelStatus;
import world.bentobox.challenges.utils.Utils; import world.bentobox.challenges.utils.Utils;
@ -97,7 +98,6 @@ public class ChallengesManager
* String for free Challenge Level. * String for free Challenge Level.
*/ */
public static final String FREE = ""; public static final String FREE = "";
public static final String VALUE = "[value]";
public static final String USER_ID = "user-id"; public static final String USER_ID = "user-id";
public static final String CHALLENGE_ID = "challenge-id"; public static final String CHALLENGE_ID = "challenge-id";
public static final String ADMIN_ID = "admin-id"; public static final String ADMIN_ID = "admin-id";
@ -230,7 +230,7 @@ public class ChallengesManager
*/ */
private void loadChallenge(@NonNull Challenge challenge) private void loadChallenge(@NonNull Challenge challenge)
{ {
this.loadChallenge(challenge, true, null, true); this.loadChallenge(challenge, null, true, null, true);
} }
@ -244,9 +244,10 @@ public class ChallengesManager
* @return - true if imported * @return - true if imported
*/ */
public boolean loadChallenge(@Nullable Challenge challenge, public boolean loadChallenge(@Nullable Challenge challenge,
boolean overwrite, World world,
User user, boolean overwrite,
boolean silent) User user,
boolean silent)
{ {
// This may happen if database somehow failed to load challenge and return // This may happen if database somehow failed to load challenge and return
// null as input. // null as input.
@ -254,7 +255,10 @@ public class ChallengesManager
{ {
if (!silent) if (!silent)
{ {
Utils.sendMessage(user, user.getTranslation("load-error", "[value]", "NULL")); Utils.sendMessage(user,
world,
Constants.ERRORS + "load-error",
Constants.PARAMETER_VALUE, "NULL");
} }
return false; return false;
@ -264,8 +268,10 @@ public class ChallengesManager
{ {
if (!silent) if (!silent)
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.invalid-challenge", Utils.sendMessage(user,
"[challenge]", challenge.getUniqueId())); world,
Constants.ERRORS + "invalid-challenge",
Constants.PARAMETER_CHALLENGE, challenge.getUniqueId());
} }
this.addon.logWarning("Data for challenge `" + challenge.getUniqueId() + "` is not valid. It could be NULL element in item-stack!"); this.addon.logWarning("Data for challenge `" + challenge.getUniqueId() + "` is not valid. It could be NULL element in item-stack!");
@ -280,8 +286,10 @@ public class ChallengesManager
{ {
if (!silent) if (!silent)
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.load-skipping", Utils.sendMessage(user,
VALUE, challenge.getFriendlyName())); world,
Constants.MESSAGES + "load-skipping",
Constants.PARAMETER_VALUE, challenge.getFriendlyName());
} }
return false; return false;
@ -290,8 +298,10 @@ public class ChallengesManager
{ {
if (!silent) if (!silent)
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.load-overwriting", Utils.sendMessage(user,
VALUE, challenge.getFriendlyName())); world,
Constants.MESSAGES + "load-overwriting",
Constants.PARAMETER_VALUE, challenge.getFriendlyName());
} }
} }
} }
@ -299,8 +309,10 @@ public class ChallengesManager
{ {
if (!silent) if (!silent)
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.load-add", Utils.sendMessage(user,
VALUE, challenge.getFriendlyName())); world,
Constants.MESSAGES + "load-add",
Constants.PARAMETER_VALUE, challenge.getFriendlyName());
} }
} }
@ -316,7 +328,7 @@ public class ChallengesManager
*/ */
private void loadLevel(@NonNull ChallengeLevel level) private void loadLevel(@NonNull ChallengeLevel level)
{ {
this.loadLevel(level, true, null, true); this.loadLevel(level, null, true, null, true);
} }
@ -331,6 +343,7 @@ public class ChallengesManager
* @return boolean that indicate about load status. * @return boolean that indicate about load status.
*/ */
public boolean loadLevel(@Nullable ChallengeLevel level, public boolean loadLevel(@Nullable ChallengeLevel level,
World world,
boolean overwrite, boolean overwrite,
User user, User user,
boolean silent) boolean silent)
@ -341,7 +354,10 @@ public class ChallengesManager
{ {
if (!silent) if (!silent)
{ {
Utils.sendMessage(user, user.getTranslation("load-error", "[value]", "NULL")); Utils.sendMessage(user,
world,
Constants.ERRORS + "load-error",
Constants.PARAMETER_VALUE, "NULL");
} }
return false; return false;
@ -351,8 +367,10 @@ public class ChallengesManager
{ {
if (!silent) if (!silent)
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.invalid-level", Utils.sendMessage(user,
"[level]", level.getUniqueId())); world,
Constants.ERRORS + "invalid-level",
"[level]", level.getUniqueId());
} }
this.addon.logWarning("Data for level `" + level.getUniqueId() + "` is not valid. It could be NULL element in item-stack!"); this.addon.logWarning("Data for level `" + level.getUniqueId() + "` is not valid. It could be NULL element in item-stack!");
@ -363,8 +381,10 @@ public class ChallengesManager
{ {
if (user != null) if (user != null)
{ {
Utils.sendMessage(user, user.getTranslation("challenges.errors.load-error", Utils.sendMessage(user,
VALUE, level.getFriendlyName())); world,
Constants.ERRORS + "load-error",
Constants.PARAMETER_VALUE, level.getFriendlyName());
} }
else else
{ {
@ -380,8 +400,10 @@ public class ChallengesManager
{ {
if (!silent) if (!silent)
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.load-skipping", Utils.sendMessage(user,
VALUE, level.getFriendlyName())); world,
Constants.MESSAGES + "load-skipping",
Constants.PARAMETER_VALUE, level.getFriendlyName());
} }
return false; return false;
@ -390,8 +412,10 @@ public class ChallengesManager
{ {
if (!silent) if (!silent)
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.load-overwriting", Utils.sendMessage(user,
VALUE, level.getFriendlyName())); world,
Constants.MESSAGES + "load-overwriting",
Constants.PARAMETER_VALUE, level.getFriendlyName());
} }
} }
} }
@ -399,8 +423,10 @@ public class ChallengesManager
{ {
if (!silent) if (!silent)
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.load-add", Utils.sendMessage(user,
VALUE, level.getFriendlyName())); world,
Constants.MESSAGES + "load-add",
Constants.PARAMETER_VALUE, level.getFriendlyName());
} }
} }
@ -486,7 +512,7 @@ public class ChallengesManager
if (!this.challengeCacheData.containsKey(uniqueID)) if (!this.challengeCacheData.containsKey(uniqueID))
{ {
if (!this.challengeDatabase.objectExists(uniqueID) || if (!this.challengeDatabase.objectExists(uniqueID) ||
!this.loadChallenge(this.challengeDatabase.loadObject(uniqueID), false, null, true)) !this.loadChallenge(this.challengeDatabase.loadObject(uniqueID), Bukkit.getWorld(level.getWorld()), false, null, true))
{ {
this.addon.logError("Cannot find " + uniqueID + " challenge for " + level.getUniqueId()); this.addon.logError("Cannot find " + uniqueID + " challenge for " + level.getUniqueId());
return false; return false;
@ -640,7 +666,9 @@ public class ChallengesManager
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.migrate-start")); Utils.sendMessage(user,
world,
Constants.MESSAGES + "migrate-start");
} }
else else
{ {
@ -656,7 +684,9 @@ public class ChallengesManager
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.migrate-end")); Utils.sendMessage(user,
world,
Constants.MESSAGES + "migrate-end");
} }
else else
{ {
@ -667,7 +697,9 @@ public class ChallengesManager
{ {
if (user.isPlayer()) if (user.isPlayer())
{ {
Utils.sendMessage(user, user.getTranslation("challenges.messages.migrate-not")); Utils.sendMessage(user,
world,
Constants.MESSAGES + "migrate-not");
} }
else else
{ {
@ -1094,11 +1126,20 @@ public class ChallengesManager
// know how many challenges there were and how many has been done. Then // know how many challenges there were and how many has been done. Then
// remove waiver amount to get count of challenges that still necessary to do. // remove waiver amount to get count of challenges that still necessary to do.
List<Challenge> previousChallengeList = previousLevel == null ?
Collections.emptyList() :
this.getLevelChallenges(previousLevel);
int challengesToDo = previousLevel == null ? 0 : int challengesToDo = previousLevel == null ? 0 :
(previousLevel.getChallenges().size() - doneChallengeCount - previousLevel.getWaiverAmount()); (previousChallengeList.size() - doneChallengeCount - previousLevel.getWaiverAmount());
List<Challenge> challengeList = this.getLevelChallenges(level);
// As level already contains unique ids of challenges, just iterate through them. // As level already contains unique ids of challenges, just iterate through them.
doneChallengeCount = (int) level.getChallenges().stream().filter(playerData::isChallengeDone).count(); doneChallengeCount = (int) challengeList.stream().
map(Challenge::getUniqueId).
filter(playerData::isChallengeDone).
count();
// Mark if level is unlocked // Mark if level is unlocked
boolean unlocked = previousUnlocked && challengesToDo <= 0; boolean unlocked = previousUnlocked && challengesToDo <= 0;
@ -1107,7 +1148,7 @@ public class ChallengesManager
level, level,
previousLevel, previousLevel,
challengesToDo, challengesToDo,
level.getChallenges().size() == doneChallengeCount, challengeList.size() == doneChallengeCount,
unlocked)); unlocked));
previousLevel = level; previousLevel = level;
@ -1143,18 +1184,27 @@ public class ChallengesManager
{ {
ChallengeLevel previousLevel = levelIndex < 1 ? null : challengeLevelList.get(levelIndex - 1); ChallengeLevel previousLevel = levelIndex < 1 ? null : challengeLevelList.get(levelIndex - 1);
List<Challenge> previousChallengeList = previousLevel == null ? Collections.emptyList() :
this.getLevelChallenges(previousLevel);
int challengesToDo = previousLevel == null ? 0 : int challengesToDo = previousLevel == null ? 0 :
(previousLevel.getChallenges().size() - previousLevel.getWaiverAmount()) - (previousChallengeList.size() - previousLevel.getWaiverAmount()) -
(int) previousLevel.getChallenges().stream().filter(playerData::isChallengeDone).count(); (int) previousChallengeList.stream().map(Challenge::getUniqueId).
filter(playerData::isChallengeDone).count();
List<Challenge> challengeList = this.getLevelChallenges(level);
// As level already contains unique ids of challenges, just iterate through them. // As level already contains unique ids of challenges, just iterate through them.
int doneChallengeCount = (int) level.getChallenges().stream().filter(playerData::isChallengeDone).count(); int doneChallengeCount = (int) challengeList.stream().
map(Challenge::getUniqueId).
filter(playerData::isChallengeDone).
count();
return new LevelStatus( return new LevelStatus(
level, level,
previousLevel, previousLevel,
challengesToDo, challengesToDo,
level.getChallenges().size() == doneChallengeCount, challengeList.size() == doneChallengeCount,
challengesToDo <= 0); challengesToDo <= 0);
} }
} }
@ -1182,9 +1232,15 @@ public class ChallengesManager
{ {
this.addPlayerData(storageDataID); this.addPlayerData(storageDataID);
ChallengesPlayerData playerData = this.playerCacheData.get(storageDataID); ChallengesPlayerData playerData = this.playerCacheData.get(storageDataID);
long doneChallengeCount = level.getChallenges().stream().filter(playerData::isChallengeDone).count();
return level.getChallenges().size() == doneChallengeCount; List<Challenge> challengeList = this.getLevelChallenges(level);
long doneChallengeCount = challengeList.stream().
map(Challenge::getUniqueId).
filter(playerData::isChallengeDone).
count();
return challengeList.size() == doneChallengeCount;
} }
@ -1743,11 +1799,11 @@ public class ChallengesManager
{ {
// Free Challenges hides under FREE level. // Free Challenges hides under FREE level.
return this.islandWorldManager.getAddon(world).map(gameMode -> return this.islandWorldManager.getAddon(world).map(gameMode ->
this.challengeCacheData.values().stream(). this.challengeCacheData.values().stream().
filter(challenge -> challenge.getLevel().equals(FREE) && filter(challenge -> challenge.getLevel().equals(FREE) &&
challenge.matchGameMode(gameMode.getDescription().getName())). challenge.matchGameMode(gameMode.getDescription().getName())).
sorted(Comparator.comparing(Challenge::getOrder)). sorted(Comparator.comparing(Challenge::getOrder)).
collect(Collectors.toList())). collect(Collectors.toList())).
orElse(Collections.emptyList()); orElse(Collections.emptyList());
} }
@ -1758,10 +1814,24 @@ public class ChallengesManager
* @return List with challenges in given level. * @return List with challenges in given level.
*/ */
public List<Challenge> getLevelChallenges(ChallengeLevel level) public List<Challenge> getLevelChallenges(ChallengeLevel level)
{
return this.getLevelChallenges(level,
this.addon.getChallengesSettings().isIncludeUndeployed());
}
/**
* Level which challenges must be received
* @param level Challenge level.
* @param includeUndeployed if true, then include challenges that are not deployed.
* @return List with challenges in given level.
*/
public List<Challenge> getLevelChallenges(ChallengeLevel level, boolean includeUndeployed)
{ {
return level.getChallenges().stream(). return level.getChallenges().stream().
map(this::getChallenge). map(this::getChallenge).
filter(Objects::nonNull). filter(Objects::nonNull).
filter(challenge -> includeUndeployed || challenge.isDeployed()).
sorted(Comparator.comparing(Challenge::getOrder)). sorted(Comparator.comparing(Challenge::getOrder)).
collect(Collectors.toList()); collect(Collectors.toList());
} }
@ -1880,7 +1950,9 @@ public class ChallengesManager
*/ */
public int getChallengeCount(World world) public int getChallengeCount(World world)
{ {
return this.getAllChallenges(world).size(); return (int) this.getAllChallenges(world).stream().
filter(challenge -> this.settings.isIncludeUndeployed() || challenge.isDeployed()).
count();
} }

View File

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

View File

@ -7,12 +7,12 @@
package world.bentobox.challenges.panel; package world.bentobox.challenges.panel;
import org.apache.commons.lang.ArrayUtils;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.conversations.*; import org.bukkit.conversations.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
@ -65,7 +65,7 @@ public class ConversationUtils
// Split and check if they exist in valid entries. // Split and check if they exist in valid entries.
String[] accepted = validEntry.toLowerCase().replaceAll("\\s", "").split(","); String[] accepted = validEntry.toLowerCase().replaceAll("\\s", "").split(",");
return ArrayUtils.contains(accepted, input.toLowerCase()); return Arrays.asList(accepted).contains(input.toLowerCase());
} }
@ -81,7 +81,7 @@ public class ConversationUtils
{ {
String validEntry = user.getTranslation(Constants.CONVERSATIONS + "confirm-string").toLowerCase(); String validEntry = user.getTranslation(Constants.CONVERSATIONS + "confirm-string").toLowerCase();
if (ArrayUtils.contains(validEntry.replaceAll("\\s", "").split(","), input.toLowerCase())) if (Arrays.asList(validEntry.replaceAll("\\s", "").split(",")).contains(input.toLowerCase()))
{ {
// Add answer to consumer. // Add answer to consumer.
consumer.accept(true); consumer.accept(true);
@ -432,7 +432,7 @@ public class ConversationUtils
toLowerCase().replaceAll("\\s", ""). toLowerCase().replaceAll("\\s", "").
split(","); split(",");
if (input != null && ArrayUtils.contains(exit, input.toLowerCase())) if (input != null && Arrays.asList(exit).contains(input.toLowerCase()))
{ {
return messagePrompt; return messagePrompt;
} }

View File

@ -156,7 +156,7 @@ public class EditChallengePanel extends CommonPanel
// This will ensure that all main things will be always stored // This will ensure that all main things will be always stored
this.addon.getChallengesManager().saveChallenge(this.challenge); this.addon.getChallengesManager().saveChallenge(this.challenge);
// If for some reason challenge is not loaded, do it. // If for some reason challenge is not loaded, do it.
this.addon.getChallengesManager().loadChallenge(this.challenge, false, null, true); this.addon.getChallengesManager().loadChallenge(this.challenge, this.world,false, null, true);
panelBuilder.build(); panelBuilder.build();
} }
@ -445,8 +445,10 @@ public class EditChallengePanel extends CommonPanel
else else
{ {
Utils.sendMessage(this.user, Utils.sendMessage(this.user,
this.user.getTranslation(Constants.CONVERSATIONS + "invalid-challenge", this.world,
"[challenge]", this.challenge.getFriendlyName())); Constants.CONVERSATIONS + "invalid-challenge",
Constants.PARAMETER_CHALLENGE,
this.challenge.getFriendlyName());
this.challenge.setDeployed(false); this.challenge.setDeployed(false);
} }

View File

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

View File

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

View File

@ -166,8 +166,9 @@ public class LibraryPanel extends CommonPagedPanel<LibraryEntry>
{ {
if (this.libraryEntries.isEmpty()) if (this.libraryEntries.isEmpty())
{ {
Utils.sendMessage(this.user, this.user.getTranslation( Utils.sendMessage(this.user,
Constants.ERRORS + "no-library-entries")); this.world,
Constants.ERRORS + "no-library-entries");
return; return;
} }
@ -311,8 +312,9 @@ public class LibraryPanel extends CommonPagedPanel<LibraryEntry>
{ {
this.blockedForDownland = true; this.blockedForDownland = true;
Utils.sendMessage(this.user, this.user.getTranslation( Utils.sendMessage(this.user,
Constants.MESSAGES + "start-downloading")); this.world,
Constants.MESSAGES + "start-downloading");
// Run download task after 5 ticks. // Run download task after 5 ticks.
this.updateTask = this.addon.getPlugin().getServer().getScheduler(). this.updateTask = this.addon.getPlugin().getServer().getScheduler().

View File

@ -77,7 +77,7 @@ public class ChallengesPanel extends CommonPanel
if (!this.containsChallenges) if (!this.containsChallenges)
{ {
this.addon.logError("There are no challenges set up!"); this.addon.logError("There are no challenges set up!");
Utils.sendMessage(user, user.getTranslation(Constants.ERRORS + "no-challenges")); Utils.sendMessage(this.user, this.world, Constants.ERRORS + "no-challenges");
return; return;
} }
@ -130,7 +130,7 @@ public class ChallengesPanel extends CommonPanel
{ {
if (this.lastSelectedLevel != null) if (this.lastSelectedLevel != null)
{ {
this.challengeList = this.manager.getLevelChallenges(this.lastSelectedLevel.getLevel()); this.challengeList = this.manager.getLevelChallenges(this.lastSelectedLevel.getLevel(), true);
if (this.addon.getChallengesSettings().isRemoveCompleteOneTimeChallenges()) if (this.addon.getChallengesSettings().isRemoveCompleteOneTimeChallenges())
{ {

View File

@ -265,18 +265,21 @@ public class TryToComplete
// Send message about first completion only if it is completed only once. // Send message about first completion only if it is completed only once.
if (result.getFactor() == 1) if (result.getFactor() == 1)
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.messages.you-completed-challenge", Utils.sendMessage(this.user,
"[value]", this.challenge.getFriendlyName())); this.world,
Constants.MESSAGES + "you-completed-challenge",
Constants.PARAMETER_VALUE, this.challenge.getFriendlyName());
} }
if (this.addon.getChallengesSettings().isBroadcastMessages()) if (this.addon.getChallengesSettings().isBroadcastMessages())
{ {
Bukkit.getOnlinePlayers().stream(). Bukkit.getOnlinePlayers().stream().
map(User::getInstance). map(User::getInstance).
forEach(user -> Utils.sendMessage(user, user.getTranslation( forEach(user -> Utils.sendMessage(user,
"challenges.messages.name-has-completed-challenge", this.world,
Constants.MESSAGES + "name-has-completed-challenge",
Constants.PARAMETER_NAME, this.user.getName(), Constants.PARAMETER_NAME, this.user.getName(),
"[value]", this.challenge.getFriendlyName()))); Constants.PARAMETER_VALUE, this.challenge.getFriendlyName()));
} }
// sends title to player on challenge completion // sends title to player on challenge completion
@ -327,14 +330,18 @@ public class TryToComplete
if (result.getFactor() > 1) if (result.getFactor() > 1)
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.messages.you-repeated-challenge-multiple", Utils.sendMessage(this.user,
"[value]", this.challenge.getFriendlyName(), this.world,
"[count]", Integer.toString(result.getFactor()))); Constants.MESSAGES + "you-repeated-challenge-multiple",
Constants.PARAMETER_VALUE, this.challenge.getFriendlyName(),
"[count]", Integer.toString(result.getFactor()));
} }
else else
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.messages.you-repeated-challenge", Utils.sendMessage(this.user,
"[value]", this.challenge.getFriendlyName())); this.world,
Constants.MESSAGES + "you-repeated-challenge",
Constants.PARAMETER_VALUE, this.challenge.getFriendlyName());
} }
} }
@ -372,17 +379,20 @@ public class TryToComplete
// Run commands // Run commands
this.runCommands(level.getRewardCommands()); this.runCommands(level.getRewardCommands());
Utils.sendMessage(this.user, this.user.getTranslation("challenges.messages.you-completed-level", Utils.sendMessage(this.user,
"[value]", level.getFriendlyName())); this.world,
Constants.MESSAGES + "you-completed-level",
Constants.PARAMETER_VALUE, level.getFriendlyName());
if (this.addon.getChallengesSettings().isBroadcastMessages()) if (this.addon.getChallengesSettings().isBroadcastMessages())
{ {
Bukkit.getOnlinePlayers().stream(). Bukkit.getOnlinePlayers().stream().
map(User::getInstance). map(User::getInstance).
forEach(user -> Utils.sendMessage(user, user.getTranslation( forEach(user -> Utils.sendMessage(user,
"challenges.messages.name-has-completed-level", this.world,
Constants.MESSAGES + "name-has-completed-level",
Constants.PARAMETER_NAME, this.user.getName(), Constants.PARAMETER_NAME, this.user.getName(),
"[value]", level.getFriendlyName()))); Constants.PARAMETER_VALUE, level.getFriendlyName()));
} }
this.manager.setLevelComplete(this.user, this.world, level); this.manager.setLevelComplete(this.user, this.world, level);
@ -447,7 +457,8 @@ public class TryToComplete
if (sumEverything != removedAmount) if (sumEverything != removedAmount)
{ {
Utils.sendMessage(this.user, Utils.sendMessage(this.user,
this.user.getTranslation("challenges.errors.cannot-remove-items")); this.world,
Constants.ERRORS + "cannot-remove-items");
result.removedItems = removedItems; result.removedItems = removedItems;
result.meetsRequirements = false; result.meetsRequirements = false;
@ -495,45 +506,54 @@ public class TryToComplete
} }
} }
case ITEM, BLOCK -> { case ITEM, BLOCK -> {
int statistic = this.user.getPlayer().getStatistic(requirements.getStatistic());
if (requirements.getMaterial() == null) if (requirements.getMaterial() == null)
{ {
// Just a sanity check. Material cannot be null at this point of code. // Just a sanity check. Material cannot be null at this point of code.
removeAmount = 0; removeAmount = 0;
} }
else if (removeAmount >= statistic)
{
this.user.getPlayer().setStatistic(requirements.getStatistic(), requirements.getMaterial(), 0);
removeAmount -= statistic;
}
else else
{ {
this.user.getPlayer().setStatistic(requirements.getStatistic(), int statistic = this.user.getPlayer().getStatistic(requirements.getStatistic(),
requirements.getMaterial(), requirements.getMaterial());
statistic - removeAmount);
removeAmount = 0; if (removeAmount >= statistic)
{
this.user.getPlayer()
.setStatistic(requirements.getStatistic(), requirements.getMaterial(), 0);
removeAmount -= statistic;
}
else
{
this.user.getPlayer().setStatistic(requirements.getStatistic(),
requirements.getMaterial(),
statistic - removeAmount);
removeAmount = 0;
}
} }
} }
case ENTITY -> { case ENTITY -> {
int statistic = this.user.getPlayer().getStatistic(requirements.getStatistic());
if (requirements.getEntity() == null) if (requirements.getEntity() == null)
{ {
// Just a sanity check. Entity cannot be null at this point of code. // Just a sanity check. Entity cannot be null at this point of code.
removeAmount = 0; removeAmount = 0;
} }
else if (removeAmount >= statistic)
{
this.user.getPlayer().setStatistic(requirements.getStatistic(), requirements.getEntity(), 0);
removeAmount -= statistic;
}
else else
{ {
this.user.getPlayer().setStatistic(requirements.getStatistic(), int statistic = this.user.getPlayer().getStatistic(requirements.getStatistic(),
requirements.getEntity(), requirements.getEntity());
statistic - removeAmount);
removeAmount = 0; if (removeAmount >= statistic)
{
this.user.getPlayer().setStatistic(requirements.getStatistic(), requirements.getEntity(), 0);
removeAmount -= statistic;
}
else
{
this.user.getPlayer().setStatistic(requirements.getStatistic(),
requirements.getEntity(),
statistic - removeAmount);
removeAmount = 0;
}
} }
} }
} }
@ -577,45 +597,57 @@ public class TryToComplete
} }
} }
case ITEM, BLOCK -> { case ITEM, BLOCK -> {
int statistic = player.getStatistic(requirements.getStatistic());
if (requirements.getMaterial() == null) if (requirements.getMaterial() == null)
{ {
// Just a sanity check. Entity cannot be null at this point of code. // Just a sanity check. Entity cannot be null at this point of code.
removeAmount = 0; removeAmount = 0;
} }
else if (removeAmount >= statistic)
{
removeAmount -= statistic;
player.setStatistic(requirements.getStatistic(), requirements.getMaterial(), 0);
}
else else
{ {
player.setStatistic(requirements.getStatistic(), int statistic = player.getStatistic(requirements.getStatistic(),
requirements.getMaterial(), requirements.getMaterial());
statistic - removeAmount);
removeAmount = 0; if (removeAmount >= statistic)
{
removeAmount -= statistic;
player.setStatistic(requirements.getStatistic(),
requirements.getMaterial(),
0);
}
else
{
player.setStatistic(requirements.getStatistic(),
requirements.getMaterial(),
statistic - removeAmount);
removeAmount = 0;
}
} }
} }
case ENTITY -> { case ENTITY -> {
int statistic = player.getStatistic(requirements.getStatistic());
if (requirements.getEntity() == null) if (requirements.getEntity() == null)
{ {
// Just a sanity check. Entity cannot be null at this point of code. // Just a sanity check. Entity cannot be null at this point of code.
removeAmount = 0; removeAmount = 0;
} }
else if (removeAmount >= statistic)
{
removeAmount -= statistic;
player.setStatistic(requirements.getStatistic(), requirements.getEntity(), 0);
}
else else
{ {
player.setStatistic(requirements.getStatistic(), int statistic = player.getStatistic(requirements.getStatistic(),
requirements.getEntity(), requirements.getEntity());
statistic - removeAmount);
removeAmount = 0; if (removeAmount >= statistic)
{
removeAmount -= statistic;
player.setStatistic(requirements.getStatistic(),
requirements.getEntity(),
0);
}
else
{
player.setStatistic(requirements.getStatistic(),
requirements.getEntity(),
statistic - removeAmount);
removeAmount = 0;
}
} }
} }
} }
@ -640,18 +672,18 @@ public class TryToComplete
// Check the world // Check the world
if (!this.challenge.isDeployed()) if (!this.challenge.isDeployed())
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-deployed")); Utils.sendMessage(this.user, this.world, Constants.ERRORS + "not-deployed");
result = EMPTY_RESULT; result = EMPTY_RESULT;
} }
else if (maxTimes < 1) else if (maxTimes < 1)
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-valid-integer")); Utils.sendMessage(this.user, this.world, Constants.ERRORS + "not-valid-integer");
result = EMPTY_RESULT; result = EMPTY_RESULT;
} }
else if (Util.getWorld(this.world) != Util.getWorld(this.user.getWorld()) || else if (Util.getWorld(this.world) != Util.getWorld(this.user.getWorld()) ||
!this.challenge.matchGameMode(Utils.getGameMode(this.world))) !this.challenge.matchGameMode(Utils.getGameMode(this.world)))
{ {
Utils.sendMessage(this.user, this.user.getTranslation("general.errors.wrong-world")); Utils.sendMessage(this.user, this.world, "general.errors.wrong-world");
result = EMPTY_RESULT; result = EMPTY_RESULT;
} }
// Player is not on island // Player is not on island
@ -659,7 +691,7 @@ public class TryToComplete
ChallengesAddon.CHALLENGES_WORLD_PROTECTION.isSetForWorld(this.world) && ChallengesAddon.CHALLENGES_WORLD_PROTECTION.isSetForWorld(this.world) &&
!this.addon.getIslands().locationIsOnIsland(this.user.getPlayer(), this.user.getLocation())) !this.addon.getIslands().locationIsOnIsland(this.user.getPlayer(), this.user.getLocation()))
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-on-island")); Utils.sendMessage(this.user, this.world, Constants.MESSAGES + "not-on-island");
result = EMPTY_RESULT; result = EMPTY_RESULT;
} }
// Check player permission // Check player permission
@ -667,27 +699,27 @@ public class TryToComplete
map(i -> i.isAllowed(this.user, ChallengesAddon.CHALLENGES_ISLAND_PROTECTION)). map(i -> i.isAllowed(this.user, ChallengesAddon.CHALLENGES_ISLAND_PROTECTION)).
orElse(false)) orElse(false))
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.no-rank")); Utils.sendMessage(this.user, this.world, Constants.MESSAGES + "no-rank");
result = EMPTY_RESULT; result = EMPTY_RESULT;
} }
// Check if user has unlocked challenges level. // Check if user has unlocked challenges level.
else if (!this.challenge.getLevel().equals(ChallengesManager.FREE) && else if (!this.challenge.getLevel().equals(ChallengesManager.FREE) &&
!this.manager.isLevelUnlocked(this.user, this.world, this.manager.getLevel(this.challenge.getLevel()))) !this.manager.isLevelUnlocked(this.user, this.world, this.manager.getLevel(this.challenge.getLevel())))
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.challenge-level-not-available")); Utils.sendMessage(this.user, this.world, Constants.ERRORS + "challenge-level-not-available");
result = EMPTY_RESULT; result = EMPTY_RESULT;
} }
// Check max times // Check max times
else if (this.challenge.isRepeatable() && this.challenge.getMaxTimes() > 0 && else if (this.challenge.isRepeatable() && this.challenge.getMaxTimes() > 0 &&
this.manager.getChallengeTimes(this.user, this.world, this.challenge) >= this.challenge.getMaxTimes()) this.manager.getChallengeTimes(this.user, this.world, this.challenge) >= this.challenge.getMaxTimes())
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-repeatable")); Utils.sendMessage(this.user, this.world, Constants.ERRORS + "not-repeatable");
result = EMPTY_RESULT; result = EMPTY_RESULT;
} }
// Check repeatability // Check repeatability
else if (!this.challenge.isRepeatable() && this.manager.isChallengeComplete(this.user, this.world, this.challenge)) else if (!this.challenge.isRepeatable() && this.manager.isChallengeComplete(this.user, this.world, this.challenge))
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-repeatable")); Utils.sendMessage(this.user, this.world, Constants.ERRORS + "not-repeatable");
result = EMPTY_RESULT; result = EMPTY_RESULT;
} }
// Check if timeout is not broken // Check if timeout is not broken
@ -696,22 +728,22 @@ public class TryToComplete
long missing = this.manager.getLastCompletionDate(this.user, this.world, challenge) + long missing = this.manager.getLastCompletionDate(this.user, this.world, challenge) +
this.challenge.getTimeout() - System.currentTimeMillis(); this.challenge.getTimeout() - System.currentTimeMillis();
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.timeout", Utils.sendMessage(this.user, this.world, Constants.ERRORS + "timeout",
"[timeout]", Utils.parseDuration(Duration.ofMillis(this.challenge.getTimeout()), this.user), "[timeout]", Utils.parseDuration(Duration.ofMillis(this.challenge.getTimeout()), this.user),
"[wait-time]", Utils.parseDuration(Duration.ofMillis(missing), this.user))); "[wait-time]", Utils.parseDuration(Duration.ofMillis(missing), this.user));
result = EMPTY_RESULT; result = EMPTY_RESULT;
} }
// Check environment // Check environment
else if (!this.challenge.getEnvironment().isEmpty() && else if (!this.challenge.getEnvironment().isEmpty() &&
!this.challenge.getEnvironment().contains(this.user.getWorld().getEnvironment())) !this.challenge.getEnvironment().contains(this.user.getWorld().getEnvironment()))
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.wrong-environment")); Utils.sendMessage(this.user, this.world, Constants.ERRORS + "wrong-environment");
result = EMPTY_RESULT; result = EMPTY_RESULT;
} }
// Check permission // Check permission
else if (!this.checkPermissions()) else if (!this.checkPermissions())
{ {
Utils.sendMessage(this.user, this.user.getTranslation("general.errors.no-permission")); Utils.sendMessage(this.user, this.world, Constants.ERRORS + "no-permission");
result = EMPTY_RESULT; result = EMPTY_RESULT;
} }
else if (type.equals(ChallengeType.INVENTORY_TYPE)) else if (type.equals(ChallengeType.INVENTORY_TYPE))
@ -806,9 +838,9 @@ public class TryToComplete
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). cmd = cmd.substring(6).
replaceAll(Constants.PARAMETER_PLAYER, this.user.getName()). replaceAll(Constants.ESC + Constants.PARAMETER_PLAYER, this.user.getName()).
replaceAll(Constants.PARAMETER_OWNER, owner). replaceAll(Constants.ESC + Constants.PARAMETER_OWNER, owner).
replaceAll(Constants.PARAMETER_NAME, island == null || island.getName() == null ? "" : island.getName()). replaceAll(Constants.ESC + Constants.PARAMETER_NAME, island == null || island.getName() == null ? "" : island.getName()).
trim(); trim();
try try
{ {
@ -829,9 +861,9 @@ public class TryToComplete
try try
{ {
cmd = cmd.replaceAll(Constants.PARAMETER_PLAYER, this.user.getName()). cmd = cmd.replaceAll(Constants.ESC + Constants.PARAMETER_PLAYER, this.user.getName()).
replaceAll(Constants.PARAMETER_OWNER, owner). replaceAll(Constants.ESC + Constants.PARAMETER_OWNER, owner).
replaceAll(Constants.PARAMETER_NAME, island == null || island.getName() == null ? "" : island.getName()). replaceAll(Constants.ESC + Constants.PARAMETER_NAME, island == null || island.getName() == null ? "" : island.getName()).
trim(); trim();
if (!this.addon.getServer().dispatchCommand(this.addon.getServer().getConsoleSender(), cmd)) if (!this.addon.getServer().dispatchCommand(this.addon.getServer().getConsoleSender(), cmd))
@ -908,9 +940,9 @@ public class TryToComplete
if (numInInventory < required.getAmount()) if (numInInventory < required.getAmount())
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-enough-items", Utils.sendMessage(this.user, this.world, Constants.ERRORS + "not-enough-items",
"[items]", "[items]",
Utils.prettifyObject(required, this.user))); Utils.prettifyObject(required, this.user));
return EMPTY_RESULT; return EMPTY_RESULT;
} }
@ -1173,13 +1205,16 @@ public class TryToComplete
return new ChallengeResult().setMeetsRequirements().setCompleteFactor(factor).setBlockQueue(blockFromWorld); return new ChallengeResult().setMeetsRequirements().setCompleteFactor(factor).setBlockQueue(blockFromWorld);
} }
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-close-enough", Utils.sendMessage(this.user,
"[number]", String.valueOf(this.getIslandRequirements().getSearchRadius()))); this.world,
Constants.ERRORS + "not-close-enough",
Constants.PARAMETER_NUMBER, String.valueOf(this.getIslandRequirements().getSearchRadius()));
blocks.forEach((k, v) -> Utils.sendMessage(this.user, blocks.forEach((k, v) -> Utils.sendMessage(this.user,
this.user.getTranslation("challenges.errors.you-still-need", this.world,
"[amount]", String.valueOf(v), Constants.ERRORS + "you-still-need",
"[item]", Utils.prettifyObject(k, this.user)))); "[amount]", String.valueOf(v),
"[item]", Utils.prettifyObject(k, this.user)));
// kick garbage collector // kick garbage collector
@ -1259,9 +1294,11 @@ public class TryToComplete
} }
minimalRequirements.forEach((reqEnt, amount) -> minimalRequirements.forEach((reqEnt, amount) ->
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.you-still-need", Utils.sendMessage(this.user,
this.world,
Constants.ERRORS + "you-still-need",
"[amount]", String.valueOf(amount), "[amount]", String.valueOf(amount),
"[item]", Utils.prettifyObject(reqEnt, this.user)))); "[item]", Utils.prettifyObject(reqEnt, this.user)));
// Kick garbage collector // Kick garbage collector
entitiesFound.clear(); entitiesFound.clear();
@ -1342,42 +1379,47 @@ public class TryToComplete
if (!this.addon.isLevelProvided() && requirements.getRequiredIslandLevel() != 0) if (!this.addon.isLevelProvided() && requirements.getRequiredIslandLevel() != 0)
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.missing-addon")); Utils.sendMessage(this.user, this.world, Constants.ERRORS + "missing-addon");
} }
else if (!this.addon.isEconomyProvided() && else if (!this.addon.isEconomyProvided() &&
requirements.getRequiredMoney() != 0) requirements.getRequiredMoney() != 0)
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.missing-addon")); Utils.sendMessage(this.user, this.world, Constants.ERRORS + "missing-addon");
} }
else if (this.addon.isEconomyProvided() && requirements.getRequiredMoney() < 0) else if (this.addon.isEconomyProvided() && requirements.getRequiredMoney() < 0)
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.incorrect")); Utils.sendMessage(this.user, this.world, Constants.ERRORS + "incorrect");
} }
else if (this.addon.isEconomyProvided() && else if (this.addon.isEconomyProvided() &&
!this.addon.getEconomyProvider().has(this.user, requirements.getRequiredMoney())) !this.addon.getEconomyProvider().has(this.user, requirements.getRequiredMoney()))
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-enough-money", Utils.sendMessage(this.user,
"[value]", this.world,
Double.toString(requirements.getRequiredMoney()))); Constants.ERRORS + "not-enough-money",
Constants.PARAMETER_VALUE, Double.toString(requirements.getRequiredMoney()));
} }
else if (requirements.getRequiredExperience() < 0) else if (requirements.getRequiredExperience() < 0)
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.incorrect")); Utils.sendMessage(this.user, this.world, Constants.ERRORS + "incorrect");
} }
else if (this.user.getPlayer().getTotalExperience() < requirements.getRequiredExperience() && else if (this.user.getPlayer().getTotalExperience() < requirements.getRequiredExperience() &&
this.user.getPlayer().getGameMode() != GameMode.CREATIVE) this.user.getPlayer().getGameMode() != GameMode.CREATIVE)
{ {
// Players in creative gamemode has infinite amount of EXP. // Players in creative gamemode has infinite amount of EXP.
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-enough-experience", Utils.sendMessage(this.user,
"[value]", this.world,
Integer.toString(requirements.getRequiredExperience()))); Constants.ERRORS + "not-enough-experience",
Constants.PARAMETER_VALUE,
Integer.toString(requirements.getRequiredExperience()));
} }
else if (this.addon.isLevelProvided() && else if (this.addon.isLevelProvided() &&
this.addon.getLevelAddon().getIslandLevel(this.world, this.user.getUniqueId()) < requirements.getRequiredIslandLevel()) this.addon.getLevelAddon().getIslandLevel(this.world, this.user.getUniqueId()) < requirements.getRequiredIslandLevel())
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.island-level", Utils.sendMessage(this.user,
this.world,
Constants.ERRORS + "island-level",
TextVariables.NUMBER, TextVariables.NUMBER,
String.valueOf(requirements.getRequiredIslandLevel()))); String.valueOf(requirements.getRequiredIslandLevel()));
} }
else else
{ {
@ -1440,10 +1482,35 @@ public class TryToComplete
if (currentValue < requirements.getAmount()) if (currentValue < requirements.getAmount())
{ {
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.requirement-not-met", switch (Objects.requireNonNull(requirements.getStatistic()).getType())
TextVariables.NUMBER, String.valueOf(requirements.getAmount()), {
"[statistic]", Utils.prettifyObject(requirements.getStatistic(), this.user), case ITEM, BLOCK -> {
"[value]", String.valueOf(currentValue))); Utils.sendMessage(this.user,
this.world,
Constants.ERRORS + "requirement-not-met-material",
TextVariables.NUMBER, String.valueOf(requirements.getAmount()),
"[statistic]", Utils.prettifyObject(requirements.getStatistic(), this.user),
"[material]", Utils.prettifyObject(requirements.getMaterial(), this.user),
Constants.PARAMETER_VALUE, String.valueOf(currentValue));
}
case ENTITY -> {
Utils.sendMessage(this.user,
this.world,
Constants.ERRORS + "requirement-not-met-entity",
TextVariables.NUMBER, String.valueOf(requirements.getAmount()),
"[statistic]", Utils.prettifyObject(requirements.getStatistic(), this.user),
"[entity]", Utils.prettifyObject(requirements.getEntity(), this.user),
Constants.PARAMETER_VALUE, String.valueOf(currentValue));
}
default -> {
Utils.sendMessage(this.user,
this.world,
Constants.ERRORS + "requirement-not-met",
TextVariables.NUMBER, String.valueOf(requirements.getAmount()),
"[statistic]", Utils.prettifyObject(requirements.getStatistic(), this.user),
Constants.PARAMETER_VALUE, String.valueOf(currentValue));
}
}
} }
else else
{ {

View File

@ -223,4 +223,9 @@ public class Constants
* Reference string to challenge parameter in translations. * Reference string to challenge parameter in translations.
*/ */
public static final String PARAMETER_CHALLENGE = "[challenge]"; public static final String PARAMETER_CHALLENGE = "[challenge]";
/**
* Regex escape chars.
*/
public static final String ESC = "\\";
} }

View File

@ -186,11 +186,14 @@ public class Utils
* Send given message to user and add prefix to the start of the message. * Send given message to user and add prefix to the start of the message.
* *
* @param user User who need to receive message. * @param user User who need to receive message.
* @param message String of message that must be send. * @param world Reference to world where message must be send.
* @param translation String of message that must be send.
* @param parameters Parameters that must be added to translation.
*/ */
public static void sendMessage(User user, String message) public static void sendMessage(User user, World world, String translation, String... parameters)
{ {
user.sendMessage(user.getTranslation(Constants.CONVERSATIONS + "prefix") + message); user.sendMessage(user.getTranslation(world, Constants.CONVERSATIONS + "prefix") +
user.getTranslation(world, translation, parameters));
} }

View File

@ -683,6 +683,15 @@ challenges:
visible: "Show visible challenges" visible: "Show visible challenges"
hidden: "Show all challenges" hidden: "Show all challenges"
toggleable: "Allow toggling" toggleable: "Allow toggling"
include_undeployed:
name: "&f&l Include Undeployed Challenges"
description: |-
&7 Indicates if undeployed
&7 challenges should be
&7 counted towards level
&7 completion.
enabled: "&2 Enabled"
disabled: "&c Disabled"
download: download:
name: "&f&l Download Libraries" name: "&f&l Download Libraries"
description: |- description: |-
@ -1204,6 +1213,8 @@ challenges:
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]. " requirement-not-met: "&c This challenge requires [statistic] to have [number]. You have only [value]. "
requirement-not-met-entity: "&c This challenge requires [statistic] [entity] to have [number]. You have only [value]. "
requirement-not-met-material: "&c This challenge requires [statistic] [material] 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.

View File

@ -2,6 +2,9 @@
meta: meta:
authors: authors:
- BONNe - BONNe
# Attention for Chinese translation
# 中文翻译须知在本人2023年1月19日接手前上一位翻译者疑似用机翻软件翻译了全文包括变量在内的所有文字。
# 感谢原作者BONNe进行了修改同时笔者对管理员部分的翻译和玩家全部的翻译进行了订正。时间仓促请君斧正。
challenges: challenges:
commands: commands:
admin: admin:
@ -33,14 +36,14 @@ challenges:
gamemode-gui: "&0&l 选择游戏模式" gamemode-gui: "&0&l 选择游戏模式"
multiple-gui: "&0&l 多少次?" multiple-gui: "&0&l 多少次?"
admin-gui: "&0&l 挑战管理菜单" admin-gui: "&0&l 挑战管理菜单"
edit-challenge: "&0&l 编辑 [挑战]" edit-challenge: "&0&l 编辑 [challenge]"
edit-level: "&0&l 编辑 [等级]" edit-level: "&0&l 编辑 [level]"
settings: "&0&l 设置" settings: "&0&l 设置"
choose-challenge: "&0&l 选择挑战" choose-challenge: "&0&l 选择挑战"
choose-level: "&0&l 选择级别" choose-level: "&0&l 选择级别"
choose-player: "&0&l 选择播放器" choose-player: "&0&l 选择玩家"
library: "&0&l 库" library: "&0&l 库"
manage-blocks: "&0&l 管理块" manage-blocks: "&0&l 管理块"
manage-entities: "&0&l 管理实体" manage-entities: "&0&l 管理实体"
type-selector: "&0&l 挑战类型选择器" type-selector: "&0&l 挑战类型选择器"
item-selector: "&0&l 项目选择器" item-selector: "&0&l 项目选择器"
@ -51,10 +54,10 @@ challenges:
environment-selector: "&0&l 环境选择器" environment-selector: "&0&l 环境选择器"
buttons: buttons:
free-challenges: free-challenges:
name: "&f&l 免费挑战" name: "&f&l 自由挑战"
description: |- description: |-
&7 显示列表 &7 显示列表
&7 免费挑战 &7 自由挑战
return: return:
name: "&f&l 返回" name: "&f&l 返回"
description: |- description: |-
@ -62,20 +65,20 @@ challenges:
&7 或退出 GUI &7 或退出 GUI
previous: previous:
name: "&f&l 上一页" name: "&f&l 上一页"
description: "&7 切换到 &e [数字] &7 页面" description: "&7 切换到 &e [number] &7 页"
next: next:
name: "&f&l 下一页" name: "&f&l 下一页"
description: "&7 切换到 &e [数字] &7 页面" description: "&7 切换到 &e [number] &7 页"
reduce: reduce:
name: "&f&l 减少" name: "&f&l 减少"
description: "&7 减少 &e [数字]" description: "&7 减少 &e [number]"
increase: increase:
name: "&f&l 增加" name: "&f&l 增加"
description: "&7 增加 &e [数字]" description: "&7 增加 &e [number]"
accept: accept:
name: "&f&l 完成" name: "&f&l 完成"
description: |- description: |-
&7 完成挑战 &e [数字] &7 完成挑战 &e [number]
&7次(-s) &7次(-s)
quit: quit:
name: "&f&l 退出" name: "&f&l 退出"
@ -97,10 +100,10 @@ challenges:
&7 启动一个进程 &7 启动一个进程
&7 创造了一个新的挑战。 &7 创造了一个新的挑战。
add_level: add_level:
name: "&f&l 创建关卡" name: "&f&l 创建级别"
description: |- description: |-
&7 启动一个进程 &7 启动一个进程
&7 创造了一个新的水平 &7 创造了一个新的级别
edit_challenge: edit_challenge:
name: "&f&l 编辑挑战" name: "&f&l 编辑挑战"
description: |- description: |-
@ -117,7 +120,7 @@ challenges:
&7 允许选择和删除 &7 允许选择和删除
&7 挑战。 &7 挑战。
delete_level: delete_level:
name: "&f&l 删除级" name: "&f&l 删除"
description: |- description: |-
&7 允许选择和删除 &7 允许选择和删除
&7 一个级别。 &7 一个级别。
@ -146,7 +149,7 @@ challenges:
name: "&f&l 库" name: "&f&l 库"
description: |- description: |-
&7 打开公共 &7 打开公共
&7 挑战图书馆 &7 挑战
import_database: import_database:
name: "&f&l 导入数据库" name: "&f&l 导入数据库"
description: |- description: |-
@ -158,7 +161,7 @@ challenges:
&7 允许导入模板 &7 允许导入模板
&7 文件有挑战。 &7 文件有挑战。
export_challenges: export_challenges:
name: "&f&l 挑战" name: "&f&l 出挑战"
description: |- description: |-
&7 允许导出数据库 &7 允许导出数据库
&7 到本地文件。 &7 到本地文件。
@ -184,7 +187,7 @@ challenges:
description: |- description: |-
&7 允许更改 &7 允许更改
&7 显示名称。 &7 显示名称。
value: "&7 当前:&r [名称]" value: "&7 当前:&r [name]"
remove_on_complete: remove_on_complete:
name: "&f&l 完成后隐藏" name: "&f&l 完成后隐藏"
description: |- description: |-
@ -209,14 +212,14 @@ challenges:
enabled: "&2" enabled: "&2"
disabled: "C" disabled: "C"
order: order:
name: "&f&l 订单" name: "&f&l 顺序"
description: |- description: |-
&7 允许改变顺序 &7 允许改变顺序
&7 个对象。 &7 个对象。
&7 相同数量的对象 &7 相同数量的对象
&7 将由他们订购 &7 将由他们订购
&7 唯一 ID 名称。 &7 唯一 ID 名称。
value: "&7 当前订单:&e [数字]" value: "&7 当前顺序:&e [number]"
icon: icon:
name: "&f&l 图标" name: "&f&l 图标"
description: |- description: |-
@ -234,82 +237,83 @@ challenges:
&7 权限 &7 权限
&7 挑战是可完成的。 &7 挑战是可完成的。
title: "&7 权限:" title: "&7 权限:"
permission: " &8 - [权限]" permission: " &8 - [permission]"
none: "&7 权限未设置。" none: "&7 权限未设置。"
remove_entities: remove_entities:
name: "&f&l 删除实体" name: "&f&l 删除实体"
description: |- description: |-
&7 允许切换 &7 允许切换
&7 所需实体将 &7 所需要的
&7 从世界中移除 &7 在完成挑战
&7 完成 &7
&7 挑战。 &7 从世界中移除的实体
enabled: "&2 已启用" enabled: "&2 已启用"
disabled: "&c 已禁用" disabled: "&c 已禁用"
required_entities: required_entities:
name: "&f&l 必需的实体" name: "&f&l 必需的实体"
description: |- description: |-
&7 允许根据需要进行更改 &7 允许
&7 实体为此 &7 为完成这个挑战。
&7 挑战是可完成的。 &7 所需要的实体进行更改
title: "&7 实体:" title: "&7 实体:"
list: " &8 - [数字] x [实体]" list: " &8 - [number] x [entity]"
none: "&7 不添加实体。" none: "&7 不添加实体。"
remove_blocks: remove_blocks:
name: "&f&l 移除方块" name: "&f&l 移除方块"
description: |- description: |-
&7 允许切换 &7 允许切换
&7 所需块将 &7 所需
&7 从世界中移除 &7 在完成挑战
&7 完成 &7
&7 挑战。 &7 从世界中移除的方块
enabled: "&2 已启用" enabled: "&2 已启用"
disabled: "&c 已禁用" disabled: "&c 已禁用"
required_blocks: required_blocks:
name: "&f&l 所需块" name: "&f&l 所需块"
description: |- description: |-
&7 允许根据需要进行更改 &7 允许更改
&7 块为此 &7 为完成挑战所需要的
&7 挑战是可完成的。 &7 方块
title: "&7 块:" title: "&7 块:"
list: " &8 - [数量] x [块]" list: " &8 - [number] x [block]"
none: "&7 块不被添加。" none: "&7 块不被添加。"
search_radius: search_radius:
name: "&f&l 搜索半径" name: "&f&l 搜索半径"
description: |- description: |-
&7 允许改变半径 &7 允许更改任务所需的方块
&7 周围的玩家 &7 或实体的检测半径。
&7 块和/或实体是 &7 (部分任务需要玩家周围
&7 检测到。 &7 有一定数量的方块/实体)
value: "&7 当前距离:&e [数字]" value: "&7 当前距离:&e [number]"
remove_items: remove_items:
name: "&f&l 删除项目" name: "&f&l 删除道具"
description: |- description: |-
&7 允许切换 &7 允许切换
&7 项必填项 &7 挑战所需道具
&7 从库存中移除 &7 在挑战完成后
&7 完成后 &7 是否从背包中
&7 挑战 &7 移除
enabled: "&2 已启用" enabled: "&2 已启用"
disabled: "&c 已禁用" disabled: "&c 已禁用"
required_items: required_items:
name: "&f&l 必填项目" name: "&f&l 需求道具"
description: |- description: |-
&7 允许根据需要进行更改 &7 允许根据需要进行更改
&7 项为此 &7 项为此
&7 挑战是可完成的。 &7 挑战是可完成的。
title: "&7 项:" title: "&7 项:"
list: " &8 - [数量] x [项目]" list: " &8 - [number] x [item]"
none: "&7 项目未添加。" none: "&7 项目未添加。"
add_ignored_meta: add_ignored_meta:
name: "&f&l 添加忽略元数据" name: "&f&l 添加忽略元数据"
#翻译到这了下面的都是没有人工翻译的cirno看了也无语
description: |- description: |-
&7 允许添加哪个 &7 允许添加哪个
&7 项应忽略 &7 项应忽略
&7 任何元数据 &7 任何元数据
&7 分配给他们。 &7 分配给他们。
title: "&7 项:" title: "&7 项:"
list: " &8 - [数量] x [项目]" list: " &8 - [number] x [item]"
none: "&7 项目未添加。" none: "&7 项目未添加。"
remove_ignored_meta: remove_ignored_meta:
name: "&f&l 删除忽略元数据" name: "&f&l 删除忽略元数据"
@ -323,7 +327,7 @@ challenges:
description: |- description: |-
&7 允许切换 &7 允许切换
&7 所需经验将 &7 所需经验将
&7 播放器中移除 &7 玩家中移除
&7 完成后 &7 完成后
&7 挑战。 &7 挑战。
enabled: "&2 已启用" enabled: "&2 已启用"
@ -333,21 +337,21 @@ challenges:
description: |- description: |-
&7 允许更改 &7 允许更改
&7 所需经验 &7 所需经验
&7 播放器 &7 玩家
value: "&7 当前经验:&e [数字]" value: "&7 当前经验:&e [number]"
required_level: required_level:
name: "&f&l 所需岛屿等级" name: "&f&l 所需岛屿等级"
description: |- description: |-
&7 允许更改 &7 允许更改
&7 所需岛屿等级 &7 所需岛屿等级
&7 挑战。 &7 挑战。
value: "&7 当前级别:&e [数字]" value: "&7 当前级别:&e [number]"
remove_money: remove_money:
name: "&f&l 移除金钱" name: "&f&l 移除金钱"
description: |- description: |-
&7 允许切换 &7 允许切换
&7 所需资金将 &7 所需资金将
&7 播放器中移除 &7 玩家中移除
&7 帐号完成后 &7 帐号完成后
&7 挑战。 &7 挑战。
enabled: "&2 已启用" enabled: "&2 已启用"
@ -358,21 +362,21 @@ challenges:
&7 允许更改 &7 允许更改
&7 玩家需要的钱 &7 玩家需要的钱
&7 说明了挑战。 &7 说明了挑战。
value: "&7 当前值:&e [数字]" value: "&7 当前值:&e [number]"
statistic: statistic:
name: "&f&l 统计" name: "&f&l 统计"
description: |- description: |-
&7 允许更改 &7 允许更改
&7 统计类型是 &7 统计类型是
&7 签入了这个挑战。 &7 签入了这个挑战。
value: "&7 当前值:&e [统计]" value: "&7 当前值:&e [statistic]"
statistic_amount: statistic_amount:
name: "&f&l 目标值" name: "&f&l 目标值"
description: |- description: |-
&7 允许更改 &7 允许更改
&7 统计目标值 &7 统计目标值
&7 必须满足。 &7 必须满足。
value: "&7 当前值:&e [数字]" value: "&7 当前值:&e [number]"
remove_statistic: remove_statistic:
name: "&f&l 减少统计量" name: "&f&l 减少统计量"
description: |- description: |-
@ -387,19 +391,19 @@ challenges:
description: |- description: |-
&7 允许更改 &7 允许更改
&7 统计目标块。 &7 统计目标块。
value: "&7 当前块:&e []" value: "&7 当前块:&e [block]"
statistic_items: statistic_items:
name: "&f&l 目标项目" name: "&f&l 目标项目"
description: |- description: |-
&7 允许更改 &7 允许更改
&7 统计目标项。 &7 统计目标项。
value: "&7 当前项目:&e [项目]" value: "&7 当前项目:&e [item]"
statistic_entities: statistic_entities:
name: "&f&l 目标实体" name: "&f&l 目标实体"
description: |- description: |-
&7 允许更改 &7 允许更改
&7 统计目标实体。 &7 统计目标实体。
value: "&7 当前实体:&e [实体]" value: "&7 当前实体:&e [entity]"
reward_text: reward_text:
name: "&f&l 奖励文本" name: "&f&l 奖励文本"
description: |- description: |-
@ -420,7 +424,7 @@ challenges:
&7 允许更改奖励 &7 允许更改奖励
&7 项。 &7 项。
title: "&7 项:" title: "&7 项:"
list: " &8 - [数量] x [项目]" list: " &8 - [number] x [item]"
none: "&7 项目未添加。" none: "&7 项目未添加。"
repeat_reward_items: repeat_reward_items:
name: "&f&l 重复奖励项目" name: "&f&l 重复奖励项目"
@ -429,35 +433,35 @@ challenges:
&7 奖励物品 &7 奖励物品
&7 挑战。 &7 挑战。
title: "&7 项:" title: "&7 项:"
list: " &8 - [数量] x [项目]" list: " &8 - [number] x [item]"
none: "&7 项目未添加。" none: "&7 项目未添加。"
reward_experience: reward_experience:
name: "&f&l 奖励体验" name: "&f&l 奖励体验"
description: |- description: |-
&7 允许更改 &7 允许更改
&7 奖励经验 &7 奖励经验
&7 播放器 &7 玩家
value: "&7 奖励经验:&e [数字]" value: "&7 奖励经验:&e [number]"
repeat_reward_experience: repeat_reward_experience:
name: "&f&l 重复奖励体验" name: "&f&l 重复奖励体验"
description: |- description: |-
&7 允许更改 &7 允许更改
&7 重复奖励经验 &7 重复奖励经验
&7 播放器 &7 玩家
value: "&7 奖励经验:&e [数字]" value: "&7 奖励经验:&e [number]"
reward_money: reward_money:
name: "&f&l 奖励金" name: "&f&l 奖励金"
description: |- description: |-
&7 允许更改 &7 允许更改
&7 奖励金钱。 &7 奖励金钱。
value: "&7 当前值:&e [数字]" value: "&7 当前值:&e [number]"
repeat_reward_money: repeat_reward_money:
name: "&f&l 重复奖励金" name: "&f&l 重复奖励金"
description: |- description: |-
&7 允许更改 &7 允许更改
&7 重复奖励金 &7 重复奖励金
&7 挑战。 &7 挑战。
value: "&7 当前值:&e [数字]" value: "&7 当前值:&e [number]"
reward_commands: reward_commands:
name: "&f&l 奖励命令" name: "&f&l 奖励命令"
description: |- description: |-
@ -509,7 +513,7 @@ challenges:
&7 允许更改 &7 允许更改
&7 重复次数 &7 重复次数
&7 挑战。 &7 挑战。
value: "&7 当前值:&e [数字]" value: "&7 当前值:&e [number]"
cool_down: cool_down:
name: "&f&l 冷却" name: "&f&l 冷却"
description: |- description: |-
@ -518,7 +522,7 @@ challenges:
&7 之间必须等待 &7 之间必须等待
&7 可重复挑战 &7 可重复挑战
&7 完成。 &7 完成。
value: "&7 当前值:&e [时间]" value: "&7 当前值:&e [time]"
challenges: challenges:
name: "&f&l 挑战" name: "&f&l 挑战"
description: |- description: |-
@ -531,7 +535,7 @@ challenges:
&7 的挑战 &7 的挑战
&7 未完成 &7 未完成
&7 解锁下一个级别。 &7 解锁下一个级别。
value: "&7 当前值:&e [数字]" value: "&7 当前值:&e [number]"
add_challenges: add_challenges:
name: "&f&l 添加挑战(-s)" name: "&f&l 添加挑战(-s)"
description: |- description: |-
@ -626,13 +630,13 @@ challenges:
&7 在用户数据中。 &7 在用户数据中。
&7 0 表示数据将 &7 0 表示数据将
&7 不会被删除。 &7 不会被删除。
value: "&7 当前值:&e [数字]" value: "&7 当前值:&e [number]"
title_showtime: title_showtime:
name: "&f&l 标题放映时间" name: "&f&l 标题放映时间"
description: |- description: |-
&7 该标题的刻度数 &7 该标题的刻度数
&7 将显示给玩家。 &7 将显示给玩家。
value: "&7 当前值:&e [数字]" value: "&7 当前值:&e [number]"
active_world_list: active_world_list:
name: "&f&l 仅显示活跃世界" name: "&f&l 仅显示活跃世界"
description: |- description: |-
@ -658,16 +662,16 @@ challenges:
name: "&f&l 下载库" name: "&f&l 下载库"
description: |- description: |-
&7 可手动更新 &7 可手动更新
&7 挑战图书馆 &7 挑战
enabled: "&2 清除缓存" enabled: "&2 清除缓存"
disabled: "&c 不清除缓存" disabled: "&c 不清除缓存"
player: player:
name: "&f&l [名称]" name: "&f&l [name]"
description: "&7 岛主:[所有者]" description: "&7 岛主:[owner]"
members: "&7 岛成员:" members: "&7 岛成员:"
member: "&8 - [名称]" member: "&8 - [name]"
no-island: |- no-island: |-
&c 播放器没有 &c 玩家没有
&c 一个岛屿。 &c 一个岛屿。
player_list: player_list:
name: "&f&l 选择用户列表" name: "&f&l 选择用户列表"
@ -691,9 +695,9 @@ challenges:
&7 个选定的块 &7 个选定的块
&7 来自列表。 &7 来自列表。
title: "&7 精选材料:" title: "&7 精选材料:"
material: "&8 - [材质]" material: "&8 - [material]"
material: material:
name: "&f&l [材质]" name: "&f&l [material]"
description: "&7 材质 ID[id]" description: "&7 材质 ID[id]"
selected: "&2 已选择" selected: "&2 已选择"
add_entity: add_entity:
@ -705,7 +709,7 @@ challenges:
name: "&f&l 换鸡蛋" name: "&f&l 换鸡蛋"
description: |- description: |-
&7 允许从 &7 允许从
&7 鸡蛋给暴徒头。 &7 鸡蛋给怪物头。
remove_entity: remove_entity:
name: "&f&l 删除实体" name: "&f&l 删除实体"
description: |- description: |-
@ -713,9 +717,9 @@ challenges:
&7 个选定的实体 &7 个选定的实体
&7 来自列表。 &7 来自列表。
title: "&7 选定实体:" title: "&7 选定实体:"
entity: "&8 - [实体]" entity: "&8 - [entity]"
entity: entity:
name: "&f&l [实体]" name: "&f&l [entity]"
description: "&7 实体 ID[id]" description: "&7 实体 ID[id]"
selected: "&2 已选择" selected: "&2 已选择"
inventory_type: inventory_type:
@ -728,7 +732,7 @@ challenges:
description: |- description: |-
&7 检查的挑战 &7 检查的挑战
&7 周围的方块或实体 &7 周围的方块或实体
&7 播放器 &7 玩家
other_type: other_type:
name: "&f&l 其他类型" name: "&f&l 其他类型"
description: |- description: |-
@ -756,40 +760,41 @@ challenges:
&7 返回选中的元素 &7 返回选中的元素
&7 并打开以前的 GUI。 &7 并打开以前的 GUI。
title: "&7 已选择:" title: "&7 已选择:"
element: "&8 - [元素]" element: "&8 - [element]"
statistic_element: statistic_element:
name: "&f&l [统计]" name: "&f&l [statistic]"
description: "[描述]" description: "[description]"
environment_element: environment_element:
name: "&f&l [环境]" name: "&f&l [environment]"
description: "[描述]" description: "[description]"
search: search:
name: "&f&l 搜索" name: "&f&l 搜索"
description: |- description: |-
&7 允许搜索 &7 允许搜索
&7 元素与输入 &7 元素与输入
&7 文本值。 &7 文本值。
search: "&b 值:[值]" search: "&b 值:[value]"
#上面的都是没有翻译的,cirno看了直摇头
tips: tips:
click-to-select: "&e 单击 &7 进行选择。" click-to-select: "&e 单击 &7 进行选择。"
click-to-choose: "&e 单击 &7 进行选择。" click-to-choose: "&e 单击 &7 进行选择。"
click-to-complete: "&e 击 &7 完成。" click-to-complete: "&e 击 &7 完成。"
right-click-multiple-open: "&e 右击 &7 选择完成数。" right-click-multiple-open: "&e 右击 &7 选择完成挑战的次数。"
shift-left-click-to-complete-all: "&e Shift 单击 &7 完成所有操作。" shift-left-click-to-complete-all: "&e 按住Shift并左击 &7 一键完成(根据背包中所需道具数量)。"
left-click-to-accept: "&e 左键单击 &7 完成。" left-click-to-accept: "&e 左击 &7 接受。"
right-click-to-write: "&e 右击 &7 写入。" right-click-to-write: "&e 右击 &7 写入。"
click-to-reduce: "&e 点击 &7 减少。" click-to-reduce: "&e 点击 &7 减少。"
click-to-increase: "&e 点击 &7 增加。" click-to-increase: "&e 点击 &7 增加。"
click-to-return: "&e 单击 &7 返回。" click-to-return: "&e 单击 &7 返回。"
click-to-quit: "&e 点击 &7 退出。" click-to-quit: "&e 点击 &7 退出。"
click-to-wipe: "&e 单击 &7 除。" click-to-wipe: "&e 单击 &7 除。"
left-click-to-wipe: "&e 左键单击 &7 除。" left-click-to-wipe: "&e 左键单击 &7 除。"
right-click-to-switch: "&e 右键 &7 切换。" right-click-to-switch: "&e 右键 &7 切换。"
click-to-open: "&e 点击 &7 打开。" click-to-open: "&e 点击 &7 打开。"
click-to-export: "&e 点击 &7 导出。" click-to-export: "&e 点击 &7 导出。"
click-to-create: "&e 点击 &7 创建。" click-to-create: "&e 点击 &7 创建。"
left-click-to-open: "&e 左键单击 &7 打开。" left-click-to-open: "&e 左键单击 &7 打开。"
right-click-to-reset-all: "&e 右键单击 &7 擦除所有内容。" right-click-to-reset-all: "&e 右键单击 &7 重置所有内容。"
click-to-toggle: "&e 单击 &7 进行切换。" click-to-toggle: "&e 单击 &7 进行切换。"
click-to-change: "&e 单击 &7 进行更改。" click-to-change: "&e 单击 &7 进行更改。"
shift-click-to-reset: "&e Shift 单击 &7 进行重置。" shift-click-to-reset: "&e Shift 单击 &7 进行重置。"
@ -818,110 +823,111 @@ challenges:
descriptions: descriptions:
challenge: challenge:
lore: |- lore: |-
[描述] [description]
[地位] [status]
[冷却] [cooldown]
[要求] [requirements]
[奖励] [rewards]
status: status:
completed: "&2&l 已完成" completed: "&2&l 已完成"
completed-times: "&2 完成 &7&l [数字] &r&2 时间(-s)" #原来的time(-s)意思是如果完成复数次就是times不是时间里秒的含义
completed-times-of: "&2 已完成 &7&l [次数] &r&2 共 &7&l [最多] &r&2 次" completed-times: "&2 完成 &7&l [number] &r&2 次"
completed-times-reached: "&2&l 全部完成 &7 [最多] &2 次" completed-times-of: "&2 已完成 &7&l [number] &r&2 共 &7&l [max] &r&2 次"
completed-times-reached: "&2&l 全部完成 &7 [max] &2 次"
cooldown: cooldown:
lore: |- lore: |-
[超时] [timeout]
[等待时间] [wait-time]
timeout: "&7&l 冷却时间:&r&7 [时间]" timeout: "&7&l 冷却时间:&r&7 [time]"
wait-time: "&c&l 可用时间:&r&c [时间]" wait-time: "&c&l 等待时间:&r&c [time]"
in-days: "[数量] d" in-days: "[number] d"
in-hours: "[数量]小时" in-hours: "[number]小时"
in-minutes: "[数量] 分钟" in-minutes: "[number] 分钟"
in-seconds: "[数字] s" in-seconds: "[number] s"
requirements: requirements:
lore: |- lore: |-
[环境] [environment]
[类型要求] [type-requirement]
[权限] [permission]
environment-single: "&7 限于 [环境]" environment-single: "&7 限于 [environment]"
environment-title: "&7 限于:" environment-title: "&7 限于:"
environment-list: " &7 - &e [环境]" environment-list: " &7 - &e [environment]"
permission-single: "&c 需要 [permissions] 权限" permission-single: "&c 需要 [permissions] 权限"
permissions-title: "&c 需要权限:" permissions-title: "&c 需要权限:"
permissions-list: " &c - [权限]" permissions-list: " &c - [permission]"
island: island:
lore: |- lore: |-
[] [blocks]
[实体] [entities]
[搜索半径] [search-radius]
[警告块] [warning-block]
[警告实体] [warning-entity]
blocks-title: "&7&l 所需块:" blocks-title: "&7&l 所需块:"
block-value: " &7 - &e [材质]" block-value: " &7 - &e [material]"
blocks-value: " &7 - &e [数量] x [材料]" blocks-value: " &7 - &e [number] x [material]"
entities-title: "&7&l 所需实体:" entities-title: "&7&l 所需实体:"
entity-value: " &7 - &e [实体]" entity-value: " &7 - &e [entity]"
entities-value: " &7 - &e [数字] x [实体]" entities-value: " &7 - &e [number] x [entity]"
search-radius: "&7 不超过 &e [数字] &7 米" search-radius: "&7 不超过 &e [number] &7 米"
warning-block: "&e 块将被 &c 删除" warning-block: "&e 块将被 &c 删除"
warning-entity: "&e 实体将被 &c 删除" warning-entity: "&e 实体将被 &c 删除"
inventory: inventory:
lore: |- lore: |-
[项目] [items]
[警告] [warning]
item-title: "&7&l 必填项目:" item-title: "&7&l 必填项目:"
item-value: " &7 - &e [项目]" item-value: " &7 - &e [item]"
items-value: " &7 - &e [数字] x [项目]" items-value: " &7 - &e [number] x [item]"
warning: "&e 项目(-s将被 &c 删除" warning: "&e 项目(-s将被 &c 删除"
other: other:
lore: |- lore: |-
[经验] [experience]
[经验警告] [experience-warning]
[] [money]
[金钱警告] [money-warning]
[等级] [level]
experience: "&7&l 所需经验:&r&e [数量]" experience: "&7&l 所需经验:&r&e [number]"
experience-warning: "&e 经验将被 &c 移除" experience-warning: "&e 经验将被 &c 移除"
money: "&7&l 所需资金:&r&e [数字]" money: "&7&l 所需资金:&r&e [number]"
money-warning: "&e 钱将被 &c 移除" money-warning: "&e 钱将被 &c 移除"
level: "&7&l 所需岛屿等级:&r&e [数字]" level: "&7&l 所需岛屿等级:&r&e [number]"
statistic: statistic:
lore: |- lore: |-
[统计] [statistic]
[警告] [warning]
multiple-target: "&7&l [统计]: &r&e [数字] x [目标]" multiple-target: "&7&l [statistic]: &r&e [number] x [target]"
single-target: "&7&l [统计]: &r&e [目标]" single-target: "&7&l [statistic]: &r&e [target]"
statistic: "&7&l [统计] &r&e [数字]" statistic: "&7&l [statistic] &r&e [number]"
warning: "&e 统计数据将 &c 减少" warning: "&e 统计数据将 &c 减少"
rewards: rewards:
lore: |- lore: |-
&7&l 奖励: &7&l 奖励:
[文本] [text]
[项目] [items]
[经验] [experience]
[] [money]
[命令] [commands]
item-title: "&7 项:" item-title: "&7 项:"
item-value: " &7 - &e [项目]" item-value: " &7 - &e [item]"
items-value: " &7 - &e [数字] x [项目]" items-value: " &7 - &e [number] x [item]"
experience: "&7 经验:&r&e [数字]" experience: "&7 经验:&r&e [number]"
money: "&7 金钱:&r&e [数字]" money: "&7 金钱:&r&e [number]"
commands-title: "&7 命令:" commands-title: "&7 命令:"
command: " &7 - &e [命令]" command: " &7 - &e [command]"
level: level:
lore: |- lore: |-
[文本] [text]
[地位] [status]
[放弃] [waiver]
[奖励] [rewards]
status: status:
completed: "&2&l 已完成" completed: "&2&l 已完成"
completed-challenges-of: |- completed-challenges-of: |-
&2 已完成 &7&l [数量] &r&2 出 &2 已完成 &7&l [number] &r&2 出
&7&l [max] &r&2 挑战。 &7&l [max] &r&2 挑战。
locked: "&c&l 锁定" locked: "&c&l 锁定"
missing-challenges: |- missing-challenges: |-
&7 [数字] 更多的挑战必须是 &7 [number] 更多的挑战必须是
&7 完成以解锁此级别。 &7 完成以解锁此级别。
waiver: |- waiver: |-
&7&l [number] 挑战(-s) &r&7 可以 &7&l [number] 挑战(-s) &r&7 可以
@ -929,25 +935,26 @@ challenges:
rewards: rewards:
lore: |- lore: |-
&7&l 奖励: &7&l 奖励:
[文本] [text]
[项目] [items]
[经验] [experience]
[] [money]
[命令] [commands]
item-title: "&7 项:" item-title: "&7 项:"
item-value: " &7 - &e [项目]" item-value: " &7 - &e [item]"
items-value: " &7 - &e [数字] x [项目]" items-value: " &7 - &e [number] x [item]"
experience: "&7 经验:&r&e [数字]" experience: "&7 经验:&r&e [number]"
money: "&7 金钱:&r&e [数字]" money: "&7 金钱:&r&e [number]"
commands-title: "&7 命令:" commands-title: "&7 命令:"
command: " &7 - &e [命令]" command: " &7 - &e [command]"
library: library:
author: "&7 作者 &e [作者]" author: "&7 作者 &e [author]"
version: "&7 Made with Challenges &e [版本]" version: "&7 Made with Challenges &e [version]"
lang: "&7 语言:&e [lang]" lang: "&7 语言:&e [lang]"
gamemode: "&7 主要用于 &e [游戏模式]" gamemode: "&7 主要用于 &e [gamemode]"
#后面没人工翻译了
conversations: conversations:
prefix: "&l&6 [便当盒]: &r" prefix: "&l&6 [BentoBox]: &r"
confirm-string: true, on, yes, 确认, y, 有效, 正确 confirm-string: true, on, yes, 确认, y, 有效, 正确
deny-string: 关闭拒绝n无效不正确 deny-string: 关闭拒绝n无效不正确
cancel-string: 取消 cancel-string: 取消
@ -956,17 +963,17 @@ challenges:
input-number: "&e 请在聊天中输入一个号码。" input-number: "&e 请在聊天中输入一个号码。"
input-seconds: "&e 请在聊天中输入秒。" input-seconds: "&e 请在聊天中输入秒。"
numeric-only: "&c 给定的 [value] 不是数字!" numeric-only: "&c 给定的 [value] 不是数字!"
not-valid-value: "&c 给定的数字 [] 无效。它必须大于 [min] 并且小于 [max]" not-valid-value: "&c 给定的数字 [value] 无效。它必须大于 [min] 并且小于 [max]"
user-data-removed: "&a [游戏模式] 的所有用户数据都从数据库中清除。" user-data-removed: "&a [gamemode] 的所有用户数据都从数据库中清除。"
confirm-user-data-deletion: "&e 请确认您要清除 [游戏模式] 的用户数据库。" confirm-user-data-deletion: "&e 请确认您要清除 [gamemode] 的用户数据库。"
challenge-data-removed: "&a [游戏模式] 的所有挑战数据都从数据库中清除。" challenge-data-removed: "&a [gamemode] 的所有挑战数据都从数据库中清除。"
confirm-challenge-data-deletion: "&e 请确认您要清除 [游戏模式] 的挑战数据库。" confirm-challenge-data-deletion: "&e 请确认您要清除 [gamemode] 的挑战数据库。"
all-data-removed: "&a [游戏模式] 的所有插件数据都从数据库中清除。" all-data-removed: "&a [gamemode] 的所有插件数据都从数据库中清除。"
confirm-all-data-deletion: "&e 请确认您要清除 [游戏模式] 的插件数据。" confirm-all-data-deletion: "&e 请确认您要清除 [gamemode] 的插件数据。"
write-name: "&e 请在聊天中一个名字。" write-name: "&e 请在聊天中输入一个名字。"
new-object-created: "&a 为 [gamemode] 创建了一个新对象。" new-object-created: "&a 为 [gamemode] 创建了一个新对象。"
object-already-exists: "&c 对象 &7 [id] &c 已经存在。选择不同的名称。" object-already-exists: "&c 对象 &7 [id] &c 已经存在。选择不同的名称。"
invalid-challenge: "&c 挑战 [挑战] 包含无效数据。无法部署!" invalid-challenge: "&c 挑战 [challenge] 包含无效数据。无法部署!"
name-changed: "&a 成功,名称已更新。" name-changed: "&a 成功,名称已更新。"
write-description: "&e 请在聊天中输入新的描述,然后在一行中自行“退出”以完成。" write-description: "&e 请在聊天中输入新的描述,然后在一行中自行“退出”以完成。"
description-changed: "&a 成功,说明已更新。" description-changed: "&a 成功,说明已更新。"
@ -987,7 +994,7 @@ challenges:
start-downloading: "&a 开始下载和导入挑战库。" start-downloading: "&a 开始下载和导入挑战库。"
written-text: "&a 输入文本:" written-text: "&a 输入文本:"
confirm-data-replacement: "&e 请确认您想用新的挑战替换当前的挑战。" confirm-data-replacement: "&e 请确认您想用新的挑战替换当前的挑战。"
new-challenges-imported: "&a 成功,[游戏模式] 的新挑战已导入。" new-challenges-imported: "&a 成功,[gamemode] 的新挑战已导入。"
exported-file-name: "&e 请输入导出的数据库文件的文件名。 (写“取消”退出)" exported-file-name: "&e 请输入导出的数据库文件的文件名。 (写“取消”退出)"
database-export-completed: "&a 成功,[world] 的数据库导出完成。文件[文件]生成。" database-export-completed: "&a 成功,[world] 的数据库导出完成。文件[文件]生成。"
file-name-exist: "&c 名称为“[id]”的文件存在。无法覆盖。" file-name-exist: "&c 名称为“[id]”的文件存在。无法覆盖。"
@ -998,11 +1005,12 @@ challenges:
challenge-subtitle: "[friendlyName]" challenge-subtitle: "[friendlyName]"
level-title: "&a已完成" level-title: "&a已完成"
level-subtitle: "[friendlyName]" level-subtitle: "[friendlyName]"
#上面没翻译了
messages: messages:
completed: "&2 你为[玩家]完成了挑战[名字]" completed: "&2 你为[player]完成了挑战[name]"
already-completed: "&2 这个挑战已经完成了!" already-completed: "&2 这个挑战已经完成了!"
reset: "&2 你为 [玩家] 重置挑战 [名称]" reset: "&2 你为 [player] 重置挑战 [name]"
reset-all: "&2 所有[玩家]挑战均已重置!" reset-all: "&2 所有[player]挑战均已重置!"
not-completed: "&2 此挑战尚未完成!" not-completed: "&2 此挑战尚未完成!"
migrate-start: "&2 开始迁移挑战插件数据。" migrate-start: "&2 开始迁移挑战插件数据。"
migrate-end: "&2 挑战插件数据更新为新格式。" migrate-end: "&2 挑战插件数据更新为新格式。"
@ -1031,7 +1039,7 @@ challenges:
you-still-need: "&c你还差 &f[amount] &c个 &f[item] &c才能完成挑战。" you-still-need: "&c你还差 &f[amount] &c个 &f[item] &c才能完成挑战。"
missing-addon: "&c无法完成挑战缺少必需的组件或插件。" missing-addon: "&c无法完成挑战缺少必需的组件或插件。"
incorrect: "&c无法完成挑战必要条件设定错误。" incorrect: "&c无法完成挑战必要条件设定错误。"
not-enough-money: "&c你必须有 &f[value] &c游戏币才能完成任务。" not-enough-money: "&c你必须有 &f[value] &c金钱才能完成任务。"
not-enough-experience: "&c你必须有 &f[value] &c经验值才能完成任务。" not-enough-experience: "&c你必须有 &f[value] &c经验值才能完成任务。"
island-level: "&c你的岛屿等级必须达到 &flv[number] &c才能完成任务" island-level: "&c你的岛屿等级必须达到 &flv[number] &c才能完成任务"
no-load: "&c错误 无法载入 &fchallenges.yml&c. [message]" no-load: "&c错误 无法载入 &fchallenges.yml&c. [message]"
@ -1047,18 +1055,106 @@ challenges:
invalid-challenge: "&c挑战项 [challenge] &c包含错误它不会从数据库中加载" invalid-challenge: "&c挑战项 [challenge] &c包含错误它不会从数据库中加载"
no-library-entries: "&c 找不到任何库条目。没什么可显示的。" no-library-entries: "&c 找不到任何库条目。没什么可显示的。"
not-hooked: "&c Challenges Addon 找不到任何游戏模式。" not-hooked: "&c Challenges Addon 找不到任何游戏模式。"
timeout: "&c 此挑战需要在完成之间等待 [超时]。您必须等待 [wait-time] 才能再次完成。" timeout: "&c 此挑战需要在完成之间等待 [timeout]。您必须等待 [wait-time] 才能再次完成。"
requirement-not-met: "&c This challenge requires [statistic] to have [number]. You have only [value]. "
# # Showcase for manual material translation
# materials:
# # Names should be lowercase.
# cobblestone: "Cobblestone"
# # Also supports descriptions.
# stone:
# name: "Stone"
# description: ""
# item-stacks:
# # Non-specific item meta translations.
# # TYPE is the item type
# # META is a content of item meta.
# generic: "[type] [meta]"
# # Non-specific meta translations. Will replace [meta]
# meta:
# upgraded: "Upgraded"
# extended: "Extended"
# potion-meta: "&e [type] [upgraded] [extended]"
# # Be aware, enchants are always listed below item in separate line.
# enchant-meta: " &7 - &e [type] [level]"
# skull-meta: ": &e [player-name]"
# book-meta: "&e [title] [author]"
# # Custom Enchantment Translation.
# enchant:
# menting: "Mending"
# unbreaking: "Unbreaking"
# # Custom Potion Translation.
# potion-type:
# water_breathing: "Water Breathing"
# # You can also create specific item translations
# # Like translate all potions.
# potion:
# # This will overwrite generic translation.
# name: "[type] [upgraded] [extended]"
# # 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"
# 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:
# # This will mean that only stone shovels will not show
# # meta information.
# name: "[type]"
#
# # Showcase how to support multi-linguistic challenges
# challenges:
# # Database ID name.
# example_challenge_id:
# name: "&2 Translated Name"
# description: |-
# &7 Translated Custom
# &7 description
# reward-text: |-
# &7 Translated Reward
# &7 text
# repeat-reward-text: |-
# &7 Translated Repeat
# &7 Reward text
# levels:
# # Database ID name.
# example_level_id:
# name: "&2 Translated Name"
# description: |-
# &7 Translated Custom
# &7 description
# reward-text: |-
# &7 Translated Reward
# &7 text
protection: protection:
flags: flags:
CHALLENGES_ISLAND_PROTECTION: CHALLENGES_ISLAND_PROTECTION:
description: 允许/禁止 在岛屿上完成挑战 description: |-
name: 挑战权限 &5 &o 切换谁可以
&5 &o 完成挑战
name: 挑战保护
CHALLENGES_WORLD_PROTECTION: CHALLENGES_WORLD_PROTECTION:
description: |- description: |-
&7允许/禁止 限制玩家只能在自己岛 &5 &o 启用 / 禁用
&7上才能完成挑战。 &5 &o 玩家们在自己
&c允许时玩家只能在自己岛上进行 &5 &o 岛屿中完成挑
&c和完成挑战。 &5 &o 战的需求
name: 挑战岛屿限制 name: 岛屿挑战限制
hint: "&c已被禁止在岛屿范围外进行挑战" hint: 岛屿外无挑战
version: 11 version: 11

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
name: BentoBox-Challenges
main: world.bentobox.challenges.ChallengesPladdon
version: ${project.version}${build.number}
api-version: "1.17"
authors: [tastybento, BONNe]
contributors: ["The BentoBoxWorld Community"]
website: https://bentobox.world
description: ${project.description}

View File

@ -245,96 +245,96 @@ public class ChallengesManagerTest {
} }
/** /**
* Test method for {@link ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, boolean, world.bentobox.bentobox.api.user.User, boolean)}. * Test method for {@link ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, World, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/ */
@Test @Test
public void testLoadChallengeNoOverwriteSilent() { public void testLoadChallengeNoOverwriteSilent() {
// load once // load once
assertTrue(cm.loadChallenge(challenge, false, user, true)); assertTrue(cm.loadChallenge(challenge, world, false, user, true));
// load twice - no overwrite // load twice - no overwrite
assertFalse(cm.loadChallenge(challenge, false, user, true)); assertFalse(cm.loadChallenge(challenge, world, false, user, true));
} }
/** /**
* Test method for {@link ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, boolean, world.bentobox.bentobox.api.user.User, boolean)}. * Test method for {@link ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, World, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/ */
@Test @Test
public void testLoadChallengeNoOverwriteNotSilent() { public void testLoadChallengeNoOverwriteNotSilent() {
// load once // load once
assertTrue(cm.loadChallenge(challenge, false, user, true)); assertTrue(cm.loadChallenge(challenge, world, false, user, true));
// load twice - no overwrite, not silent // load twice - no overwrite, not silent
assertFalse(cm.loadChallenge(challenge, false, user, false)); assertFalse(cm.loadChallenge(challenge, world, false, user, false));
verify(user).getTranslation("challenges.messages.load-skipping", "[value]", "name"); verify(user).getTranslation("challenges.messages.load-skipping", "[value]", "name");
} }
/** /**
* Test method for {@link ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, boolean, world.bentobox.bentobox.api.user.User, boolean)}. * Test method for {@link ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, World, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/ */
@Test @Test
public void testLoadChallengeOverwriteSilent() { public void testLoadChallengeOverwriteSilent() {
// load once // load once
assertTrue(cm.loadChallenge(challenge, false, user, true)); assertTrue(cm.loadChallenge(challenge, world, false, user, true));
// overwrite // overwrite
assertTrue(cm.loadChallenge(challenge, true, user, true)); assertTrue(cm.loadChallenge(challenge, world, true, user, true));
verify(user, never()).getTranslation(anyString(), anyString(), anyString()); verify(user, never()).getTranslation(anyString(), anyString(), anyString());
} }
/** /**
* Test method for {@link ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, boolean, world.bentobox.bentobox.api.user.User, boolean)}. * Test method for {@link ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, World, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/ */
@Test @Test
public void testLoadChallengeOverwriteNotSilent() { public void testLoadChallengeOverwriteNotSilent() {
// load once // load once
assertTrue(cm.loadChallenge(challenge, false, user, true)); assertTrue(cm.loadChallenge(challenge, world, false, user, true));
// overwrite not silent // overwrite not silent
assertTrue(cm.loadChallenge(challenge, true, user, false)); assertTrue(cm.loadChallenge(challenge, world, true, user, false));
verify(user).getTranslation("challenges.messages.load-overwriting", "[value]", "name"); verify(user).getTranslation("challenges.messages.load-overwriting", "[value]", "name");
} }
/** /**
* Test method for {@link ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, boolean, world.bentobox.bentobox.api.user.User, boolean)}. * Test method for {@link ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, World, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/ */
@Test @Test
public void testLoadLevelNoOverwriteSilent() { public void testLoadLevelNoOverwriteSilent() {
// load once // load once
assertTrue(cm.loadLevel(level, false, user, true)); assertTrue(cm.loadLevel(level, world, false, user, true));
// load twice - no overwrite // load twice - no overwrite
assertFalse(cm.loadLevel(level, false, user, true)); assertFalse(cm.loadLevel(level, world, false, user, true));
} }
/** /**
* Test method for {@link ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, boolean, world.bentobox.bentobox.api.user.User, boolean)}. * Test method for {@link ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, World, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/ */
@Test @Test
public void testLoadLevelNoOverwriteNotSilent() { public void testLoadLevelNoOverwriteNotSilent() {
// load once // load once
assertTrue(cm.loadLevel(level, false, user, true)); assertTrue(cm.loadLevel(level, world, false, user, true));
// load twice - no overwrite, not silent // load twice - no overwrite, not silent
assertFalse(cm.loadLevel(level, false, user, false)); assertFalse(cm.loadLevel(level, world, false, user, false));
verify(user).getTranslation("challenges.messages.load-skipping", "[value]", "Novice"); verify(user).getTranslation("challenges.messages.load-skipping", "[value]", "Novice");
} }
/** /**
* Test method for {@link ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, boolean, world.bentobox.bentobox.api.user.User, boolean)}. * Test method for {@link ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, World, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/ */
@Test @Test
public void testLoadLevelOverwriteSilent() { public void testLoadLevelOverwriteSilent() {
// load once // load once
assertTrue(cm.loadLevel(level, false, user, true)); assertTrue(cm.loadLevel(level, world, false, user, true));
// overwrite // overwrite
assertTrue(cm.loadLevel(level, true, user, true)); assertTrue(cm.loadLevel(level, world, true, user, true));
verify(user, never()).getTranslation(anyString(), anyString(), anyString()); verify(user, never()).getTranslation(anyString(), anyString(), anyString());
} }
/** /**
* Test method for {@link ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, boolean, world.bentobox.bentobox.api.user.User, boolean)}. * Test method for {@link ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, World, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/ */
@Test @Test
public void testLoadLevelOverwriteNotSilent() { public void testLoadLevelOverwriteNotSilent() {
// load once // load once
assertTrue(cm.loadLevel(level, false, user, true)); assertTrue(cm.loadLevel(level, world, false, user, true));
// overwrite not silent // overwrite not silent
assertTrue(cm.loadLevel(level, true, user, false)); assertTrue(cm.loadLevel(level, world, true, user, false));
verify(user).getTranslation("challenges.messages.load-overwriting", "[value]", "Novice"); verify(user).getTranslation("challenges.messages.load-overwriting", "[value]", "Novice");
} }
@ -660,7 +660,7 @@ public class ChallengesManagerTest {
public void testGetAllChallengesNames() { public void testGetAllChallengesNames() {
assertTrue(cm.getAllChallengesNames(world).isEmpty()); assertTrue(cm.getAllChallengesNames(world).isEmpty());
cm.saveChallenge(challenge); cm.saveChallenge(challenge);
cm.loadChallenge(challenge, false, user, true); cm.loadChallenge(challenge, world, false, user, true);
List<String> list = cm.getAllChallengesNames(world); List<String> list = cm.getAllChallengesNames(world);
assertFalse(list.isEmpty()); assertFalse(list.isEmpty());
assertEquals(cName, list.get(0)); assertEquals(cName, list.get(0));
@ -673,7 +673,7 @@ public class ChallengesManagerTest {
public void testGetAllChallenges() { public void testGetAllChallenges() {
assertTrue(cm.getAllChallenges(world).isEmpty()); assertTrue(cm.getAllChallenges(world).isEmpty());
cm.saveChallenge(challenge); cm.saveChallenge(challenge);
cm.loadChallenge(challenge, false, user, true); cm.loadChallenge(challenge, world, false, user, true);
List<Challenge> list = cm.getAllChallenges(world); List<Challenge> list = cm.getAllChallenges(world);
assertFalse(list.isEmpty()); assertFalse(list.isEmpty());
assertEquals(challenge, list.get(0)); assertEquals(challenge, list.get(0));
@ -688,12 +688,12 @@ public class ChallengesManagerTest {
assertTrue(cm.getFreeChallenges(world).isEmpty()); assertTrue(cm.getFreeChallenges(world).isEmpty());
// One normal // One normal
cm.saveChallenge(challenge); cm.saveChallenge(challenge);
cm.loadChallenge(challenge, false, user, true); cm.loadChallenge(challenge, world, false, user, true);
assertTrue(cm.getFreeChallenges(world).isEmpty()); assertTrue(cm.getFreeChallenges(world).isEmpty());
// One free // One free
challenge.setLevel(""); challenge.setLevel("");
cm.saveChallenge(challenge); cm.saveChallenge(challenge);
cm.loadChallenge(challenge, false, user, true); cm.loadChallenge(challenge, world, false, user, true);
List<Challenge> list = cm.getFreeChallenges(world); List<Challenge> list = cm.getFreeChallenges(world);
assertFalse(list.isEmpty()); assertFalse(list.isEmpty());
assertEquals(challenge, list.get(0)); assertEquals(challenge, list.get(0));
@ -792,7 +792,7 @@ public class ChallengesManagerTest {
public void testGetLevelString() { public void testGetLevelString() {
assertNull(cm.getLevel("dss")); assertNull(cm.getLevel("dss"));
cm.saveLevel(level); cm.saveLevel(level);
cm.loadLevel(level, false, user, true); cm.loadLevel(level, world, false, user, true);
assertEquals(level, cm.getLevel(levelName)); assertEquals(level, cm.getLevel(levelName));
} }