Bug fix release (#228)

* Fix issue when users could not select non-block items as icons for challenges and levels. (#190)

* English update (#193)

* Organized imports

* Minor code cleanup

* Updated English locale file.

* Translate zh-CN.yml via GitLocalize (#188)

* Make default translation looking a bit nicer (#192)

* Make default translation looking a bit nicer
* Updating a few friendly names and rewording some phrases
* Add generic .gitignore

* Fix novice level

Update `chiseledmaker` name in `novice` level.

* Adapt literal style (#197)

Improve translations and process as a YAML string.

* Test coverage (#199)

* Test coverage for Challenges Command

* Added CompleteChallengeCommand test class

* Added Utils test class

* Added ChallengesGUI test class

* Fix code smells from sonarcloud analysis

* Added .gitignore

* Added Travis CI config file

* WIP ChallengesManager Test class

* Added ChallengesManager test class

* Removed debug

* Removed code smells.

* Added ChallengesAddon test class.

* Added onDisbale test

* Added new TryToComplete test class - WIP

Covers inventory challenges.

* Added Island Challenge entity tests to TryToComplete test class

* Fix a bug with challenge deletion.

If challenge has been left in a level, then system did not remove challenge from it and was kept as ghost challenge, preventing from completing level.

* Fixes tests

* Updated travis.yml

* All strings to spanish (#200)

* Translate es.yml via GitLocalize

* Translate es.yml via GitLocalize

* Translate es.yml via GitLocalize

* Fix LevelListRequestHandler.
This handler did not return list of strings but list of challenge levels, that is incorrect.
Not it should work correctly.

* Create ro.yml

* Create id.yml

* Remove blanks files now that GitLocalize is fixed.

* Initial Russian translation (#207)

* Translate ru.yml via GitLocalize

Co-authored-by: @mt-gitlocalize @IPeredero @LoveBiscuit

* Changed build character from # to b

* Add German translation (#210)

* Translate de.yml via GitLocalize

* Translate de.yml via GitLocalize

* Translate de.yml via GitLocalize

Co-authored-by: xXjojojXx <36734820+xXjojojXx@users.noreply.github.com>
Co-authored-by: FunnysBanana <51290016+FunnysBanana@users.noreply.github.com>
Co-authored-by: mt-gitlocalize <mt@gitlocalize.com>

* Czech translation. Credit @Polda18

* Added a uniqueId sanitization when creating challenges/levels
This will help fixing issues with spaces, hyphens and accents in non-English languages.

* Fixes bug with checking entities in nether and end (#219)

https://github.com/BentoBoxWorld/Challenges/issues/218

Adds test case to check for compliance.

* Add 7 new placeholders for Challenges Addon.

- `[gamemode]_challenge_total_completion_count` returns number of sum of challenge completions for user.
- `[gamemode]_challenge_completed_count` returns number of completed challenges (at least once) for user.
- `[gamemode]_challenge_uncompleted_count` returns number of uncompleted challenges for user.
- `[gamemode]_challenge_completed_level_count` returns number of completed levels for user.
- `[gamemode]_challenge_uncompleted_level_count` returns number of uncompleted levels for user.
- `[gamemode]_challenge_unlocked_level_count` returns number of unlocked levels for user.
- `[gamemode]_challenge_locked_level_count` returns number of locked levels for user.

Fixes #224

* Add 2 new placeholders:

- `[gamemode]_challenge_latest_level_name` returns latest unlocked challenge level name
- `[gamemode]_challenge_latest_level_id` returns latest unlocked challenge level id

Fixes #226

* Fix broken tests due to placeholder additions.

b5ecffb725
2958ca8b6c

* Added default perms for aoneblock

* Downgrade to 0.8.1 version

* Add option to quit from conversation by writing "cancel" in chat.
Move sanitizeInput to a GuiUtil class.

* Change latest version to 0.8.1
This commit is contained in:
BONNe 2020-04-22 01:19:46 +03:00 committed by GitHub
parent 29a5057535
commit 8383c93cf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
76 changed files with 9420 additions and 3650 deletions

134
.gitignore vendored Normal file
View File

@ -0,0 +1,134 @@
### Others ###
*.cmd
*.sh
*.prefs
### Maven ###
/mvn
/target/lib
/target/maven-archiver
/target/classes
/target/maven-status
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
out/
### Java ###
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
*.iml
## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:
# User-specific stuff:
.idea/workspace.xml
.idea/tasks.xml
.idea/dictionaries
.idea/shelf
# Sensitive or high-churn files:
.idea/dataSources.ids
.idea/dataSources.xml
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml
# Gradle:
.idea/gradle.xml
.idea/libraries
.gradle
# Mongo Explorer plugin:
# .idea/mongoSettings.xml
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Eclipse ###
*.pydevproject
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
# Eclipse Core
.project
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# JDT-specific (Eclipse Java Development Tools)
.classpath
# Java annotation processor (APT)
.factorypath
# PDT-specific
.buildpath
# sbteclipse plugin
.target
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
/target/
checkstyle.xml
classes/
/.DS_Store

23
.travis.yml Normal file
View File

@ -0,0 +1,23 @@
language: java
sudo: false
addons:
sonarcloud:
organization: "bentobox-world"
jdk:
- openjdk8
- openjdk11
matrix:
allow_failures:
- jdk: openjdk11
script:
#- sonar-scanner
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent install sonar:sonar -Dsonar.projectKey=BentoBoxWorld_Challenges
#- echo "${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}"
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.sonar/cache'

View File

@ -7,7 +7,7 @@ Add-on for BentoBox to provide challenges for any BentoBox GameMode.
## Where to find
Currently Challenges Addon is in **Beta stage**, so it may or may not contain bugs... a lot of bugs. Also it means, that some features are not working or implemented.
Latest official **Beta Release is 0.8.0**, and you can download it from [Release tab](https://github.com/BentoBoxWorld/Challenges/releases)
Latest official **Beta Release is 0.8.1**, and you can download it from [Release tab](https://github.com/BentoBoxWorld/Challenges/releases)
But it will work with BentoBox 1.6.x and BentoBox 1.7.x.
Latest development builds will be based on **Minecraft 1.14.4** and **BentoBox 1.8.0**.

43
pom.xml
View File

@ -33,7 +33,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<powermock.version>1.7.4</powermock.version>
<powermock.version>2.0.2</powermock.version>
<!-- More visible way how to change dependency versions -->
<spigot.version>1.14.4-R0.1-SNAPSHOT</spigot.version>
<bentobox.version>1.7.0</bentobox.version>
@ -42,7 +42,7 @@
<!-- Revision variable removes warning about dynamic version -->
<revision>${build.version}-SNAPSHOT</revision>
<!-- This allows to change between versions and snapshots. -->
<build.version>0.8.0</build.version>
<build.version>0.8.1</build.version>
<build.number>-LOCAL</build.number>
</properties>
@ -56,7 +56,7 @@
</activation>
<properties>
<!-- Override only if necessary -->
<build.number>-#${env.BUILD_NUMBER}</build.number>
<build.number>-b${env.BUILD_NUMBER}</build.number>
<!-- GIT_BRANCH -->
</properties>
</profile>
@ -129,24 +129,25 @@
<version>${spigot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<!-- Mockito (Unit testing) -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>world.bentobox</groupId>
<artifactId>bentobox</artifactId>

View File

@ -1,11 +1,14 @@
package world.bentobox.challenges;
import org.bukkit.Material;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.configuration.Config;
@ -18,6 +21,7 @@ import world.bentobox.challenges.commands.ChallengesUserCommand;
import world.bentobox.challenges.commands.admin.Challenges;
import world.bentobox.challenges.commands.admin.ChallengesAdminCommand;
import world.bentobox.challenges.config.Settings;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.handlers.ChallengeDataRequestHandler;
import world.bentobox.challenges.handlers.ChallengeListRequestHandler;
import world.bentobox.challenges.handlers.CompletedChallengesRequestHandler;
@ -87,7 +91,7 @@ public class ChallengesAddon extends Addon {
* This flag allows to complete challenges in any part of the world. It will not limit
* player to their island. Useful for skygrid without protection flags.
*/
public static Flag CHALLENGES_WORLD_PROTECTION =
public static final Flag CHALLENGES_WORLD_PROTECTION =
new Flag.Builder("CHALLENGES_WORLD_PROTECTION", Material.GRASS_BLOCK).type(Flag.Type.WORLD_SETTING).defaultSetting(true).build();
/**
@ -95,7 +99,7 @@ public class ChallengesAddon extends Addon {
* that only Island owner can complete challenge.
* By default it is set to Visitor.
*/
public static Flag CHALLENGES_ISLAND_PROTECTION =
public static final Flag CHALLENGES_ISLAND_PROTECTION =
new Flag.Builder("CHALLENGES_ISLAND_PROTECTION", Material.COMMAND_BLOCK).defaultRank(RanksManager.VISITOR_RANK).build();
@ -154,7 +158,8 @@ public class ChallengesAddon extends Addon {
List<GameModeAddon> hookedGameModes = new ArrayList<>();
this.getPlugin().getAddonsManager().getGameModeAddons().forEach(gameModeAddon -> {
if (!this.settings.getDisabledGameModes().contains(gameModeAddon.getDescription().getName()))
if (!this.settings.getDisabledGameModes().contains(
gameModeAddon.getDescription().getName()))
{
if (gameModeAddon.getPlayerCommand().isPresent())
{
@ -172,6 +177,8 @@ public class ChallengesAddon extends Addon {
CHALLENGES_WORLD_PROTECTION.addGameModeAddon(gameModeAddon);
CHALLENGES_ISLAND_PROTECTION.addGameModeAddon(gameModeAddon);
this.registerPlaceholders(gameModeAddon);
}
});
@ -237,7 +244,7 @@ public class ChallengesAddon extends Addon {
if (this.settings.getAutoSaveTimer() > 0)
{
this.getPlugin().getServer().getScheduler().runTaskTimerAsynchronously(
Bukkit.getScheduler().runTaskTimerAsynchronously(
this.getPlugin(),
bukkitTask -> ChallengesAddon.this.challengesManager.save(),
this.settings.getAutoSaveTimer() * 60 * 20,
@ -263,7 +270,7 @@ public class ChallengesAddon extends Addon {
{
this.loadSettings();
this.challengesManager.reload();
this.getLogger().info("Challenges addon reloaded.");
this.log("Challenges addon reloaded.");
}
}
@ -308,6 +315,72 @@ public class ChallengesAddon extends Addon {
}
/**
* This method registers placeholders into GameMode addon.
* @param gameModeAddon GameMode addon where placeholders must be hooked in.
*/
private void registerPlaceholders(GameModeAddon gameModeAddon)
{
final String gameMode = gameModeAddon.getDescription().getName().toLowerCase();
final World world = gameModeAddon.getOverWorld();
// Number of completions for all challenges placeholder
this.getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gameMode + "_challenge_total_completion_count",
user -> String.valueOf(this.challengesManager.getTotalChallengeCompletionCount(user, world)));
// Completed challenge count placeholder
this.getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gameMode + "_challenge_completed_count",
user -> String.valueOf(this.challengesManager.getCompletedChallengeCount(user, world)));
// Uncompleted challenge count placeholder
this.getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gameMode + "_challenge_uncompleted_count",
user -> String.valueOf(this.challengesManager.getChallengeCount(world) -
this.challengesManager.getCompletedChallengeCount(user, world)));
// Completed challenge level count placeholder
this.getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gameMode + "_challenge_completed_level_count",
user -> String.valueOf(this.challengesManager.getCompletedLevelCount(user, world)));
// Uncompleted challenge level count placeholder
this.getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gameMode + "_challenge_uncompleted_level_count",
user -> String.valueOf(this.challengesManager.getLevelCount(world) -
this.challengesManager.getCompletedLevelCount(user, world)));
// Unlocked challenge level count placeholder
this.getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gameMode + "_challenge_unlocked_level_count",
user -> String.valueOf(this.challengesManager.getLevelCount(world) -
this.challengesManager.getUnlockedLevelCount(user, world)));
// Locked challenge level count placeholder
this.getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gameMode + "_challenge_locked_level_count",
user -> String.valueOf(this.challengesManager.getLevelCount(world) -
this.challengesManager.getUnlockedLevelCount(user, world)));
// Latest challenge level name placeholder
this.getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gameMode + "_challenge_latest_level_name",
user -> {
ChallengeLevel level = this.challengesManager.getLatestUnlockedLevel(user, world);
return level != null ? level.getFriendlyName() : "";
});
// Latest challenge level id placeholder
this.getPlugin().getPlaceholdersManager().registerPlaceholder(this,
gameMode + "_challenge_latest_level_id",
user -> {
ChallengeLevel level = this.challengesManager.getLatestUnlockedLevel(user, world);
return level != null ? level.getUniqueId() : "";
});
}
// ---------------------------------------------------------------------
// Section: Getters
// ---------------------------------------------------------------------

View File

@ -1,8 +1,5 @@
package world.bentobox.challenges;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
@ -21,12 +18,16 @@ import java.util.stream.Collectors;
import org.bukkit.World;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.json.BentoboxTypeAdapterFactory;
import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.util.Util;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.utils.Utils;
@ -42,14 +43,14 @@ public class ChallengesImportManager
* @param challengesAddon
*/
public ChallengesImportManager(ChallengesAddon challengesAddon)
{
{
this.addon = challengesAddon;
}
// ---------------------------------------------------------------------
// Section: Default Challenge Loader
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Default Challenge Loader
// ---------------------------------------------------------------------
/**
@ -78,45 +79,46 @@ public class ChallengesImportManager
}
// default configuration should be removed.
// user made configuration should not!.
// user made configuration should not!.
boolean removeAtEnd =
!Files.exists(Paths.get(this.addon.getDataFolder().getPath() + "/default.json"));
!Files.exists(Paths.get(this.addon.getDataFolder().getPath() + "/default.json"));
// Safe json configuration to Challenges folder.
this.addon.saveResource("default.json", false);
this.addon.saveResource("default.json", false);
try
{
// This prefix will be used to all challenges. That is a unique way how to separate challenged for
// each game mode.
String uniqueIDPrefix = Utils.getGameMode(world) + "_";
DefaultDataHolder defaultChallenges = new DefaultJSONHandler(this.addon).loadObject();
// This prefix will be used to all challenges. That is a unique way how to separate challenged for
// each game mode.
String uniqueIDPrefix = Utils.getGameMode(world) + "_";
DefaultDataHolder defaultChallenges = new DefaultJSONHandler(this.addon).loadObject();
if (defaultChallenges != null) {
// All new challenges should get correct ID. So we need to map it to loaded challenges.
defaultChallenges.getChallengeList().forEach(challenge -> {
// Set correct challenge ID
challenge.setUniqueId(uniqueIDPrefix + challenge.getUniqueId());
// Set up correct level ID if it is necessary
if (!challenge.getLevel().isEmpty())
{
challenge.setLevel(uniqueIDPrefix + challenge.getLevel());
}
// Load challenge in memory
manager.loadChallenge(challenge, false, user, user == null);
});
// All new challenges should get correct ID. So we need to map it to loaded challenges.
defaultChallenges.getChallengeList().forEach(challenge -> {
// Set correct challenge ID
challenge.setUniqueId(uniqueIDPrefix + challenge.getUniqueId());
// Set up correct level ID if it is necessary
if (!challenge.getLevel().isEmpty())
{
challenge.setLevel(uniqueIDPrefix + challenge.getLevel());
}
// Load challenge in memory
manager.loadChallenge(challenge, false, user, user == null);
});
defaultChallenges.getLevelList().forEach(challengeLevel -> {
// Set correct level ID
challengeLevel.setUniqueId(uniqueIDPrefix + challengeLevel.getUniqueId());
// Set correct world name
challengeLevel.setWorld(Util.getWorld(world).getName());
// Reset names for all challenges.
challengeLevel.setChallenges(challengeLevel.getChallenges().stream().
map(challenge -> uniqueIDPrefix + challenge).
collect(Collectors.toSet()));
// Load level in memory
manager.loadLevel(challengeLevel, false, user, user == null);
});
defaultChallenges.getLevelList().forEach(challengeLevel -> {
// Set correct level ID
challengeLevel.setUniqueId(uniqueIDPrefix + challengeLevel.getUniqueId());
// Set correct world name
challengeLevel.setWorld(Util.getWorld(world).getName());
// Reset names for all challenges.
challengeLevel.setChallenges(challengeLevel.getChallenges().stream().
map(challenge -> uniqueIDPrefix + challenge).
collect(Collectors.toSet()));
// Load level in memory
manager.loadLevel(challengeLevel, false, user, user == null);
});
}
}
catch (Exception e)
{
@ -127,132 +129,132 @@ public class ChallengesImportManager
this.addon.getChallengesManager().save();
if (removeAtEnd)
{
// Remove default.yml file from resources to avoid interacting with it.
new File(this.addon.getDataFolder(), "default.json").delete();
}
{
// Remove default.yml file from resources to avoid interacting with it.
return new File(this.addon.getDataFolder(), "default.json").delete();
}
return true;
}
/**
* This method loads downloaded challenges into memory.
* @param user User who calls downloaded challenge loading
* @param world Target world.
* @param downloadString String that need to be loaded via DefaultDataHolder.
* @return <code>true</code> if everything was successful, otherwise <code>false</code>.
*/
public boolean loadDownloadedChallenges(User user, World world, String downloadString)
{
ChallengesManager manager = this.addon.getChallengesManager();
/**
* This method loads downloaded challenges into memory.
* @param user User who calls downloaded challenge loading
* @param world Target world.
* @param downloadString String that need to be loaded via DefaultDataHolder.
* @return <code>true</code> if everything was successful, otherwise <code>false</code>.
*/
public boolean loadDownloadedChallenges(User user, World world, String downloadString)
{
ChallengesManager manager = this.addon.getChallengesManager();
// If exist any challenge or level that is bound to current world, then do not load default challenges.
if (manager.hasAnyChallengeData(world.getName()))
{
if (user.isPlayer())
{
user.sendMessage("challenges.errors.exist-challenges-or-levels");
}
else
{
this.addon.logWarning("challenges.errors.exist-challenges-or-levels");
}
// If exist any challenge or level that is bound to current world, then do not load default challenges.
if (manager.hasAnyChallengeData(world.getName()))
{
if (user.isPlayer())
{
user.sendMessage("challenges.errors.exist-challenges-or-levels");
}
else
{
this.addon.logWarning("challenges.errors.exist-challenges-or-levels");
}
return false;
}
return false;
}
try
{
// This prefix will be used to all challenges. That is a unique way how to separate challenged for
// each game mode.
String uniqueIDPrefix = Utils.getGameMode(world) + "_";
DefaultDataHolder downloadedChallenges = new DefaultJSONHandler(this.addon).loadWebObject(downloadString);
try
{
// This prefix will be used to all challenges. That is a unique way how to separate challenged for
// each game mode.
String uniqueIDPrefix = Utils.getGameMode(world) + "_";
DefaultDataHolder downloadedChallenges = new DefaultJSONHandler(this.addon).loadWebObject(downloadString);
// All new challenges should get correct ID. So we need to map it to loaded challenges.
downloadedChallenges.getChallengeList().forEach(challenge -> {
// Set correct challenge ID
challenge.setUniqueId(uniqueIDPrefix + challenge.getUniqueId());
// Set up correct level ID if it is necessary
if (!challenge.getLevel().isEmpty())
{
challenge.setLevel(uniqueIDPrefix + challenge.getLevel());
}
// Load challenge in memory
manager.loadChallenge(challenge, false, user, user == null);
});
// All new challenges should get correct ID. So we need to map it to loaded challenges.
downloadedChallenges.getChallengeList().forEach(challenge -> {
// Set correct challenge ID
challenge.setUniqueId(uniqueIDPrefix + challenge.getUniqueId());
// Set up correct level ID if it is necessary
if (!challenge.getLevel().isEmpty())
{
challenge.setLevel(uniqueIDPrefix + challenge.getLevel());
}
// Load challenge in memory
manager.loadChallenge(challenge, false, user, user == null);
});
downloadedChallenges.getLevelList().forEach(challengeLevel -> {
// Set correct level ID
challengeLevel.setUniqueId(uniqueIDPrefix + challengeLevel.getUniqueId());
// Set correct world name
challengeLevel.setWorld(Util.getWorld(world).getName());
// Reset names for all challenges.
challengeLevel.setChallenges(challengeLevel.getChallenges().stream().
map(challenge -> uniqueIDPrefix + challenge).
collect(Collectors.toSet()));
// Load level in memory
manager.loadLevel(challengeLevel, false, user, user == null);
});
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
downloadedChallenges.getLevelList().forEach(challengeLevel -> {
// Set correct level ID
challengeLevel.setUniqueId(uniqueIDPrefix + challengeLevel.getUniqueId());
// Set correct world name
challengeLevel.setWorld(Util.getWorld(world).getName());
// Reset names for all challenges.
challengeLevel.setChallenges(challengeLevel.getChallenges().stream().
map(challenge -> uniqueIDPrefix + challenge).
collect(Collectors.toSet()));
// Load level in memory
manager.loadLevel(challengeLevel, false, user, user == null);
});
}
catch (Exception e)
{
addon.getPlugin().logStacktrace(e);
return false;
}
this.addon.getChallengesManager().save();
this.addon.getChallengesManager().save();
return true;
}
return true;
}
// ---------------------------------------------------------------------
// Section: Default generation
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Default generation
// ---------------------------------------------------------------------
/**
* Create method that can generate default challenge file from existing challenges in given world.
* This method will create default.json file in Challenges folder.
* @param user User who calls this method.
* @param user User who calls this method.
* @param world from which challenges must be stored.
* @param overwrite indicates if existing default.json file can be overwritten.
* @return <code>true</code> if everything was successful, otherwise <code>false</code>
* @param overwrite indicates if existing default.json file can be overwritten.
* @return <code>true</code> if everything was successful, otherwise <code>false</code>
*/
public boolean generateDefaultChallengeFile(User user, World world, boolean overwrite)
{
File defaultFile = new File(this.addon.getDataFolder(), "default.json");
if (defaultFile.exists())
{
if (overwrite)
{
if (user.isPlayer())
{
user.sendMessage("challenges.messages.defaults-file-overwrite");
}
else
{
this.addon.logWarning("challenges.messages.defaults-file-overwrite");
}
{
if (overwrite)
{
if (user.isPlayer())
{
user.sendMessage("challenges.messages.defaults-file-overwrite");
}
else
{
this.addon.logWarning("challenges.messages.defaults-file-overwrite");
}
defaultFile.delete();
}
else
{
if (user.isPlayer())
{
user.sendMessage("challenges.errors.defaults-file-exist");
}
else
{
this.addon.logWarning("challenges.errors.defaults-file-exist");
}
defaultFile.delete();
}
else
{
if (user.isPlayer())
{
user.sendMessage("challenges.errors.defaults-file-exist");
}
else
{
this.addon.logWarning("challenges.errors.defaults-file-exist");
}
return false;
}
}
return false;
}
}
try
{
@ -261,102 +263,102 @@ public class ChallengesImportManager
String replacementString = Utils.getGameMode(world) + "_";
ChallengesManager manager = this.addon.getChallengesManager();
List<Challenge> challengeList = manager.getAllChallenges(world).
stream().
map(challenge -> {
// Use clone to avoid any changes in existing challenges.
Challenge clone = challenge.clone();
// Remove world name from challenge id.
clone.setUniqueId(challenge.getUniqueId().replaceFirst(replacementString, ""));
// Remove world name from level id.
clone.setLevel(challenge.getLevel().replaceFirst(replacementString, ""));
List<Challenge> challengeList = manager.getAllChallenges(world).
stream().
map(challenge -> {
// Use clone to avoid any changes in existing challenges.
Challenge clone = challenge.clone();
// Remove world name from challenge id.
clone.setUniqueId(challenge.getUniqueId().replaceFirst(replacementString, ""));
// Remove world name from level id.
clone.setLevel(challenge.getLevel().replaceFirst(replacementString, ""));
return clone;
}).
collect(Collectors.toList());
return clone;
}).
collect(Collectors.toList());
List<ChallengeLevel> levelList = manager.getLevels(world).
stream().
map(challengeLevel -> {
// Use clone to avoid any changes in existing levels.
ChallengeLevel clone = challengeLevel.clone();
// Remove world name from level ID.
clone.setUniqueId(challengeLevel.getUniqueId().replaceFirst(replacementString, ""));
// Remove world name.
clone.setWorld("");
// Challenges must be reassign, as they also contains world name.
clone.setChallenges(challengeLevel.getChallenges().stream().
map(challenge -> challenge.replaceFirst(replacementString, "")).
collect(Collectors.toSet()));
List<ChallengeLevel> levelList = manager.getLevels(world).
stream().
map(challengeLevel -> {
// Use clone to avoid any changes in existing levels.
ChallengeLevel clone = challengeLevel.clone();
// Remove world name from level ID.
clone.setUniqueId(challengeLevel.getUniqueId().replaceFirst(replacementString, ""));
// Remove world name.
clone.setWorld("");
// Challenges must be reassign, as they also contains world name.
clone.setChallenges(challengeLevel.getChallenges().stream().
map(challenge -> challenge.replaceFirst(replacementString, "")).
collect(Collectors.toSet()));
return clone;
}).
collect(Collectors.toList());
return clone;
}).
collect(Collectors.toList());
DefaultDataHolder defaultChallenges = new DefaultDataHolder();
defaultChallenges.setChallengeList(challengeList);
defaultChallenges.setLevelList(levelList);
defaultChallenges.setVersion(this.addon.getDescription().getVersion());
DefaultDataHolder defaultChallenges = new DefaultDataHolder();
defaultChallenges.setChallengeList(challengeList);
defaultChallenges.setLevelList(levelList);
defaultChallenges.setVersion(this.addon.getDescription().getVersion());
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(defaultFile), StandardCharsets.UTF_8));
writer.write(Objects.requireNonNull(
new DefaultJSONHandler(this.addon).toJsonString(defaultChallenges)));
writer.close();
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(defaultFile), StandardCharsets.UTF_8))) {
writer.write(Objects.requireNonNull(
new DefaultJSONHandler(this.addon).toJsonString(defaultChallenges)));
}
}
}
catch (IOException e)
{
if (user.isPlayer())
{
user.sendMessage("challenges.errors.defaults-file-error");
}
if (user.isPlayer())
{
user.sendMessage("challenges.errors.defaults-file-error");
}
this.addon.logError("Could not save json file: " + e.getMessage());
return false;
}
this.addon.logError("Could not save json file: " + e.getMessage());
return false;
}
finally
{
if (user.isPlayer())
{
user.sendMessage("challenges.messages.defaults-file-completed", "[world]", world.getName());
}
else
{
this.addon.logWarning("challenges.messages.defaults-file-completed");
}
}
{
if (user.isPlayer())
{
user.sendMessage("challenges.messages.defaults-file-completed", "[world]", world.getName());
}
else
{
this.addon.logWarning("challenges.messages.defaults-file-completed");
}
}
return true;
}
return true;
}
// ---------------------------------------------------------------------
// Section: Private classes for default challenges
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Private classes for default challenges
// ---------------------------------------------------------------------
/**
* This Class allows to load default challenges and their levels as objects much easier.
*/
private static final class DefaultJSONHandler
private static final class DefaultJSONHandler
{
/**
* This constructor inits JSON builder that will be used to parse challenges.
* @param addon Challenges Adddon
*/
DefaultJSONHandler(ChallengesAddon addon)
/**
* This constructor inits JSON builder that will be used to parse challenges.
* @param addon Challenges Adddon
*/
DefaultJSONHandler(ChallengesAddon addon)
{
GsonBuilder builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().enableComplexMapKeySerialization();
// Register adapters
builder.registerTypeAdapterFactory(new BentoboxTypeAdapterFactory(addon.getPlugin()));
// Keep null in the database
builder.serializeNulls();
// Allow characters like < or > without escaping them
builder.disableHtmlEscaping();
GsonBuilder builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().enableComplexMapKeySerialization();
// Register adapters
builder.registerTypeAdapterFactory(new BentoboxTypeAdapterFactory(addon.getPlugin()));
// Keep null in the database
builder.serializeNulls();
// Allow characters like < or > without escaping them
builder.disableHtmlEscaping();
this.addon = addon;
this.gson = builder.setPrettyPrinting().create();
this.addon = addon;
this.gson = builder.setPrettyPrinting().create();
}
@ -365,7 +367,7 @@ public class ChallengesImportManager
* @param instance Instance that must be parsed to json string.
* @return String that contains JSON information from instance object.
*/
String toJsonString(DefaultDataHolder instance)
String toJsonString(DefaultDataHolder instance)
{
// Null check
if (instance == null)
@ -374,193 +376,193 @@ public class ChallengesImportManager
return null;
}
return this.gson.toJson(instance);
return this.gson.toJson(instance);
}
/**
* This method creates and adds to list all objects from default.json file.
* @return List of all objects from default.json that is with T instance.
*/
DefaultDataHolder loadObject()
{
File defaultFile = new File(this.addon.getDataFolder(), "default.json");
/**
* This method creates and adds to list all objects from default.json file.
* @return List of all objects from default.json that is with T instance.
*/
DefaultDataHolder loadObject()
{
File defaultFile = new File(this.addon.getDataFolder(), "default.json");
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(defaultFile), StandardCharsets.UTF_8))
{
DefaultDataHolder object = this.gson.fromJson(reader, DefaultDataHolder.class);
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(defaultFile), StandardCharsets.UTF_8))
{
DefaultDataHolder object = this.gson.fromJson(reader, DefaultDataHolder.class);
reader.close(); // NOSONAR Required to keep OS file handlers low and not rely on GC
reader.close(); // NOSONAR Required to keep OS file handlers low and not rely on GC
return object;
}
catch (FileNotFoundException e)
{
this.addon.logError("Could not load file '" + defaultFile.getName() + "': File not found.");
}
catch (Exception e)
{
this.addon.logError("Could not load objects " + defaultFile.getName() + " " + e.getMessage());
}
return object;
}
catch (FileNotFoundException e)
{
this.addon.logError("Could not load file '" + defaultFile.getName() + "': File not found.");
}
catch (Exception e)
{
this.addon.logError("Could not load objects " + defaultFile.getName() + " " + e.getMessage());
}
return null;
}
return null;
}
/**
* This method creates and adds to list all objects from default.json file.
* @return List of all objects from default.json that is with T instance.
*/
DefaultDataHolder loadWebObject(String downloadedObject)
{
return this.gson.fromJson(downloadedObject, DefaultDataHolder.class);
}
/**
* This method creates and adds to list all objects from default.json file.
* @return List of all objects from default.json that is with T instance.
*/
DefaultDataHolder loadWebObject(String downloadedObject)
{
return this.gson.fromJson(downloadedObject, DefaultDataHolder.class);
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* Holds JSON builder object.
*/
private Gson gson;
/**
* Holds JSON builder object.
*/
private Gson gson;
/**
* Holds ChallengesAddon object.
*/
private ChallengesAddon addon;
/**
* Holds ChallengesAddon object.
*/
private ChallengesAddon addon;
}
/**
* This is simple object that will allow to store all current challenges and levels
* in single file.
*/
private static final class DefaultDataHolder implements DataObject
{
/**
* Default constructor. Creates object with empty lists.
*/
DefaultDataHolder()
{
this.challengeList = Collections.emptyList();
this.challengeLevelList = Collections.emptyList();
this.version = "";
}
/**
* This is simple object that will allow to store all current challenges and levels
* in single file.
*/
private static final class DefaultDataHolder implements DataObject
{
/**
* Default constructor. Creates object with empty lists.
*/
DefaultDataHolder()
{
this.challengeList = Collections.emptyList();
this.challengeLevelList = Collections.emptyList();
this.version = "";
}
/**
* This method returns stored challenge list.
* @return list that contains default challenges.
*/
List<Challenge> getChallengeList()
{
return challengeList;
}
/**
* This method returns stored challenge list.
* @return list that contains default challenges.
*/
List<Challenge> getChallengeList()
{
return challengeList;
}
/**
* This method sets given list as default challenge list.
* @param challengeList new default challenge list.
*/
void setChallengeList(List<Challenge> challengeList)
{
this.challengeList = challengeList;
}
/**
* This method sets given list as default challenge list.
* @param challengeList new default challenge list.
*/
void setChallengeList(List<Challenge> challengeList)
{
this.challengeList = challengeList;
}
/**
* This method returns list of default challenge levels.
* @return List that contains default challenge levels.
*/
List<ChallengeLevel> getLevelList()
{
return challengeLevelList;
}
/**
* This method returns list of default challenge levels.
* @return List that contains default challenge levels.
*/
List<ChallengeLevel> getLevelList()
{
return challengeLevelList;
}
/**
* This method sets given list as default challenge level list.
* @param levelList new default challenge level list.
*/
void setLevelList(List<ChallengeLevel> levelList)
{
this.challengeLevelList = levelList;
}
/**
* This method sets given list as default challenge level list.
* @param levelList new default challenge level list.
*/
void setLevelList(List<ChallengeLevel> levelList)
{
this.challengeLevelList = levelList;
}
/**
* This method returns the version value.
* @return the value of version.
*/
public String getVersion()
{
return version;
}
/**
* This method returns the version value.
* @return the value of version.
*/
public String getVersion()
{
return version;
}
/**
* This method sets the version value.
* @param version the version new value.
*
*/
public void setVersion(String version)
{
this.version = version;
}
/**
* This method sets the version value.
* @param version the version new value.
*
*/
public void setVersion(String version)
{
this.version = version;
}
/**
* @return default.json
*/
@Override
public String getUniqueId()
{
return "default.json";
}
/**
* @return default.json
*/
@Override
public String getUniqueId()
{
return "default.json";
}
/**
* @param uniqueId - unique ID the uniqueId to set
*/
@Override
public void setUniqueId(String uniqueId)
{
// method not used.
}
/**
* @param uniqueId - unique ID the uniqueId to set
*/
@Override
public void setUniqueId(String uniqueId)
{
// method not used.
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* Holds a list with default challenges.
*/
@Expose
private List<Challenge> challengeList;
/**
* Holds a list with default challenges.
*/
@Expose
private List<Challenge> challengeList;
/**
* Holds a list with default levels.
*/
@Expose
private List<ChallengeLevel> challengeLevelList;
/**
* Holds a list with default levels.
*/
@Expose
private List<ChallengeLevel> challengeLevelList;
/**
* Holds a variable that stores in which addon version file was made.
*/
@Expose
private String version;
}
/**
* Holds a variable that stores in which addon version file was made.
*/
@Expose
private String version;
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
private ChallengesAddon addon;
private ChallengesAddon addon;
}

View File

@ -1,8 +1,6 @@
package world.bentobox.challenges;
import org.eclipse.jdt.annotation.NonNull;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
@ -20,6 +18,8 @@ import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.logs.LogEntry;
import world.bentobox.bentobox.api.user.User;
@ -44,7 +44,7 @@ import world.bentobox.challenges.utils.Utils;
/**
* This class manges challenges. It allows access to all data that is stored to database.
* This class manages challenges. It allows access to all data that is stored to database.
* It also provides information about challenge level status for each user.
*/
public class ChallengesManager
@ -108,6 +108,11 @@ public class ChallengesManager
* String for free Challenge Level.
*/
public static final String FREE = "";
public static final String VALUE = "[value]";
public static final String USER_ID = "user-id";
public static final String CHALLENGE_ID = "challenge-id";
public static final String ADMIN_ID = "admin-id";
public static final String RESET = "RESET";
// ---------------------------------------------------------------------
@ -143,7 +148,7 @@ public class ChallengesManager
{
// Sort by challenges level order numbers
return Integer.compare(this.getLevel(o1.getLevel()).getOrder(),
this.getLevel(o2.getLevel()).getOrder());
this.getLevel(o2.getLevel()).getOrder());
}
}
};
@ -190,6 +195,7 @@ public class ChallengesManager
*/
public void load()
{
this.addon.log("Loading challenges...");
this.challengeCacheData.clear();
this.levelCacheData.clear();
@ -200,17 +206,15 @@ public class ChallengesManager
}
this.playerCacheData.clear();
loadAndValidate();
}
this.addon.getLogger().info("Loading challenges...");
private void loadAndValidate() {
this.challengeDatabase.loadObjects().forEach(this::loadChallenge);
this.levelDatabase.loadObjects().forEach(this::loadLevel);
// this validate challenge levels
this.validateChallenges();
// It is not necessary to load all players in memory.
// this.playersDatabase.loadObjects().forEach(this::loadPlayerData);
}
@ -219,24 +223,17 @@ public class ChallengesManager
*/
public void reload()
{
this.addon.log("Reloading challenges...");
if (!this.playerCacheData.isEmpty())
{
// store player data before cleaning.
this.savePlayersData();
}
//this.challengeDatabase = new Database<>(addon, Challenge.class);
//this.levelDatabase = new Database<>(addon, ChallengeLevel.class);
//this.playersDatabase = new Database<>(addon, ChallengesPlayerData.class);
this.addon.getLogger().info("Reloading challenges...");
this.challengeDatabase = new Database<>(addon, Challenge.class);
this.levelDatabase = new Database<>(addon, ChallengeLevel.class);
this.playersDatabase = new Database<>(addon, ChallengesPlayerData.class);
this.challengeDatabase.loadObjects().forEach(this::loadChallenge);
this.levelDatabase.loadObjects().forEach(this::loadLevel);
this.validateChallenges();
// It is not necessary to load all players in memory.
// this.playersDatabase.loadObjects().forEach(this::loadPlayerData);
loadAndValidate();
}
@ -262,17 +259,10 @@ public class ChallengesManager
* @return - true if imported
*/
public boolean loadChallenge(@NonNull Challenge challenge,
boolean overwrite,
User user,
boolean silent)
boolean overwrite,
User user,
boolean silent)
{
if (challenge == null)
{
this.addon.logError(
"Tried to load NULL element from Database. One challenge is broken and will not work.");
return false;
}
if (this.challengeCacheData.containsKey(challenge.getUniqueId()))
{
if (!overwrite)
@ -280,7 +270,7 @@ public class ChallengesManager
if (!silent)
{
user.sendMessage("challenges.messages.load-skipping",
"[value]", challenge.getFriendlyName());
VALUE, challenge.getFriendlyName());
}
return false;
@ -290,7 +280,7 @@ public class ChallengesManager
if (!silent)
{
user.sendMessage("challenges.messages.load-overwriting",
"[value]", challenge.getFriendlyName());
VALUE, challenge.getFriendlyName());
}
}
}
@ -299,7 +289,7 @@ public class ChallengesManager
if (!silent)
{
user.sendMessage("challenges.messages.load-add",
"[value]", challenge.getFriendlyName());
VALUE, challenge.getFriendlyName());
}
}
@ -330,28 +320,21 @@ public class ChallengesManager
* @return boolean that indicate about load status.
*/
public boolean loadLevel(@NonNull ChallengeLevel level,
boolean overwrite,
User user,
boolean silent)
boolean overwrite,
User user,
boolean silent)
{
if (level == null)
{
this.addon.logError(
"Tried to load NULL element from Database. One level is broken and will not work.");
return false;
}
if (!this.isValidLevel(level))
{
if (user != null)
{
user.sendMessage("challenges.errors.load-error",
"[value]", level.getFriendlyName());
VALUE, level.getFriendlyName());
}
else
{
this.addon.logError(
"Challenge Level '" + level.getUniqueId() + "' is not valid and skipped");
"Challenge Level '" + level.getUniqueId() + "' is not valid and skipped");
}
return false;
@ -364,7 +347,7 @@ public class ChallengesManager
if (!silent)
{
user.sendMessage("challenges.messages.load-skipping",
"[value]", level.getFriendlyName());
VALUE, level.getFriendlyName());
}
return false;
@ -374,7 +357,7 @@ public class ChallengesManager
if (!silent)
{
user.sendMessage("challenges.messages.load-overwriting",
"[value]", level.getFriendlyName());
VALUE, level.getFriendlyName());
}
}
}
@ -383,7 +366,7 @@ public class ChallengesManager
if (!silent)
{
user.sendMessage("challenges.messages.load-add",
"[value]", level.getFriendlyName());
VALUE, level.getFriendlyName());
}
}
@ -396,6 +379,8 @@ public class ChallengesManager
* This method stores PlayerData into local cache.
*
* @param playerData ChallengesPlayerData that must be loaded.
*
* TODO: Remove this unused method?
*/
private void loadPlayerData(@NonNull ChallengesPlayerData playerData)
{
@ -417,14 +402,11 @@ public class ChallengesManager
*/
public void removeFromCache(UUID playerID)
{
if (!this.settings.isStoreAsIslandData())
if (!this.settings.isStoreAsIslandData() && this.playerCacheData.containsKey(playerID.toString()))
{
if (this.playerCacheData.containsKey(playerID.toString()))
{
// save before remove
this.savePlayerData(playerID.toString());
this.playerCacheData.remove(playerID.toString());
}
// save before remove
this.savePlayerData(playerID.toString());
this.playerCacheData.remove(playerID.toString());
}
// TODO: It would be necessary to remove also data, if they stores islands.
@ -450,7 +432,7 @@ public class ChallengesManager
// If challenge's level is not found, then set it as free challenge.
challenge.setLevel(FREE);
this.addon.logWarning("Challenge's " + challenge.getUniqueId() + " level was not found in the database. " +
"To avoid any errors with missing level, challenge was added to the FREE level!");
"To avoid any errors with missing level, challenge was added to the FREE level!");
}
});
}
@ -681,13 +663,13 @@ public class ChallengesManager
this.levelCacheData.remove(level.getUniqueId());
level.setUniqueId(
addonName + level.getUniqueId().substring(world.getName().length()));
addonName + level.getUniqueId().substring(world.getName().length()));
Set<String> challengesID = new HashSet<>(level.getChallenges());
level.getChallenges().clear();
challengesID.forEach(challenge ->
level.getChallenges().add(addonName + challenge.substring(world.getName().length())));
level.getChallenges().add(addonName + challenge.substring(world.getName().length())));
this.levelDatabase.saveObject(level);
this.levelCacheData.put(level.getUniqueId(), level);
@ -703,6 +685,7 @@ public class ChallengesManager
/**
* This method collects all data from challenges database and migrates them.
*/
@SuppressWarnings("deprecation")
private boolean migrateChallenges(World world)
{
String addonName = Utils.getGameMode(world);
@ -741,36 +724,36 @@ public class ChallengesManager
{
switch (challenge.getChallengeType())
{
case INVENTORY:
InventoryRequirements inventoryRequirements = new InventoryRequirements();
inventoryRequirements.setRequiredItems(challenge.getRequiredItems());
inventoryRequirements.setTakeItems(challenge.isTakeItems());
case INVENTORY:
InventoryRequirements inventoryRequirements = new InventoryRequirements();
inventoryRequirements.setRequiredItems(challenge.getRequiredItems());
inventoryRequirements.setTakeItems(challenge.isTakeItems());
inventoryRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
challenge.setRequirements(inventoryRequirements);
break;
case ISLAND:
IslandRequirements islandRequirements = new IslandRequirements();
islandRequirements.setRemoveBlocks(challenge.isRemoveBlocks());
islandRequirements.setRemoveEntities(challenge.isRemoveEntities());
islandRequirements.setRequiredBlocks(challenge.getRequiredBlocks());
islandRequirements.setRequiredEntities(challenge.getRequiredEntities());
islandRequirements.setSearchRadius(challenge.getSearchRadius());
inventoryRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
challenge.setRequirements(inventoryRequirements);
break;
case ISLAND:
IslandRequirements islandRequirements = new IslandRequirements();
islandRequirements.setRemoveBlocks(challenge.isRemoveBlocks());
islandRequirements.setRemoveEntities(challenge.isRemoveEntities());
islandRequirements.setRequiredBlocks(challenge.getRequiredBlocks());
islandRequirements.setRequiredEntities(challenge.getRequiredEntities());
islandRequirements.setSearchRadius(challenge.getSearchRadius());
islandRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
challenge.setRequirements(islandRequirements);
break;
case OTHER:
OtherRequirements otherRequirements = new OtherRequirements();
otherRequirements.setRequiredExperience(challenge.getRequiredExperience());
otherRequirements.setRequiredIslandLevel(challenge.getRequiredIslandLevel());
otherRequirements.setRequiredMoney(challenge.getRequiredMoney());
otherRequirements.setTakeExperience(challenge.isTakeExperience());
otherRequirements.setTakeMoney(challenge.isTakeMoney());
islandRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
challenge.setRequirements(islandRequirements);
break;
case OTHER:
OtherRequirements otherRequirements = new OtherRequirements();
otherRequirements.setRequiredExperience(challenge.getRequiredExperience());
otherRequirements.setRequiredIslandLevel(challenge.getRequiredIslandLevel());
otherRequirements.setRequiredMoney(challenge.getRequiredMoney());
otherRequirements.setTakeExperience(challenge.isTakeExperience());
otherRequirements.setTakeMoney(challenge.isTakeMoney());
otherRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
challenge.setRequirements(otherRequirements);
break;
otherRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
challenge.setRequirements(otherRequirements);
break;
}
// This save should not involve any upgrades in other parts.
@ -1083,6 +1066,7 @@ public class ChallengesManager
* @param gameMode - World Name where levels should be searched.
* @return Level status - how many challenges still to do on which level
*/
@NonNull
private List<LevelStatus> getAllChallengeLevelStatus(String storageDataID, String gameMode)
{
this.addPlayerData(storageDataID);
@ -1110,15 +1094,14 @@ public class ChallengesManager
doneChallengeCount = (int) level.getChallenges().stream().filter(playerData::isChallengeDone).count();
result.add(new LevelStatus(
level,
previousLevel,
challengesToDo,
level.getChallenges().size() == doneChallengeCount,
challengesToDo <= 0));
level,
previousLevel,
challengesToDo,
level.getChallenges().size() == doneChallengeCount,
challengesToDo <= 0));
previousLevel = level;
}
return result;
}
@ -1130,6 +1113,7 @@ public class ChallengesManager
* @param level Level which status must be calculated.
* @return LevelStatus of given level.
*/
@Nullable
private LevelStatus getChallengeLevelStatus(@NonNull String storageDataID, World world, @NonNull ChallengeLevel level)
{
this.addPlayerData(storageDataID);
@ -1149,43 +1133,20 @@ public class ChallengesManager
int challengesToDo = previousLevel == null ? 0 :
(previousLevel.getChallenges().size() - level.getWaiverAmount()) -
(int) previousLevel.getChallenges().stream().filter(playerData::isChallengeDone).count();
(int) previousLevel.getChallenges().stream().filter(playerData::isChallengeDone).count();
// As level already contains unique ids of challenges, just iterate through them.
int doneChallengeCount = (int) level.getChallenges().stream().filter(playerData::isChallengeDone).count();
return new LevelStatus(
level,
previousLevel,
challengesToDo,
level.getChallenges().size() == doneChallengeCount,
challengesToDo <= 0);
level,
previousLevel,
challengesToDo,
level.getChallenges().size() == doneChallengeCount,
challengesToDo <= 0);
}
}
/**
* Check is playerData can see given level.
* TODO: not an optimal way. Faster would be to check previous level challenges.
* @param storageDataID - playerData ID
* @param level - level
* @return true if level is unlocked
*/
private boolean isLevelUnlocked(@NonNull String storageDataID,
World world,
ChallengeLevel level)
{
this.addPlayerData(storageDataID);
return this.islandWorldManager.getAddon(world).filter(gameMode ->
this.getAllChallengeLevelStatus(storageDataID, gameMode.getDescription().getName()).
stream().
filter(LevelStatus::isUnlocked).
anyMatch(lv -> lv.getLevel().equals(level))).
isPresent();
}
/**
* This method returns if given user has been already completed given level.
* @param levelID Level that must be checked.
@ -1317,17 +1278,17 @@ public class ChallengesManager
String storageID = this.getDataUniqueID(userID, Util.getWorld(world));
this.setChallengeComplete(storageID, challenge.getUniqueId(), completionCount);
this.addLogEntry(storageID, new LogEntry.Builder("COMPLETE").
data("user-id", userID.toString()).
data("challenge-id", challenge.getUniqueId()).
data("completion-count", Integer.toString(completionCount)).
build());
data(USER_ID, userID.toString()).
data(CHALLENGE_ID, challenge.getUniqueId()).
data("completion-count", Integer.toString(completionCount)).
build());
// Fire event that user completes challenge
Bukkit.getServer().getPluginManager().callEvent(
new ChallengeCompletedEvent(challenge.getUniqueId(),
userID,
false,
completionCount));
Bukkit.getPluginManager().callEvent(
new ChallengeCompletedEvent(challenge.getUniqueId(),
userID,
false,
completionCount));
}
@ -1344,17 +1305,17 @@ public class ChallengesManager
this.setChallengeComplete(storageID, challenge.getUniqueId());
this.addLogEntry(storageID, new LogEntry.Builder("COMPLETE").
data("user-id", userID.toString()).
data("challenge-id", challenge.getUniqueId()).
data("admin-id", adminID == null ? "OP" : adminID.toString()).
build());
data(USER_ID, userID.toString()).
data(CHALLENGE_ID, challenge.getUniqueId()).
data(ADMIN_ID, adminID == null ? "OP" : adminID.toString()).
build());
// Fire event that admin completes user challenge
Bukkit.getServer().getPluginManager().callEvent(
new ChallengeCompletedEvent(challenge.getUniqueId(),
userID,
true,
1));
Bukkit.getPluginManager().callEvent(
new ChallengeCompletedEvent(challenge.getUniqueId(),
userID,
true,
1));
}
@ -1369,18 +1330,18 @@ public class ChallengesManager
String storageID = this.getDataUniqueID(userID, Util.getWorld(world));
this.resetChallenge(storageID, challenge.getUniqueId());
this.addLogEntry(storageID, new LogEntry.Builder("RESET").
data("user-id", userID.toString()).
data("challenge-id", challenge.getUniqueId()).
data("admin-id", adminID == null ? "RESET" : adminID.toString()).
build());
this.addLogEntry(storageID, new LogEntry.Builder(RESET).
data(USER_ID, userID.toString()).
data(CHALLENGE_ID, challenge.getUniqueId()).
data(ADMIN_ID, adminID == null ? RESET : adminID.toString()).
build());
// Fire event that admin resets user challenge
Bukkit.getServer().getPluginManager().callEvent(
new ChallengeResetEvent(challenge.getUniqueId(),
userID,
true,
"RESET"));
Bukkit.getPluginManager().callEvent(
new ChallengeResetEvent(challenge.getUniqueId(),
userID,
true,
RESET));
}
@ -1408,16 +1369,16 @@ public class ChallengesManager
this.islandWorldManager.getAddon(world).ifPresent(gameMode -> {
this.resetAllChallenges(storageID, gameMode.getDescription().getName());
this.addLogEntry(storageID, new LogEntry.Builder("RESET_ALL").
data("user-id", userID.toString()).
data("admin-id", adminID == null ? "ISLAND_RESET" : adminID.toString()).
build());
data(USER_ID, userID.toString()).
data(ADMIN_ID, adminID == null ? "ISLAND_RESET" : adminID.toString()).
build());
// Fire event that admin resets user challenge
Bukkit.getServer().getPluginManager().callEvent(
new ChallengeResetAllEvent(gameMode.getDescription().getName(),
userID,
adminID != null,
adminID == null ? "ISLAND_RESET" : "RESET_ALL"));
Bukkit.getPluginManager().callEvent(
new ChallengeResetAllEvent(gameMode.getDescription().getName(),
userID,
adminID != null,
adminID == null ? "ISLAND_RESET" : "RESET_ALL"));
});
}
@ -1469,11 +1430,19 @@ public class ChallengesManager
* @param world World where level must be checked.
* @param level Level that must be checked.
* @param user User who need to be checked.
* @return true, if level is already completed.
* @return true, if level is unlocked.
*/
public boolean isLevelUnlocked(User user, World world, ChallengeLevel level)
{
return this.isLevelUnlocked(this.getDataUniqueID(user, Util.getWorld(world)), world, level);
String storageDataID = this.getDataUniqueID(user, Util.getWorld(world));
this.addPlayerData(storageDataID);
return this.islandWorldManager.getAddon(world).filter(gameMode -> this.getAllChallengeLevelStatus(storageDataID, gameMode.getDescription().getName()).
stream().
filter(LevelStatus::isUnlocked).
anyMatch(lv -> lv.getLevel().equals(level))).
isPresent();
}
@ -1489,14 +1458,14 @@ public class ChallengesManager
this.setLevelComplete(storageID, level.getUniqueId());
this.addLogEntry(storageID, new LogEntry.Builder("COMPLETE_LEVEL").
data("user-id", user.getUniqueId().toString()).
data("level", level.getUniqueId()).build());
data(USER_ID, user.getUniqueId().toString()).
data("level", level.getUniqueId()).build());
// Fire event that user completes level
Bukkit.getServer().getPluginManager().callEvent(
new LevelCompletedEvent(level.getUniqueId(),
user.getUniqueId(),
false));
Bukkit.getPluginManager().callEvent(
new LevelCompletedEvent(level.getUniqueId(),
user.getUniqueId(),
false));
}
@ -1515,14 +1484,15 @@ public class ChallengesManager
/**
* This method returns LevelStatus object for given challenge level.
* @param uniqueId UUID of user who need to be validated.
* @param world World where level must be validated.
* @param level Level that must be validated.
* @param user User who need to be validated.
* @return LevelStatus of given level.
*/
public LevelStatus getChallengeLevelStatus(UUID user, World world, ChallengeLevel level)
@Nullable
public LevelStatus getChallengeLevelStatus(UUID uniqueId, World world, ChallengeLevel level)
{
return this.getChallengeLevelStatus(this.getDataUniqueID(user, Util.getWorld(world)), world, level);
return this.getChallengeLevelStatus(this.getDataUniqueID(uniqueId, Util.getWorld(world)), world, level);
}
@ -1533,13 +1503,35 @@ public class ChallengesManager
* @param world - World where levels should be searched.
* @return Level status - how many challenges still to do on which level
*/
@NonNull
public List<LevelStatus> getAllChallengeLevelStatus(User user, World world)
{
return this.islandWorldManager.getAddon(world).map(gameMode ->
this.getAllChallengeLevelStatus(
this.getDataUniqueID(user, Util.getWorld(world)),
gameMode.getDescription().getName())).
orElse(Collections.emptyList());
orElse(Collections.emptyList());
}
/**
* This method returns latest ChallengeLevel object that is unlocked.
* @param user user who latest unlocked level must be returned.
* @param world World where level operates.
* @return ChallengeLevel for latest unlocked level.
*/
@Nullable
public ChallengeLevel getLatestUnlockedLevel(User user, World world)
{
LevelStatus lastStatus = null;
for (Iterator<LevelStatus> statusIterator = this.getAllChallengeLevelStatus(user, world).iterator();
statusIterator.hasNext() && (lastStatus == null || !lastStatus.isUnlocked());)
{
lastStatus = statusIterator.next();
}
return lastStatus != null ? lastStatus.getLevel() : null;
}
@ -1592,12 +1584,12 @@ public class ChallengesManager
{
// Free Challenges hides under FREE level.
return this.islandWorldManager.getAddon(world).map(gameMode ->
this.challengeCacheData.values().stream().
filter(challenge -> challenge.getLevel().equals(FREE) &&
challenge.matchGameMode(gameMode.getDescription().getName())).
sorted(Comparator.comparing(Challenge::getOrder)).
collect(Collectors.toList())).
orElse(Collections.emptyList());
this.challengeCacheData.values().stream().
filter(challenge -> challenge.getLevel().equals(FREE) &&
challenge.matchGameMode(gameMode.getDescription().getName())).
sorted(Comparator.comparing(Challenge::getOrder)).
collect(Collectors.toList())).
orElse(Collections.emptyList());
}
@ -1609,10 +1601,10 @@ public class ChallengesManager
public List<Challenge> getLevelChallenges(ChallengeLevel level)
{
return level.getChallenges().stream().
map(this::getChallenge).
filter(Objects::nonNull).
sorted(Comparator.comparing(Challenge::getOrder)).
collect(Collectors.toList());
map(this::getChallenge).
filter(Objects::nonNull).
sorted(Comparator.comparing(Challenge::getOrder)).
collect(Collectors.toList());
}
@ -1622,6 +1614,7 @@ public class ChallengesManager
* @param name - unique name of challenge
* @return - challenge or null if it does not exist
*/
@Nullable
public Challenge getChallenge(String name)
{
if (this.challengeCacheData.containsKey(name))
@ -1659,30 +1652,7 @@ public class ChallengesManager
*/
public boolean containsChallenge(String name)
{
if (this.challengeCacheData.containsKey(name))
{
return true;
}
else
{
// check database.
if (this.challengeDatabase.objectExists(name))
{
Challenge challenge = this.challengeDatabase.loadObject(name);
if (challenge != null)
{
this.challengeCacheData.put(name, challenge);
return true;
}
else
{
this.addon.logError("Tried to load NULL challenge object!");
}
}
}
return false;
return getChallenge(name) != null;
}
@ -1692,6 +1662,7 @@ public class ChallengesManager
* @param requirements - requirements object, as it is not changeable anymore.
* @return Challenge that is currently created.
*/
@Nullable
public Challenge createChallenge(String uniqueID, Challenge.ChallengeType type, Requirements requirements)
{
if (!this.containsChallenge(uniqueID))
@ -1722,15 +1693,65 @@ public class ChallengesManager
{
if (this.challengeCacheData.containsKey(challenge.getUniqueId()))
{
// First remove challenge from its owner level.
if (!challenge.getLevel().equals(FREE))
{
ChallengeLevel level = this.getLevel(challenge.getLevel());
if (level != null)
{
this.removeChallengeFromLevel(challenge, level);
}
}
// Afterwards remove challenge from the database.
this.challengeCacheData.remove(challenge.getUniqueId());
this.challengeDatabase.deleteObject(challenge);
this.addon.getPlugin().getPlaceholdersManager().
unregisterPlaceholder("challenges_challenge_repetition_count_" + challenge.getUniqueId());
}
}
/**
* This method returns number of challenges in given world.
* @param world World where challenge count must be returned.
* @return Number of challenges in given world.
*/
public int getChallengeCount(World world)
{
return this.getAllChallenges(world).size();
}
/**
* This method returns number of completed challenges in given world.
* @param user User which completed challenge count must be returned.
* @param world World where challenge count must be returned.
* @return Number of completed challenges by given user in given world.
*/
public long getCompletedChallengeCount(User user, World world)
{
return this.getAllChallenges(world).stream().
filter(challenge -> this.getChallengeTimes(user, world, challenge) > 0).
count();
}
/**
* This method returns total number of all completion times for all challenges in given world.
* @param user User which total completion count must be returned.
* @param world World where challenge count must be returned.
* @return Sum of completion count for all challenges by given user in given world.
*/
public long getTotalChallengeCompletionCount(User user, World world)
{
return this.getAllChallenges(world).stream().
mapToLong(challenge -> this.getChallengeTimes(user, world, challenge)).
sum();
}
// ---------------------------------------------------------------------
// Section: Level related methods
// ---------------------------------------------------------------------
@ -1764,12 +1785,30 @@ public class ChallengesManager
}
/**
* This method returns list of challenge levels in given gameMode.
* @param world for which levels must be searched.
* @return List with challengeLevel uniqueIds in given world.
*/
public List<String> getLevelNames(@NonNull World world)
{
return this.islandWorldManager.getAddon(world).map(gameMode ->
this.levelCacheData.values().stream().
sorted(ChallengeLevel::compareTo).
filter(level -> level.matchGameMode(gameMode.getDescription().getName())).
map(ChallengeLevel::getUniqueId).
collect(Collectors.toList())).
orElse(Collections.emptyList());
}
/**
* Get challenge level by its challenge.
*
* @param challenge - challenge which level must be returned.
* @return - challenge level or null if it does not exist
*/
@Nullable
public ChallengeLevel getLevel(Challenge challenge)
{
if (!challenge.getLevel().equals(FREE))
@ -1787,6 +1826,7 @@ public class ChallengesManager
* @param name - unique name of challenge level
* @return - challenge level or null if it does not exist
*/
@Nullable
public ChallengeLevel getLevel(String name)
{
if (this.levelCacheData.containsKey(name))
@ -1854,7 +1894,7 @@ public class ChallengesManager
/**
* This method adds given challenge to given challenge level.
* @param newChallenge Challenge who must change owner.
* @param newLevel Level who must add new challenge
* @param newLevel Level to add to - must exist already
*/
public void addChallengeToLevel(Challenge newChallenge, ChallengeLevel newLevel)
{
@ -1870,7 +1910,7 @@ public class ChallengesManager
{
ChallengeLevel oldLevel = this.getLevel(newChallenge.getLevel());
if (!oldLevel.equals(newLevel))
if (oldLevel == null || !oldLevel.equals(newLevel))
{
this.removeChallengeFromLevel(newChallenge, newLevel);
newLevel.getChallenges().add(newChallenge.getUniqueId());
@ -1905,6 +1945,7 @@ public class ChallengesManager
* @param uniqueID - new ID for challenge level.
* @return ChallengeLevel that is currently created.
*/
@Nullable
public ChallengeLevel createLevel(String uniqueID, World world)
{
if (!this.containsLevel(uniqueID))
@ -1952,7 +1993,7 @@ public class ChallengesManager
this.levelDatabase.deleteObject(challengeLevel);
this.addon.getPlugin().getPlaceholdersManager().
unregisterPlaceholder("challenges_completed_challenge_count_per_level_" + challengeLevel.getUniqueId());
unregisterPlaceholder("challenges_completed_challenge_count_per_level_" + challengeLevel.getUniqueId());
}
}
@ -1965,7 +2006,7 @@ public class ChallengesManager
public boolean hasAnyChallengeData(@NonNull World world)
{
return this.islandWorldManager.getAddon(world).filter(gameMode ->
this.hasAnyChallengeData(gameMode.getDescription().getName())).isPresent();
this.hasAnyChallengeData(gameMode.getDescription().getName())).isPresent();
}
@ -1977,8 +2018,47 @@ public class ChallengesManager
public boolean hasAnyChallengeData(@NonNull String gameMode)
{
return this.challengeDatabase.loadObjects().stream().anyMatch(
challenge -> challenge.matchGameMode(gameMode)) ||
this.levelDatabase.loadObjects().stream().anyMatch(
level -> level.matchGameMode(gameMode));
challenge -> challenge.matchGameMode(gameMode)) ||
this.levelDatabase.loadObjects().stream().anyMatch(
level -> level.matchGameMode(gameMode));
}
/**
* This method returns number of levels in given world.
* @param world World where level count must be returned.
* @return Number of levels in given world.
*/
public int getLevelCount(World world)
{
return this.getLevels(world).size();
}
/**
* This method returns number of completed levels in given world.
* @param user User which completed level count must be returned.
* @param world World where level count must be returned.
* @return Number of completed levels by given user in given world.
*/
public long getCompletedLevelCount(User user, World world)
{
return this.getAllChallengeLevelStatus(user, world).stream().
filter(LevelStatus::isComplete).
count();
}
/**
* This method returns number of unlocked levels in given world.
* @param user User which unlocked level count must be returned.
* @param world World where level count must be returned.
* @return Number of unlocked levels by given user in given world.
*/
public long getUnlockedLevelCount(User user, World world)
{
return this.getAllChallengeLevelStatus(user, world).stream().
filter(LevelStatus::isUnlocked).
count();
}
}

View File

@ -1,12 +1,11 @@
package world.bentobox.challenges.commands;
import java.util.List;
import java.util.Optional;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.panel.user.ChallengesGUI;
@ -27,10 +26,7 @@ public class ChallengesCommand extends CompositeCommand
@Override
public boolean canExecute(User user, String label, List<String> args)
{
Optional<GameModeAddon> optionalAddon = this.getAddon().getPlugin().getIWM().getAddon(this.getWorld());
if (!optionalAddon.isPresent())
{
if (!getIWM().inWorld(getWorld())) {
// Not a GameMode world.
user.sendMessage("general.errors.wrong-world");
return false;
@ -39,13 +35,14 @@ public class ChallengesCommand extends CompositeCommand
if (!((ChallengesAddon) this.getAddon()).getChallengesManager().hasAnyChallengeData(this.getWorld()))
{
// Do not open gui if there is no challenges.
this.getAddon().getLogger().severe("There are no challenges set up in " + this.getWorld() + "!");
this.getAddon().logError("There are no challenges set up in " + this.getWorld() + "!");
// Show admin better explanation.
if (user.isOp() || user.hasPermission(this.getPermissionPrefix() + "admin.challenges"))
{
String topLabel = optionalAddon.get().getAdminCommand().orElseGet(this::getParent).getTopLabel();
String topLabel = getIWM().getAddon(this.getWorld())
.map(GameModeAddon::getAdminCommand)
.map(optionalAdminCommand -> optionalAdminCommand.map(ac -> ac.getTopLabel()).orElse(this.getTopLabel())).orElse(this.getTopLabel());
user.sendMessage("challenges.errors.no-challenges-admin", "[command]", topLabel + " challenges");
}
else
@ -56,7 +53,7 @@ public class ChallengesCommand extends CompositeCommand
return false;
}
if (this.getPlugin().getIslands().getIsland(this.getWorld(), user.getUniqueId()) == null)
if (this.getIslands().getIsland(this.getWorld(), user) == null)
{
// Do not open gui if there is no island for this player.
user.sendMessage("general.errors.no-island");

View File

@ -6,7 +6,6 @@ import java.util.List;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.config.SettingsUtils.GuiMode;
import world.bentobox.challenges.panel.GameModesGUI;

View File

@ -1,7 +1,9 @@
package world.bentobox.challenges.commands;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.addons.Addon;
@ -19,128 +21,128 @@ import world.bentobox.challenges.utils.Utils;
*/
public class CompleteChallengeCommand extends CompositeCommand
{
/**
* Default constructor for Composite Command.
* @param addon Challenges addon.
* @param cmd Parent Command.
*/
public CompleteChallengeCommand(Addon addon, CompositeCommand cmd)
{
super(addon, cmd, "complete");
this.addon = (ChallengesAddon) addon;
}
/**
* Default constructor for Composite Command.
* @param addon Challenges addon.
* @param cmd Parent Command.
*/
public CompleteChallengeCommand(Addon addon, CompositeCommand cmd)
{
super(addon, cmd, "complete");
this.addon = (ChallengesAddon) addon;
}
/**
* {@inheritDoc}
*/
@Override
public void setup()
{
this.setOnlyPlayer(true);
this.setPermission("complete");
this.setParametersHelp("challenges.commands.user.complete.parameters");
this.setDescription("challenges.commands.user.complete.description");
}
/**
* {@inheritDoc}
*/
@Override
public void setup()
{
this.setOnlyPlayer(true);
this.setPermission("complete");
this.setParametersHelp("challenges.commands.user.complete.parameters");
this.setDescription("challenges.commands.user.complete.description");
}
/**
* {@inheritDoc}
*/
@Override
public boolean execute(User user, String label, List<String> args)
{
if (args.isEmpty())
{
user.sendMessage("challenges.errors.no-name");
this.showHelp(this, user);
return false;
}
else if (!args.get(0).isEmpty())
{
// Add world name back at the start
String challengeName = Utils.getGameMode(this.getWorld()) + "_" + args.get(0);
Challenge challenge = this.addon.getChallengesManager().getChallenge(challengeName);
/**
* {@inheritDoc}
*/
@Override
public boolean execute(User user, String label, List<String> args)
{
if (args.isEmpty())
{
user.sendMessage("challenges.errors.no-name");
this.showHelp(this, user);
return false;
}
else
{
// Add world name back at the start
String challengeName = Utils.getGameMode(this.getWorld()) + "_" + args.get(0);
Challenge challenge = this.addon.getChallengesManager().getChallenge(challengeName);
if (challenge != null)
{
int count = args.size() == 2 ? Integer.valueOf(args.get(1)) : 1;
if (challenge != null)
{
int count = args.size() == 2 ? Integer.valueOf(args.get(1)) : 1;
boolean canMultipleTimes =
user.hasPermission(this.getPermission() + ".multiple");
boolean canMultipleTimes =
user.hasPermission(this.getPermission() + ".multiple");
if (!canMultipleTimes && count > 1)
{
user.sendMessage("challenges.error.no-multiple-permission");
count = 1;
}
if (!canMultipleTimes && count > 1)
{
user.sendMessage("challenges.error.no-multiple-permission");
count = 1;
}
return TryToComplete.complete(this.addon,
user,
challenge,
this.getWorld(),
this.getTopLabel(),
this.getPermissionPrefix(),
count);
}
else
{
user.sendMessage("challenges.errors.unknown-challenge");
this.showHelp(this, user);
return false;
}
}
this.showHelp(this, user);
return false;
}
return TryToComplete.complete(this.addon,
user,
challenge,
this.getWorld(),
this.getTopLabel(),
this.getPermissionPrefix(),
count);
}
else
{
user.sendMessage("challenges.errors.unknown-challenge");
this.showHelp(this, user);
return false;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args)
{
String lastString = args.get(args.size() - 1);
/**
* {@inheritDoc}
*/
@Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args)
{
if (args.isEmpty()) return Optional.empty();
final List<String> returnList = new ArrayList<>();
final int size = args.size();
String lastString = args.get(args.size() - 1);
switch (size)
{
case 3:
// Create suggestions with all challenges that is available for users.
returnList.addAll(this.addon.getChallengesManager().getAllChallengesNames(this.getWorld()).stream().
map(challenge -> challenge.substring(Utils.getGameMode(this.getWorld()).length() + 1)).
collect(Collectors.toList()));
final List<String> returnList = new ArrayList<>();
final int size = args.size();
break;
case 4:
// Suggest a number of completions.
if (lastString.isEmpty() || lastString.matches("[0-9]*"))
{
returnList.add("<number>");
}
switch (size)
{
case 3:
break;
default:
{
returnList.add("help");
break;
}
}
// Create suggestions with all challenges that is available for users.
returnList.addAll(this.addon.getChallengesManager().getAllChallengesNames(this.getWorld()).stream().
filter(challenge -> challenge.startsWith(Utils.getGameMode(this.getWorld()) + "_")).
map(challenge -> challenge.substring(Utils.getGameMode(this.getWorld()).length() + 1)).
collect(Collectors.toList()));
break;
case 4:
// Suggest a number of completions.
if (lastString.isEmpty() || lastString.matches("[0-9]*"))
{
returnList.add("<number>");
}
return Optional.of(Util.tabLimit(returnList, lastString));
}
break;
default:
{
returnList.add("help");
break;
}
}
return Optional.of(Util.tabLimit(returnList, lastString));
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* Variable that holds challenge addon. Single casting.
*/
private ChallengesAddon addon;
/**
* Variable that holds challenge addon. Single casting.
*/
private ChallengesAddon addon;
}

View File

@ -2,9 +2,9 @@ package world.bentobox.challenges.commands.admin;
import java.util.List;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.panel.admin.AdminGUI;

View File

@ -1,7 +1,11 @@
package world.bentobox.challenges.commands.admin;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.addons.Addon;

View File

@ -2,11 +2,11 @@ package world.bentobox.challenges.commands.admin;
import java.util.List;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.ChallengesManager;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.ChallengesManager;
/**

View File

@ -1,7 +1,11 @@
package world.bentobox.challenges.commands.admin;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.addons.Addon;

View File

@ -1,12 +1,11 @@
package world.bentobox.challenges.commands.admin;
import java.util.List;
import java.util.logging.Level;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.ChallengesAddon;
public class ShowChallenges extends CompositeCommand {

View File

@ -13,10 +13,9 @@ import world.bentobox.bentobox.api.configuration.ConfigComment;
import world.bentobox.bentobox.api.configuration.ConfigEntry;
import world.bentobox.bentobox.api.configuration.ConfigObject;
import world.bentobox.bentobox.api.configuration.StoreAt;
import world.bentobox.bentobox.database.objects.adapters.Adapter;
import world.bentobox.challenges.config.SettingsUtils.GuiMode;
import world.bentobox.challenges.config.SettingsUtils.ChallengeLore;
import world.bentobox.challenges.config.SettingsUtils.GuiMode;
import world.bentobox.challenges.config.SettingsUtils.LevelLore;
import world.bentobox.challenges.config.SettingsUtils.VisibilityMode;
import world.bentobox.challenges.database.object.adapters.ChallengeLoreAdapter;

View File

@ -13,6 +13,7 @@ import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.NonNull;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.JsonAdapter;
@ -717,7 +718,7 @@ public class Challenge implements DataObject
* This method sets the level value.
* @param level the level new value.
*/
public void setLevel(String level)
public void setLevel(@NonNull String level)
{
this.level = level;
}
@ -1050,7 +1051,7 @@ public class Challenge implements DataObject
public boolean matchGameMode(String gameMode)
{
return gameMode != null &&
this.uniqueId.regionMatches(true, 0, gameMode, 0, gameMode.length());
this.uniqueId.regionMatches(true, 0, gameMode, 0, gameMode.length());
}
@ -1129,7 +1130,7 @@ public class Challenge implements DataObject
clone.setRequirements(this.requirements.clone());
clone.setRewardText(this.rewardText);
clone.setRewardItems(this.rewardItems.stream().map(ItemStack::clone).
collect(Collectors.toCollection(() -> new ArrayList<>(this.rewardItems.size()))));
collect(Collectors.toCollection(() -> new ArrayList<>(this.rewardItems.size()))));
clone.setRewardExperience(this.rewardExperience);
clone.setRewardMoney(this.rewardMoney);
clone.setRewardCommands(new ArrayList<>(this.rewardCommands));
@ -1138,7 +1139,7 @@ public class Challenge implements DataObject
clone.setMaxTimes(this.maxTimes);
clone.setRepeatExperienceReward(this.repeatExperienceReward);
clone.setRepeatItemReward(this.repeatItemReward.stream().map(ItemStack::clone).
collect(Collectors.toCollection(() -> new ArrayList<>(this.repeatItemReward.size()))));
collect(Collectors.toCollection(() -> new ArrayList<>(this.repeatItemReward.size()))));
clone.setRepeatMoneyReward(this.repeatMoneyReward);
clone.setRepeatRewardCommands(new ArrayList<>(this.repeatRewardCommands));
}

View File

@ -1,15 +1,17 @@
package world.bentobox.challenges.database.object;
import com.google.gson.annotations.Expose;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import com.google.gson.annotations.Expose;
import world.bentobox.bentobox.api.configuration.ConfigComment;
import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.challenges.ChallengesManager;

View File

@ -1,9 +1,16 @@
package world.bentobox.challenges.database.object;
import com.google.gson.annotations.Expose;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.eclipse.jdt.annotation.NonNull;
import java.util.*;
import com.google.gson.annotations.Expose;
import world.bentobox.bentobox.api.logs.LogEntry;
import world.bentobox.bentobox.database.objects.DataObject;
@ -18,334 +25,334 @@ import world.bentobox.bentobox.database.objects.adapters.LogEntryListAdapter;
*/
public class ChallengesPlayerData implements DataObject
{
/**
* Constructor ChallengesPlayerData creates a new ChallengesPlayerData instance.
*/
public ChallengesPlayerData()
{
}
/**
* Constructor ChallengesPlayerData creates a new ChallengesPlayerData instance.
*/
public ChallengesPlayerData()
{
}
/**
* Creates a player data entry
*
* @param uniqueId - the player's UUID in string format
*/
public ChallengesPlayerData(String uniqueId)
{
this.uniqueId = uniqueId;
}
/**
* Creates a player data entry
*
* @param uniqueId - the player's UUID in string format
*/
public ChallengesPlayerData(String uniqueId)
{
this.uniqueId = uniqueId;
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* This variable stores each player UUID as string.
*/
@Expose
private String uniqueId = "";
/**
* This variable stores each player UUID as string.
*/
@Expose
private String uniqueId = "";
/**
* Challenge map, where key = unique challenge name and Value = number of times
* completed
*/
@Expose
private Map<String, Integer> challengeStatus = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
/**
* Challenge map, where key = unique challenge name and Value = number of times
* completed
*/
@Expose
private Map<String, Integer> challengeStatus = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
/**
* Map of challenges completion time where key is challenges unique id and value is
* timestamp when challenge was completed last time.
*/
@Expose
private Map<String, Long> challengesTimestamp = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
/**
* Map of challenges completion time where key is challenges unique id and value is
* timestamp when challenge was completed last time.
*/
@Expose
private Map<String, Long> challengesTimestamp = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
/**
* Set of Strings that contains all challenge levels that are completed.
*/
@Expose
private Set<String> levelsDone = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
/**
* Set of Strings that contains all challenge levels that are completed.
*/
@Expose
private Set<String> levelsDone = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
/**
* Stores history about challenge completion.
*/
@Adapter(LogEntryListAdapter.class)
@Expose
private List<LogEntry> history = new LinkedList<>();
/**
* Stores history about challenge completion.
*/
@Adapter(LogEntryListAdapter.class)
@Expose
private List<LogEntry> history = new LinkedList<>();
// ---------------------------------------------------------------------
// Section: Getters
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Getters
// ---------------------------------------------------------------------
/**
* @return uniqueID
* @see DataObject#getUniqueId()
*/
@Override
public String getUniqueId()
{
return uniqueId;
}
/**
* @return uniqueID
* @see DataObject#getUniqueId()
*/
@Override
public String getUniqueId()
{
return uniqueId;
}
/**
* This method returns the challengeStatus value.
* @return the value of challengeStatus.
*/
public Map<String, Integer> getChallengeStatus()
{
return challengeStatus;
}
/**
* This method returns the challengeStatus value.
* @return the value of challengeStatus.
*/
public Map<String, Integer> getChallengeStatus()
{
return challengeStatus;
}
/**
* This method returns the challengesTimestamp value.
* @return the value of challengesTimestamp.
*/
public Map<String, Long> getChallengesTimestamp()
{
return challengesTimestamp;
}
/**
* This method returns the challengesTimestamp value.
* @return the value of challengesTimestamp.
*/
public Map<String, Long> getChallengesTimestamp()
{
return challengesTimestamp;
}
/**
* This method returns the levelsDone value.
* @return the value of levelsDone.
*/
public Set<String> getLevelsDone()
{
return levelsDone;
}
/**
* This method returns the levelsDone value.
* @return the value of levelsDone.
*/
public Set<String> getLevelsDone()
{
return levelsDone;
}
/**
* This method returns the history object.
* @return the history object.
*/
public List<LogEntry> getHistory()
{
return history;
}
/**
* This method returns the history object.
* @return the history object.
*/
public List<LogEntry> getHistory()
{
return history;
}
// ---------------------------------------------------------------------
// Section: Setters
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Setters
// ---------------------------------------------------------------------
/**
* @param uniqueId - unique ID the uniqueId to set
* @see DataObject#setUniqueId(String)
*/
@Override
public void setUniqueId(String uniqueId)
{
this.uniqueId = uniqueId;
}
/**
* @param uniqueId - unique ID the uniqueId to set
* @see DataObject#setUniqueId(String)
*/
@Override
public void setUniqueId(String uniqueId)
{
this.uniqueId = uniqueId;
}
/**
* This method sets the challengeStatus value.
* @param challengeStatus the challengeStatus new value.
*
*/
public void setChallengeStatus(Map<String, Integer> challengeStatus)
{
this.challengeStatus = challengeStatus;
}
/**
* This method sets the challengeStatus value.
* @param challengeStatus the challengeStatus new value.
*
*/
public void setChallengeStatus(Map<String, Integer> challengeStatus)
{
this.challengeStatus = challengeStatus;
}
/**
* This method sets the challengesTimestamp value.
* @param challengesTimestamp the challengesTimestamp new value.
*
*/
public void setChallengesTimestamp(Map<String, Long> challengesTimestamp)
{
this.challengesTimestamp = challengesTimestamp;
}
/**
* This method sets the challengesTimestamp value.
* @param challengesTimestamp the challengesTimestamp new value.
*
*/
public void setChallengesTimestamp(Map<String, Long> challengesTimestamp)
{
this.challengesTimestamp = challengesTimestamp;
}
/**
* This method sets the levelsDone value.
* @param levelsDone the levelsDone new value.
*
*/
public void setLevelsDone(Set<String> levelsDone)
{
this.levelsDone = levelsDone;
}
/**
* This method sets the levelsDone value.
* @param levelsDone the levelsDone new value.
*
*/
public void setLevelsDone(Set<String> levelsDone)
{
this.levelsDone = levelsDone;
}
/**
* This method sets the history object value.
* @param history the history object new value.
*/
public void setHistory(List<LogEntry> history)
{
this.history = history;
}
/**
* This method sets the history object value.
* @param history the history object new value.
*/
public void setHistory(List<LogEntry> history)
{
this.history = history;
}
// ---------------------------------------------------------------------
// Section: Other Methods
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Other Methods
// ---------------------------------------------------------------------
/**
* Resets all challenges and levels in GameMode for this player
*
* @param gameMode GameMode which challenges must be reset.
*/
public void reset(@NonNull String gameMode)
{
challengeStatus.keySet().removeIf(n -> n.regionMatches(true, 0, gameMode, 0, gameMode.length()));
challengesTimestamp.keySet().removeIf(n -> n.regionMatches(true, 0, gameMode, 0, gameMode.length()));
levelsDone.removeIf(n -> n.regionMatches(true, 0, gameMode, 0, gameMode.length()));
}
/**
* Resets all challenges and levels in GameMode for this player
*
* @param gameMode GameMode which challenges must be reset.
*/
public void reset(@NonNull String gameMode)
{
challengeStatus.keySet().removeIf(n -> n.regionMatches(true, 0, gameMode, 0, gameMode.length()));
challengesTimestamp.keySet().removeIf(n -> n.regionMatches(true, 0, gameMode, 0, gameMode.length()));
levelsDone.removeIf(n -> n.regionMatches(true, 0, gameMode, 0, gameMode.length()));
}
/**
* Mark a challenge as having been completed. Will increment the number of times and
* timestamp
*
* @param challengeName - unique challenge name
*/
public void setChallengeDone(@NonNull String challengeName)
{
this.addChallengeDone(challengeName, 1);
}
/**
* Mark a challenge as having been completed. Will increment the number of times and
* timestamp
*
* @param challengeName - unique challenge name
*/
public void setChallengeDone(@NonNull String challengeName)
{
this.addChallengeDone(challengeName, 1);
}
/**
* Mark a challenge as having been completed. Will increment the number of times and
* timestamp
*
* @param challengeName - unique challenge name
* @param times - how many new times should be added
*/
public void addChallengeDone(@NonNull String challengeName, int times)
{
int newTimes = challengeStatus.getOrDefault(challengeName, 0) + times;
challengeStatus.put(challengeName, newTimes);
challengesTimestamp.put(challengeName, System.currentTimeMillis());
}
/**
* Mark a challenge as having been completed. Will increment the number of times and
* timestamp
*
* @param challengeName - unique challenge name
* @param times - how many new times should be added
*/
public void addChallengeDone(@NonNull String challengeName, int times)
{
int newTimes = challengeStatus.getOrDefault(challengeName, 0) + times;
challengeStatus.put(challengeName, newTimes);
challengesTimestamp.put(challengeName, System.currentTimeMillis());
}
/**
* Set the number of times a challenge has been done
*
* @param challengeName - unique challenge name
* @param times - the number of times to set
*/
public void setChallengeTimes(@NonNull String challengeName, @NonNull int times)
{
challengeStatus.put(challengeName, times);
challengesTimestamp.put(challengeName, System.currentTimeMillis());
}
/**
* Set the number of times a challenge has been done
*
* @param challengeName - unique challenge name
* @param times - the number of times to set
*/
public void setChallengeTimes(@NonNull String challengeName, @NonNull int times)
{
challengeStatus.put(challengeName, times);
challengesTimestamp.put(challengeName, System.currentTimeMillis());
}
/**
* Check if a challenge has been done
*
* @param challengeName - unique challenge name
* @return true if done at least once
*/
public boolean isChallengeDone(@NonNull String challengeName)
{
return this.getTimes(challengeName) > 0;
}
/**
* Check if a challenge has been done
*
* @param challengeName - unique challenge name
* @return true if done at least once
*/
public boolean isChallengeDone(@NonNull String challengeName)
{
return this.getTimes(challengeName) > 0;
}
/**
* Check how many times a challenge has been done
*
* @param challengeName - unique challenge name
* @return - number of times
*/
public int getTimes(@NonNull String challengeName)
{
return challengeStatus.getOrDefault(challengeName, 0);
}
/**
* Check how many times a challenge has been done
*
* @param challengeName - unique challenge name
* @return - number of times
*/
public int getTimes(@NonNull String challengeName)
{
return challengeStatus.getOrDefault(challengeName, 0);
}
/**
* This method adds given level id to completed level set.
* @param uniqueId from ChallengeLevel object.
*/
public void addCompletedLevel(@NonNull String uniqueId)
{
this.levelsDone.add(uniqueId);
}
/**
* This method adds given level id to completed level set.
* @param uniqueId from ChallengeLevel object.
*/
public void addCompletedLevel(@NonNull String uniqueId)
{
this.levelsDone.add(uniqueId);
}
/**
* This method returns if given level is done.
* @param uniqueId of ChallengeLevel object.
* @return <code>true</code> if level is completed, otherwise <code>false</code>
*/
public boolean isLevelDone(@NonNull String uniqueId)
{
return !this.levelsDone.isEmpty() && this.levelsDone.contains(uniqueId);
}
/**
* This method returns if given level is done.
* @param uniqueId of ChallengeLevel object.
* @return <code>true</code> if level is completed, otherwise <code>false</code>
*/
public boolean isLevelDone(@NonNull String uniqueId)
{
return !this.levelsDone.isEmpty() && this.levelsDone.contains(uniqueId);
}
/**
* This method adds given LogEntry to history.
*
* @param entry of type LogEntry
*/
public void addHistoryRecord(@NonNull LogEntry entry)
{
this.history.add(entry);
}
/**
* This method adds given LogEntry to history.
*
* @param entry of type LogEntry
*/
public void addHistoryRecord(@NonNull LogEntry entry)
{
this.history.add(entry);
}
/**
* @see Object#hashCode()
* @return object hashCode value.
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode());
return result;
}
/**
* @see Object#hashCode()
* @return object hashCode value.
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode());
return result;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
* @param obj Other object.
* @return boolean that indicate if objects are equals.
*/
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
* @param obj Other object.
* @return boolean that indicate if objects are equals.
*/
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (!(obj instanceof ChallengesPlayerData))
{
return false;
}
if (!(obj instanceof ChallengesPlayerData))
{
return false;
}
ChallengesPlayerData other = (ChallengesPlayerData) obj;
ChallengesPlayerData other = (ChallengesPlayerData) obj;
if (uniqueId == null)
{
return other.uniqueId == null;
}
else
{
return uniqueId.equalsIgnoreCase(other.uniqueId);
}
}
if (uniqueId == null)
{
return other.uniqueId == null;
}
else
{
return uniqueId.equalsIgnoreCase(other.uniqueId);
}
}
}

View File

@ -7,6 +7,8 @@
package world.bentobox.challenges.database.object.adapters;
import java.lang.reflect.Type;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
@ -15,7 +17,6 @@ import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import world.bentobox.challenges.database.object.requirements.Requirements;

View File

@ -7,13 +7,15 @@
package world.bentobox.challenges.database.object.requirements;
import com.google.gson.annotations.Expose;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import org.bukkit.inventory.ItemStack;
import com.google.gson.annotations.Expose;
/**
* This class contains all necessary requirements to complete inventory type challenge.

View File

@ -7,14 +7,16 @@
package world.bentobox.challenges.database.object.requirements;
import com.google.gson.annotations.Expose;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import com.google.gson.annotations.Expose;
/**
* This class contains all necessary requirements to complete island type challenge.

View File

@ -7,12 +7,9 @@
package world.bentobox.challenges.database.object.requirements;
import com.google.gson.annotations.Expose;
import org.eclipse.jdt.annotation.NonNull;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.google.gson.annotations.Expose;
/**

View File

@ -7,10 +7,11 @@
package world.bentobox.challenges.database.object.requirements;
import com.google.gson.annotations.Expose;
import java.util.HashSet;
import java.util.Set;
import com.google.gson.annotations.Expose;
/**
* This abstract class allows to define requirements for each challenge.

View File

@ -5,7 +5,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import world.bentobox.bentobox.api.addons.request.AddonRequestHandler;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.database.object.Challenge;

View File

@ -1,10 +1,11 @@
package world.bentobox.challenges.handlers;
import org.bukkit.Bukkit;
import java.util.Collections;
import java.util.Map;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.addons.request.AddonRequestHandler;
import world.bentobox.challenges.ChallengesAddon;

View File

@ -1,10 +1,13 @@
package world.bentobox.challenges.handlers;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.World;
import java.util.*;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.addons.request.AddonRequestHandler;
import world.bentobox.challenges.ChallengesAddon;

View File

@ -1,10 +1,11 @@
package world.bentobox.challenges.handlers;
import org.bukkit.Bukkit;
import java.util.Collections;
import java.util.Map;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.addons.request.AddonRequestHandler;
import world.bentobox.challenges.ChallengesAddon;
@ -51,7 +52,8 @@ public class LevelListRequestHandler extends AddonRequestHandler
return Collections.emptyList();
}
return this.addon.getChallengesManager().getLevels(Bukkit.getWorld((String) metaData.get("world-name")));
return this.addon.getChallengesManager().getLevelNames(
Bukkit.getWorld((String) metaData.get("world-name")));
}

View File

@ -7,10 +7,9 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
import world.bentobox.challenges.ChallengesAddon;
/**
* Resets challenges when the island is reset

View File

@ -6,7 +6,6 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.world.WorldSaveEvent;
import world.bentobox.challenges.ChallengesAddon;

View File

@ -9,7 +9,11 @@ import java.util.function.Consumer;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.conversations.*;
import org.bukkit.conversations.Conversation;
import org.bukkit.conversations.ConversationContext;
import org.bukkit.conversations.ConversationFactory;
import org.bukkit.conversations.Prompt;
import org.bukkit.conversations.StringPrompt;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -1078,6 +1082,10 @@ public abstract class CommonGUI
}
}).
withLocalEcho(false).
// On cancel conversation will be closed.
withEscapeSequence("cancel").
// Use null value in consumer to detect if user has abandoned conversation.
addConversationAbandonedListener(abandonedEvent -> consumer.accept(null)).
withPrefix(context -> user.getTranslation("challenges.gui.questions.prefix")).
buildConversation(user.getPlayer());

View File

@ -1,12 +1,12 @@
package world.bentobox.challenges.panel;
import org.bukkit.Material;
import org.bukkit.World;
import java.util.List;
import java.util.Optional;
import org.bukkit.Material;
import org.bukkit.World;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.panels.PanelItem;

View File

@ -1,19 +1,16 @@
package world.bentobox.challenges.panel.admin;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.conversations.Conversation;
import org.bukkit.conversations.ConversationContext;
import org.bukkit.conversations.ConversationFactory;
import org.bukkit.conversations.Prompt;
import org.bukkit.conversations.ValidatingPrompt;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.NonNull;
import java.util.Locale;
import java.util.function.Consumer;
import java.util.function.Function;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.conversations.*;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
@ -251,24 +248,31 @@ public class AdminGUI extends CommonGUI
icon = new ItemStack(Material.BOOK);
clickHandler = (panel, user, clickType, slot) -> {
this.getNewUniqueID(challenge -> {
String newName = Utils.getGameMode(this.world) + "_" + challenge;
this.getNewUniqueID(challenge ->
{
if (challenge == null)
{
// Build Admin Gui if input is null.
this.build();
}
else
{
String uniqueId = Utils.getGameMode(this.world) + "_" + challenge;
ChallengeTypeGUI.open(user,
this.addon.getChallengesSettings().getLoreLineLength(),
(type, requirements) -> {
new EditChallengeGUI(this.addon,
this.world,
this.user,
this.addon.getChallengesManager().createChallenge(newName, type, requirements),
this.topLabel,
this.permissionPrefix,
this).build();
});
ChallengeTypeGUI.open(user,
this.addon.getChallengesSettings().getLoreLineLength(),
(type, requirements) -> new EditChallengeGUI(this.addon,
this.world,
this.user,
this.addon.getChallengesManager().createChallenge(uniqueId, type, requirements),
this.topLabel,
this.permissionPrefix,
this).build());
}
},
input -> {
String newName = Utils.getGameMode(this.world) + "_" + input;
return !this.addon.getChallengesManager().containsChallenge(newName);
String uniqueId = Utils.getGameMode(this.world) + "_" + input;
return !this.addon.getChallengesManager().containsChallenge(uniqueId);
},
this.user.getTranslation("challenges.gui.questions.admin.unique-id")
);
@ -286,16 +290,25 @@ public class AdminGUI extends CommonGUI
icon = new ItemStack(Material.BOOK);
clickHandler = (panel, user, clickType, slot) -> {
this.getNewUniqueID(level -> {
String newName = Utils.getGameMode(this.world) + "_" + level;
this.getNewUniqueID(level ->
{
if (level == null)
{
// Build Admin Gui if input is null.
this.build();
}
else
{
String newName = Utils.getGameMode(this.world) + "_" + level;
new EditLevelGUI(this.addon,
this.world,
this.user,
this.addon.getChallengesManager().createLevel(newName, this.world),
this.topLabel,
this.permissionPrefix,
this).build();
new EditLevelGUI(this.addon,
this.world,
this.user,
this.addon.getChallengesManager().createLevel(newName, this.world),
this.topLabel,
this.permissionPrefix,
this).build();
}
},
input -> {
String newName = Utils.getGameMode(this.world) + "_" + input;
@ -659,7 +672,7 @@ public class AdminGUI extends CommonGUI
@Override
protected boolean isInputValid(ConversationContext context, String input)
{
return stringValidation.apply(input);
return stringValidation.apply(GuiUtils.sanitizeInput(input));
}
@ -679,7 +692,7 @@ public class AdminGUI extends CommonGUI
protected String getFailedValidationText(ConversationContext context,
String invalidInput)
{
return user.getTranslation("challenges.errors.unique-id", "[id]", invalidInput);
return user.getTranslation("challenges.errors.unique-id", "[id]", GuiUtils.sanitizeInput(invalidInput));
}
@ -699,11 +712,15 @@ public class AdminGUI extends CommonGUI
protected Prompt acceptValidatedInput(ConversationContext context, String input)
{
// Add answer to consumer.
consumer.accept(input);
consumer.accept(GuiUtils.sanitizeInput(input));
// End conversation
return Prompt.END_OF_CONVERSATION;
}
}).
// On cancel conversation will be closed.
withEscapeSequence("cancel").
// Use null value in consumer to detect if user has abandoned conversation.
addConversationAbandonedListener(abandonedEvent -> consumer.accept(null)).
withLocalEcho(false).
withPrefix(context -> user.getTranslation("challenges.gui.questions.prefix")).
buildConversation(user.getPlayer());

View File

@ -1,10 +1,6 @@
package world.bentobox.challenges.panel.admin;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@ -12,6 +8,11 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
@ -499,7 +500,11 @@ public class EditChallengeGUI extends CommonGUI
clickHandler = (panel, user, clickType, slot) -> {
this.getFriendlyName(reply -> {
this.challenge.setFriendlyName(reply);
if (reply != null)
{
this.challenge.setFriendlyName(reply);
}
this.build();
},
this.user.getTranslation("challenges.gui.questions.admin.challenge-name"),

View File

@ -22,7 +22,11 @@ import world.bentobox.challenges.ChallengesManager;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.panel.CommonGUI;
import world.bentobox.challenges.panel.util.*;
import world.bentobox.challenges.panel.util.ItemSwitchGUI;
import world.bentobox.challenges.panel.util.NumberGUI;
import world.bentobox.challenges.panel.util.SelectBlocksGUI;
import world.bentobox.challenges.panel.util.SelectChallengeGUI;
import world.bentobox.challenges.panel.util.StringListGUI;
import world.bentobox.challenges.utils.GuiUtils;
import world.bentobox.challenges.utils.Utils;
@ -334,9 +338,13 @@ public class EditLevelGUI extends CommonGUI
icon = new ItemStack(Material.DROPPER);
clickHandler = (panel, user, clickType, slot) -> {
this.getFriendlyName(reply -> {
this.challengeLevel.setFriendlyName(reply);
this.build();
this.getFriendlyName(reply ->
{
if (reply != null)
{
this.challengeLevel.setFriendlyName(reply);
}
this.build();
},
this.user.getTranslation("challenges.gui.questions.admin.level-name"),
this.challengeLevel.getFriendlyName()

View File

@ -128,7 +128,6 @@ public class EditSettingsGUI extends CommonGUI
}
@SuppressWarnings("deprecation")
private PanelItem getSettingsButton(Button button)
{
ItemStack icon;
@ -434,7 +433,7 @@ public class EditSettingsGUI extends CommonGUI
if (status)
{
materials.forEach(material ->
this.settings.setLockedLevelIcon(new ItemStack(material)));
this.settings.setLockedLevelIcon(new ItemStack(material)));
}
this.build();
@ -501,14 +500,14 @@ public class EditSettingsGUI extends CommonGUI
values.add(this.user.getTranslation("challenges.gui.descriptions.admin.visibility-mode"));
values.add((this.settings.getVisibilityMode().equals(VisibilityMode.VISIBLE) ? "&2" : "&c") +
this.user.getTranslation("challenges.gui.descriptions.visibility.visible"));
this.user.getTranslation("challenges.gui.descriptions.visibility.visible"));
values.add((this.settings.getVisibilityMode().equals(VisibilityMode.HIDDEN) ? "&2" : "&c") +
this.user.getTranslation("challenges.gui.descriptions.visibility.hidden"));
this.user.getTranslation("challenges.gui.descriptions.visibility.hidden"));
values.add((this.settings.getVisibilityMode().equals(VisibilityMode.TOGGLEABLE) ? "&2" : "&c") +
this.user.getTranslation("challenges.gui.descriptions.visibility.toggleable"));
this.user.getTranslation("challenges.gui.descriptions.visibility.toggleable"));
values.add(this.user.getTranslation("challenges.gui.descriptions.current-value",
"[value]",this.settings.getVisibilityMode().name()));
"[value]",this.settings.getVisibilityMode().name()));
description = values;
@ -529,19 +528,19 @@ public class EditSettingsGUI extends CommonGUI
if (clickType.isRightClick())
{
this.settings.setVisibilityMode(
Utils.getPreviousValue(VisibilityMode.values(),
this.settings.getVisibilityMode()));
Utils.getPreviousValue(VisibilityMode.values(),
this.settings.getVisibilityMode()));
}
else
{
this.settings.setVisibilityMode(
Utils.getNextValue(VisibilityMode.values(),
this.settings.getVisibilityMode()));
Utils.getNextValue(VisibilityMode.values(),
this.settings.getVisibilityMode()));
}
// Rebuild just this icon
panel.getInventory().setItem(slot,
this.getSettingsButton(button).getItem());
this.getSettingsButton(button).getItem());
return true;
};

View File

@ -1,10 +1,11 @@
package world.bentobox.challenges.panel.admin;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.World;
import java.util.List;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;

View File

@ -1,10 +1,11 @@
package world.bentobox.challenges.panel.admin;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.World;
import java.util.List;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;

View File

@ -1,11 +1,12 @@
package world.bentobox.challenges.panel.admin;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.World;
import java.util.ArrayList;
import java.util.List;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;

View File

@ -1,16 +1,17 @@
package world.bentobox.challenges.panel.admin;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Player;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;

View File

@ -1,10 +1,16 @@
package world.bentobox.challenges.panel.admin;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.WordUtils;
import org.bukkit.Material;
import org.bukkit.World;
import java.util.*;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;

View File

@ -1,11 +1,17 @@
package world.bentobox.challenges.panel.admin;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.WordUtils;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import java.util.*;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;

View File

@ -1,11 +1,12 @@
package world.bentobox.challenges.panel.user;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
@ -77,7 +78,7 @@ public class ChallengesGUI extends CommonGUI
// Do not open gui if there is no challenges.
if (!this.challengesManager.hasAnyChallengeData(this.world))
{
this.addon.getLogger().severe("There are no challenges set up!");
this.addon.logError("There are no challenges set up!");
this.user.sendMessage("challenges.errors.no-challenges");
return;
}

View File

@ -1,10 +1,10 @@
package world.bentobox.challenges.panel.user;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.util.function.Consumer;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem;

View File

@ -7,12 +7,13 @@
package world.bentobox.challenges.panel.util;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;

View File

@ -1,10 +1,10 @@
package world.bentobox.challenges.panel.util;
import org.bukkit.Material;
import java.util.function.Consumer;
import org.bukkit.Material;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;

View File

@ -1,14 +1,15 @@
package world.bentobox.challenges.panel.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import org.bukkit.Material;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.PanelListener;

View File

@ -1,17 +1,20 @@
package world.bentobox.challenges.panel.util;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import org.apache.commons.lang.WordUtils;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.util.*;
import java.util.function.BiConsumer;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.utils.GuiUtils;
@ -28,7 +31,36 @@ public class SelectBlocksGUI
public SelectBlocksGUI(User user, boolean singleSelect, BiConsumer<Boolean, Set<Material>> consumer)
{
this(user, singleSelect, new HashSet<>(), consumer);
this.consumer = consumer;
this.user = user;
this.singleSelect = singleSelect;
// Current GUI cannot display air blocks. It crashes with null-pointer
Set<Material> excludedMaterial = new HashSet<>();
excludedMaterial.add(Material.AIR);
excludedMaterial.add(Material.CAVE_AIR);
excludedMaterial.add(Material.VOID_AIR);
// Piston head and moving piston is not necessary. useless.
excludedMaterial.add(Material.PISTON_HEAD);
excludedMaterial.add(Material.MOVING_PISTON);
// Barrier cannot be accessible to user.
excludedMaterial.add(Material.BARRIER);
this.elements = new ArrayList<>();
this.selectedMaterials = new HashSet<>();
for (Material material : Material.values())
{
if (!material.isLegacy() && !excludedMaterial.contains(material))
{
this.elements.add(material);
}
}
this.build(0);
}

View File

@ -1,17 +1,21 @@
package world.bentobox.challenges.panel.util;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.event.inventory.ClickType;
import java.util.*;
import java.util.function.BiConsumer;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.utils.GuiUtils;

View File

@ -1,18 +1,23 @@
package world.bentobox.challenges.panel.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import org.apache.commons.lang.WordUtils;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import java.util.*;
import java.util.function.BiConsumer;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.utils.GuiUtils;

View File

@ -1,12 +1,13 @@
package world.bentobox.challenges.panel.util;
import org.bukkit.Material;
import org.bukkit.World;
import java.util.Collections;
import java.util.Set;
import java.util.function.BiConsumer;
import org.bukkit.Material;
import org.bukkit.World;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;

View File

@ -1,11 +1,6 @@
package world.bentobox.challenges.panel.util;
import org.bukkit.Material;
import org.bukkit.conversations.*;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -13,6 +8,16 @@ import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.bukkit.Material;
import org.bukkit.conversations.Conversation;
import org.bukkit.conversations.ConversationContext;
import org.bukkit.conversations.ConversationFactory;
import org.bukkit.conversations.Prompt;
import org.bukkit.conversations.StringPrompt;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.TextComponent;
import world.bentobox.bentobox.BentoBox;
@ -151,7 +156,15 @@ public class StringListGUI
icon = new ItemStack(Material.WHITE_STAINED_GLASS_PANE);
clickHandler = (panel, user, clickType, slot) -> {
this.getStringInput(value -> this.value.add(value),
this.getStringInput(value -> {
if (value != null)
{
this.value.add(value);
}
// Reopen GUI.
this.build();
},
this.user.getTranslation("challenges.gui.descriptions.admin.add-text-line"));
return true;
@ -210,7 +223,15 @@ public class StringListGUI
clickHandler((panel, user1, clickType, i) -> {
this.getStringInput(
value -> this.value.set(stringIndex, value),
value -> {
if (value != null)
{
this.value.set(stringIndex, value);
}
// Reopen GUI
this.build();
},
this.user.getTranslation("challenges.gui.descriptions.admin.edit-text-line"),
element);
@ -277,12 +298,14 @@ public class StringListGUI
{
// Add answer to consumer.
consumer.accept(answer);
// Reopen GUI
StringListGUI.this.build();
// End conversation
return Prompt.END_OF_CONVERSATION;
}
}).
// On cancel conversation will be closed.
withEscapeSequence("cancel").
// Use null value in consumer to detect if user has abandoned conversation.
addConversationAbandonedListener(abandonedEvent -> consumer.accept(null)).
withLocalEcho(false).
withPrefix(context -> user.getTranslation("challenges.gui.questions.prefix")).
buildConversation(user.getPlayer());

View File

@ -1,11 +1,23 @@
/**
*
*/
package world.bentobox.challenges.tasks;
import org.bukkit.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
@ -13,8 +25,6 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.BoundingBox;
import java.util.*;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -38,9 +48,9 @@ import world.bentobox.challenges.utils.Utils;
*/
public class TryToComplete
{
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* Challenges addon variable.
@ -82,9 +92,9 @@ public class TryToComplete
*/
private final ChallengeResult EMPTY_RESULT = new ChallengeResult();
// ---------------------------------------------------------------------
// Section: Builder
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Builder
// ---------------------------------------------------------------------
@Deprecated
public TryToComplete label(String label)
@ -141,9 +151,9 @@ public class TryToComplete
}
// ---------------------------------------------------------------------
// Section: Constructor
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Constructor
// ---------------------------------------------------------------------
/**
@ -155,18 +165,18 @@ public class TryToComplete
* @param permissionPrefix - Permission prefix for GameMode addon.
*/
public TryToComplete(ChallengesAddon addon,
User user,
Challenge challenge,
World world,
String topLabel,
String permissionPrefix)
User user,
Challenge challenge,
World world,
String topLabel,
String permissionPrefix)
{
this.addon = addon;
this.world = world;
this.permissionPrefix = permissionPrefix;
this.user = user;
this.manager = addon.getChallengesManager();
// To avoid any modifications that may accure to challenges in current completion
// To avoid any modifications that may occur to challenges in current completion
// just clone it.
this.challenge = challenge.clone();
this.topLabel = topLabel;
@ -184,11 +194,11 @@ public class TryToComplete
* @return true, if challenge is completed, otherwise false.
*/
public static boolean complete(ChallengesAddon addon,
User user,
Challenge challenge,
World world,
String topLabel,
String permissionPrefix)
User user,
Challenge challenge,
World world,
String topLabel,
String permissionPrefix)
{
return TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix, 1);
}
@ -206,28 +216,28 @@ public class TryToComplete
* @return true, if challenge is completed, otherwise false.
*/
public static boolean complete(ChallengesAddon addon,
User user,
Challenge challenge,
World world,
String topLabel,
String permissionPrefix,
int maxTimes)
User user,
Challenge challenge,
World world,
String topLabel,
String permissionPrefix,
int maxTimes)
{
return new TryToComplete(addon, user, challenge, world, topLabel, permissionPrefix).
build(maxTimes).meetsRequirements;
build(maxTimes).meetsRequirements;
}
// ---------------------------------------------------------------------
// Section: Methods
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Methods
// ---------------------------------------------------------------------
/**
* This method checks if challenge can be done, and complete it, if it is possible.
* @return ChallengeResult object, that contains completion status.
*/
public ChallengeResult build(int maxTimes)
ChallengeResult build(int maxTimes)
{
// Check if can complete challenge
ChallengeResult result = this.checkIfCanCompleteChallenge(maxTimes);
@ -251,7 +261,7 @@ public class TryToComplete
returnItem.setAmount(amount);
this.user.getInventory().addItem(returnItem).forEach((k, v) ->
this.user.getWorld().dropItem(this.user.getLocation(), v));
this.user.getWorld().dropItem(this.user.getLocation(), v));
});
}
@ -269,7 +279,7 @@ public class TryToComplete
// Clone is necessary because otherwise it will chane reward itemstack
// amount.
this.user.getInventory().addItem(reward.clone()).forEach((k, v) ->
this.user.getWorld().dropItem(this.user.getLocation(), v));
this.user.getWorld().dropItem(this.user.getLocation(), v));
}
// Money Reward
@ -292,14 +302,14 @@ public class TryToComplete
if (this.addon.getChallengesSettings().isBroadcastMessages())
{
for (Player player : this.addon.getServer().getOnlinePlayers())
for (Player player : Bukkit.getOnlinePlayers())
{
// Only other players should see message.
if (!player.getUniqueId().equals(this.user.getUniqueId()))
{
User.getInstance(player).sendMessage("challenges.messages.name-has-completed-challenge",
"[name]", this.user.getName(),
"[value]", this.challenge.getFriendlyName());
"[name]", this.user.getName(),
"[value]", this.challenge.getFriendlyName());
}
}
}
@ -308,11 +318,11 @@ public class TryToComplete
if (this.addon.getChallengesSettings().isShowCompletionTitle())
{
this.user.getPlayer().sendTitle(
this.parseChallenge(this.user.getTranslation("challenges.titles.challenge-title"), this.challenge),
this.parseChallenge(this.user.getTranslation("challenges.titles.challenge-subtitle"), this.challenge),
10,
this.addon.getChallengesSettings().getTitleShowtime(),
20);
this.parseChallenge(this.user.getTranslation("challenges.titles.challenge-title"), this.challenge),
this.parseChallenge(this.user.getTranslation("challenges.titles.challenge-subtitle"), this.challenge),
10,
this.addon.getChallengesSettings().getTitleShowtime(),
20);
}
}
@ -329,7 +339,7 @@ public class TryToComplete
for (int i = 0; i < rewardFactor; i++)
{
this.user.getInventory().addItem(reward.clone()).forEach((k, v) ->
this.user.getWorld().dropItem(this.user.getLocation(), v));
this.user.getWorld().dropItem(this.user.getLocation(), v));
}
}
@ -337,12 +347,12 @@ public class TryToComplete
if (this.addon.isEconomyProvided())
{
this.addon.getEconomyProvider().deposit(this.user,
this.challenge.getRepeatMoneyReward() * rewardFactor);
(double)this.challenge.getRepeatMoneyReward() * rewardFactor);
}
// Experience Repeat Reward
this.user.getPlayer().giveExp(
this.challenge.getRepeatExperienceReward() * rewardFactor);
this.challenge.getRepeatExperienceReward() * rewardFactor);
// Run commands
for (int i = 0; i < rewardFactor; i++)
@ -353,8 +363,8 @@ public class TryToComplete
if (result.getFactor() > 1)
{
this.user.sendMessage("challenges.messages.you-repeated-challenge-multiple",
"[value]", this.challenge.getFriendlyName(),
"[count]", Integer.toString(result.getFactor()));
"[value]", this.challenge.getFriendlyName(),
"[count]", Integer.toString(result.getFactor()));
}
else
{
@ -367,7 +377,7 @@ public class TryToComplete
// Check level completion for non-free challenges
if (!result.wasCompleted() &&
!this.challenge.getLevel().equals(ChallengesManager.FREE))
!this.challenge.getLevel().equals(ChallengesManager.FREE))
{
ChallengeLevel level = this.manager.getLevel(this.challenge);
@ -381,7 +391,7 @@ public class TryToComplete
// Clone is necessary because otherwise it will chane reward itemstack
// amount.
this.user.getInventory().addItem(reward.clone()).forEach((k, v) ->
this.user.getWorld().dropItem(this.user.getLocation(), v));
this.user.getWorld().dropItem(this.user.getLocation(), v));
}
// Money Reward
@ -406,7 +416,7 @@ public class TryToComplete
if (!player.getUniqueId().equals(this.user.getUniqueId()))
{
User.getInstance(player).sendMessage("challenges.messages.name-has-completed-level",
"[name]", this.user.getName(), "[value]", level.getFriendlyName());
"[name]", this.user.getName(), "[value]", level.getFriendlyName());
}
}
}
@ -417,11 +427,11 @@ public class TryToComplete
if (this.addon.getChallengesSettings().isShowCompletionTitle())
{
this.user.getPlayer().sendTitle(
this.parseLevel(this.user.getTranslation("challenges.titles.level-title"), level),
this.parseLevel(this.user.getTranslation("challenges.titles.level-subtitle"), level),
10,
this.addon.getChallengesSettings().getTitleShowtime(),
20);
this.parseLevel(this.user.getTranslation("challenges.titles.level-title"), level),
this.parseLevel(this.user.getTranslation("challenges.titles.level-subtitle"), level),
10,
this.addon.getChallengesSettings().getTitleShowtime(),
20);
}
}
}
@ -442,15 +452,15 @@ public class TryToComplete
IslandRequirements requirements = this.challenge.getRequirements();
if (result.meetsRequirements &&
requirements.isRemoveEntities() &&
!requirements.getRequiredEntities().isEmpty())
requirements.isRemoveEntities() &&
!requirements.getRequiredEntities().isEmpty())
{
this.removeEntities(result.entities, result.getFactor());
}
if (result.meetsRequirements &&
requirements.isRemoveBlocks() &&
!requirements.getRequiredBlocks().isEmpty())
requirements.isRemoveBlocks() &&
!requirements.getRequiredBlocks().isEmpty())
{
this.removeBlocks(result.blocks, result.getFactor());
}
@ -461,11 +471,11 @@ public class TryToComplete
if (this.getInventoryRequirements().isTakeItems())
{
int sumEverything = result.requiredItems.stream().
mapToInt(itemStack -> itemStack.getAmount() * result.getFactor()).
sum();
mapToInt(itemStack -> itemStack.getAmount() * result.getFactor()).
sum();
Map<ItemStack, Integer> removedItems =
this.removeItems(result.requiredItems, result.getFactor());
this.removeItems(result.requiredItems, result.getFactor());
int removedAmount = removedItems.values().stream().mapToInt(num -> num).sum();
@ -489,11 +499,11 @@ public class TryToComplete
}
if (requirements.isTakeExperience() &&
this.user.getPlayer().getGameMode() != GameMode.CREATIVE)
this.user.getPlayer().getGameMode() != GameMode.CREATIVE)
{
// Cannot take anything from creative game mode.
this.user.getPlayer().setTotalExperience(
this.user.getPlayer().getTotalExperience() - requirements.getRequiredExperience());
this.user.getPlayer().getTotalExperience() - requirements.getRequiredExperience());
}
}
}
@ -509,7 +519,6 @@ public class TryToComplete
ChallengeResult result;
ChallengeType type = this.challenge.getChallengeType();
// Check the world
if (!this.challenge.isDeployed())
{
@ -522,36 +531,36 @@ public class TryToComplete
result = EMPTY_RESULT;
}
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)))
{
this.user.sendMessage("general.errors.wrong-world");
result = EMPTY_RESULT;
}
// Player is not on island
else if (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()))
{
this.user.sendMessage("challenges.errors.not-on-island");
result = EMPTY_RESULT;
}
// Check player permission
else if (!this.addon.getIslands().getIslandAt(this.user.getLocation()).
map(i -> i.isAllowed(this.user, ChallengesAddon.CHALLENGES_ISLAND_PROTECTION)).
orElse(false))
map(i -> i.isAllowed(this.user, ChallengesAddon.CHALLENGES_ISLAND_PROTECTION)).
orElse(false))
{
this.user.sendMessage("challenges.errors.no-rank");
result = EMPTY_RESULT;
}
// Check if user has unlocked challenges level.
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())))
{
this.user.sendMessage("challenges.errors.challenge-level-not-available");
result = EMPTY_RESULT;
}
// Check max times
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())
{
this.user.sendMessage("challenges.errors.not-repeatable");
result = EMPTY_RESULT;
@ -564,7 +573,7 @@ public class TryToComplete
}
// Check environment
else if (!this.challenge.getEnvironment().isEmpty() &&
!this.challenge.getEnvironment().contains(this.user.getWorld().getEnvironment()))
!this.challenge.getEnvironment().contains(this.user.getWorld().getEnvironment()))
{
this.user.sendMessage("challenges.errors.wrong-environment");
result = EMPTY_RESULT;
@ -597,7 +606,6 @@ public class TryToComplete
{
result.setCompleted(this.manager.isChallengeComplete(this.user, this.world, this.challenge));
}
// Everything fails till this point.
return result;
}
@ -610,7 +618,7 @@ public class TryToComplete
private boolean checkPermissions()
{
return this.challenge.getRequirements().getRequiredPermissions().isEmpty() ||
this.challenge.getRequirements().getRequiredPermissions().stream().allMatch(s -> this.user.hasPermission(s));
this.challenge.getRequirements().getRequiredPermissions().stream().allMatch(s -> this.user.hasPermission(s));
}
@ -678,7 +686,7 @@ public class TryToComplete
try
{
if (!this.addon.getServer().dispatchCommand(this.addon.getServer().getConsoleSender(),
cmd.replace("[player]", this.user.getName())))
cmd.replace("[player]", this.user.getName())))
{
this.showError(cmd);
}
@ -702,9 +710,9 @@ public class TryToComplete
}
// ---------------------------------------------------------------------
// Section: Inventory Challenge
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Inventory Challenge
// ---------------------------------------------------------------------
/**
@ -730,7 +738,7 @@ public class TryToComplete
if (Utils.canIgnoreMeta(required.getType()))
{
numInInventory =
Arrays.stream(this.user.getInventory().getContents()).
Arrays.stream(this.user.getInventory().getContents()).
filter(Objects::nonNull).
filter(i -> i.getType().equals(required.getType())).
mapToInt(ItemStack::getAmount).
@ -739,7 +747,7 @@ public class TryToComplete
else
{
numInInventory =
Arrays.stream(this.user.getInventory().getContents()).
Arrays.stream(this.user.getInventory().getContents()).
filter(Objects::nonNull).
filter(i -> i.isSimilar(required)).
mapToInt(ItemStack::getAmount).
@ -749,8 +757,8 @@ public class TryToComplete
if (numInInventory < required.getAmount())
{
this.user.sendMessage("challenges.errors.not-enough-items",
"[items]",
Util.prettifyText(required.getType().toString()));
"[items]",
Util.prettifyText(required.getType().toString()));
return EMPTY_RESULT;
}
@ -764,9 +772,9 @@ public class TryToComplete
// Return the result
return new ChallengeResult().
setMeetsRequirements().
setCompleteFactor(maxTimes).
setRequiredItems(requiredItems);
setMeetsRequirements().
setCompleteFactor(maxTimes).
setRequiredItems(requiredItems);
}
@ -782,26 +790,24 @@ public class TryToComplete
for (ItemStack required : requiredItemList)
{
int amountToBeRemoved = required.getAmount() * factor;
List<ItemStack> itemsInInventory;
if (Utils.canIgnoreMeta(required.getType()))
{
// Use collecting method that ignores item meta.
itemsInInventory = Arrays.stream(user.getInventory().getContents()).
filter(Objects::nonNull).
filter(i -> i.getType().equals(required.getType())).
collect(Collectors.toList());
filter(Objects::nonNull).
filter(i -> i.getType().equals(required.getType())).
collect(Collectors.toList());
}
else
{
// Use collecting method that compares item meta.
itemsInInventory = Arrays.stream(user.getInventory().getContents()).
filter(Objects::nonNull).
filter(i -> i.isSimilar(required)).
collect(Collectors.toList());
filter(Objects::nonNull).
filter(i -> i.isSimilar(required)).
collect(Collectors.toList());
}
for (ItemStack itemStack : itemsInInventory)
{
if (amountToBeRemoved > 0)
@ -828,7 +834,7 @@ public class TryToComplete
if (amountToBeRemoved > 0)
{
this.addon.logError("Could not remove " + amountToBeRemoved + " of " + required.getType() +
" from player's inventory!");
" from player's inventory!");
}
}
@ -836,9 +842,9 @@ public class TryToComplete
}
// ---------------------------------------------------------------------
// Section: Island Challenge
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Island Challenge
// ---------------------------------------------------------------------
/**
@ -870,6 +876,11 @@ public class TryToComplete
Island island = this.addon.getIslands().getIsland(this.world, this.user);
if (island == null) {
// Just in case. Should never hit because there is a check if the player is on this island further up
return EMPTY_RESULT;
}
if (boundingBox.getMinX() < island.getMinX())
{
boundingBox.expand(BlockFace.EAST, Math.abs(island.getMinX() - boundingBox.getMinX()));
@ -894,15 +905,15 @@ public class TryToComplete
// Protection code. Do not allow to select too large region for completing challenge.
if (boundingBox.getWidthX() > distance * 2 + 3 ||
boundingBox.getWidthZ() > distance * 2 + 3 ||
boundingBox.getHeight() > distance * 2 + 3)
boundingBox.getWidthZ() > distance * 2 + 3 ||
boundingBox.getHeight() > distance * 2 + 3)
{
this.addon.logError("BoundingBox is larger than SearchRadius. " +
" | BoundingBox: " + boundingBox.toString() +
" | Search Distance: " + requirements.getSearchRadius() +
" | Location: " + this.user.getLocation().toString() +
" | Center: " + island.getCenter().toString() +
" | Range: " + range);
" | BoundingBox: " + boundingBox.toString() +
" | Search Distance: " + requirements.getSearchRadius() +
" | Location: " + this.user.getLocation().toString() +
" | Center: " + island.getCenter().toString() +
" | Range: " + range);
return EMPTY_RESULT;
}
@ -939,15 +950,15 @@ public class TryToComplete
// This queue will contain only blocks whit required type ordered by distance till player.
Queue<Block> blockFromWorld = new PriorityQueue<>((o1, o2) -> {
if (o1.getType().equals(o2.getType()))
{
return Double.compare(o1.getLocation().distance(this.user.getLocation()),
o2.getLocation().distance(this.user.getLocation()));
}
else
{
return o1.getType().compareTo(o2.getType());
}
if (o1.getType().equals(o2.getType()))
{
return Double.compare(o1.getLocation().distance(this.user.getLocation()),
o2.getLocation().distance(this.user.getLocation()));
}
else
{
return o1.getType().compareTo(o2.getType());
}
});
for (int x = (int) boundingBox.getMinX(); x <= boundingBox.getMaxX(); x++)
@ -989,7 +1000,7 @@ public class TryToComplete
for (Map.Entry<Material, Integer> entry : blocksFound.entrySet())
{
factor = Math.min(factor,
entry.getValue() / requiredMap.get(entry.getKey()));
entry.getValue() / requiredMap.get(entry.getKey()));
}
}
@ -1000,12 +1011,12 @@ public class TryToComplete
}
this.user.sendMessage("challenges.errors.not-close-enough",
"[number]",
String.valueOf(this.getIslandRequirements().getSearchRadius()));
"[number]",
String.valueOf(this.getIslandRequirements().getSearchRadius()));
blocks.forEach((k, v) -> user.sendMessage("challenges.errors.you-still-need",
"[amount]", String.valueOf(v),
"[item]", Util.prettifyText(k.toString())));
"[amount]", String.valueOf(v),
"[item]", Util.prettifyText(k.toString())));
// kick garbage collector
@ -1025,8 +1036,8 @@ public class TryToComplete
* @return ChallengeResult
*/
private ChallengeResult searchForEntities(Map<EntityType, Integer> requiredMap,
int factor,
BoundingBox boundingBox)
int factor,
BoundingBox boundingBox)
{
if (requiredMap.isEmpty())
{
@ -1042,7 +1053,7 @@ public class TryToComplete
if (o1.getType().equals(o2.getType()))
{
return Double.compare(o1.getLocation().distance(this.user.getLocation()),
o2.getLocation().distance(this.user.getLocation()));
o2.getLocation().distance(this.user.getLocation()));
}
else
{
@ -1050,11 +1061,11 @@ public class TryToComplete
}
});
this.world.getNearbyEntities(boundingBox).forEach(entity -> {
user.getWorld().getNearbyEntities(boundingBox).forEach(entity -> {
// Check if entity is inside challenge bounding box
if (requiredMap.containsKey(entity.getType()))
{
entityQueue.add(entity);
entityQueue.add(entity);
entitiesFound.putIfAbsent(entity.getType(), 1);
entitiesFound.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount + 1);
@ -1074,7 +1085,7 @@ public class TryToComplete
for (Map.Entry<EntityType, Integer> entry : entitiesFound.entrySet())
{
factor = Math.min(factor,
entry.getValue() / requiredMap.get(entry.getKey()));
entry.getValue() / requiredMap.get(entry.getKey()));
}
}
@ -1085,8 +1096,8 @@ public class TryToComplete
}
minimalRequirements.forEach((reqEnt, amount) -> this.user.sendMessage("challenges.errors.you-still-need",
"[amount]", String.valueOf(amount),
"[item]", Util.prettifyText(reqEnt.toString())));
"[amount]", String.valueOf(amount),
"[item]", Util.prettifyText(reqEnt.toString())));
// Kick garbage collector
entitiesFound.clear();
@ -1129,26 +1140,26 @@ public class TryToComplete
private void removeEntities(Queue<Entity> entityQueue, int factor)
{
Map<EntityType, Integer> entities = this.getIslandRequirements().getRequiredEntities().isEmpty() ?
new EnumMap<>(EntityType.class) : new EnumMap<>(this.getIslandRequirements().getRequiredEntities());
new EnumMap<>(EntityType.class) : new EnumMap<>(this.getIslandRequirements().getRequiredEntities());
// Increase required entities by factor.
entities.entrySet().forEach(entry -> entry.setValue(entry.getValue() * factor));
// Increase required entities by factor.
entities.entrySet().forEach(entry -> entry.setValue(entry.getValue() * factor));
// Go through entity queue and remove entities that are requried.
entityQueue.forEach(entity -> {
if (entities.containsKey(entity.getType()))
{
entities.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount - 1);
entities.entrySet().removeIf(e -> e.getValue() == 0);
entity.remove();
}
});
// Go through entity queue and remove entities that are requried.
entityQueue.forEach(entity -> {
if (entities.containsKey(entity.getType()))
{
entities.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount - 1);
entities.entrySet().removeIf(e -> e.getValue() == 0);
entity.remove();
}
});
}
// ---------------------------------------------------------------------
// Section: Other challenge
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Other challenge
// ---------------------------------------------------------------------
/**
@ -1160,60 +1171,60 @@ public class TryToComplete
{
OtherRequirements requirements = this.getOtherRequirements();
if (!this.addon.isLevelProvided() &&
requirements.getRequiredIslandLevel() != 0)
{
this.user.sendMessage("challenges.errors.missing-addon");
}
else if (!this.addon.isEconomyProvided() &&
requirements.getRequiredMoney() != 0)
{
this.user.sendMessage("challenges.errors.missing-addon");
}
else if (this.addon.isEconomyProvided() && requirements.getRequiredMoney() < 0)
{
this.user.sendMessage("challenges.errors.incorrect");
}
else if (this.addon.isEconomyProvided() &&
!this.addon.getEconomyProvider().has(this.user, requirements.getRequiredMoney()))
if (!this.addon.isLevelProvided() &&
requirements.getRequiredIslandLevel() != 0)
{
this.user.sendMessage("challenges.errors.missing-addon");
}
else if (!this.addon.isEconomyProvided() &&
requirements.getRequiredMoney() != 0)
{
this.user.sendMessage("challenges.errors.missing-addon");
}
else if (this.addon.isEconomyProvided() && requirements.getRequiredMoney() < 0)
{
this.user.sendMessage("challenges.errors.incorrect");
}
else if (this.addon.isEconomyProvided() &&
!this.addon.getEconomyProvider().has(this.user, requirements.getRequiredMoney()))
{
this.user.sendMessage("challenges.errors.not-enough-money",
"[value]",
Double.toString(requirements.getRequiredMoney()));
"[value]",
Double.toString(requirements.getRequiredMoney()));
}
else if (requirements.getRequiredExperience() < 0)
{
this.user.sendMessage("challenges.errors.incorrect");
}
else if (requirements.getRequiredExperience() < 0)
{
this.user.sendMessage("challenges.errors.incorrect");
}
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.
this.user.sendMessage("challenges.errors.not-enough-experience",
"[value]",
Integer.toString(requirements.getRequiredExperience()));
"[value]",
Integer.toString(requirements.getRequiredExperience()));
}
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())
{
this.user.sendMessage("challenges.errors.island-level",
TextVariables.NUMBER,
String.valueOf(requirements.getRequiredIslandLevel()));
TextVariables.NUMBER,
String.valueOf(requirements.getRequiredIslandLevel()));
}
else
{
// calculate factor
// calculate factor
if (this.addon.isEconomyProvided() && requirements.isTakeMoney())
{
factor = Math.min(factor, (int) (this.addon.getEconomyProvider().getBalance(this.user) / requirements.getRequiredMoney()));
}
if (this.addon.isEconomyProvided() && requirements.isTakeMoney())
{
factor = Math.min(factor, (int) (this.addon.getEconomyProvider().getBalance(this.user) / requirements.getRequiredMoney()));
}
if (requirements.getRequiredExperience() > 0 && requirements.isTakeExperience())
{
factor = Math.min(factor, this.user.getPlayer().getTotalExperience() / requirements.getRequiredExperience());
}
if (requirements.getRequiredExperience() > 0 && requirements.isTakeExperience())
{
factor = Math.min(factor, this.user.getPlayer().getTotalExperience() / requirements.getRequiredExperience());
}
return new ChallengeResult().setMeetsRequirements().setCompleteFactor(factor);
}
@ -1222,9 +1233,9 @@ public class TryToComplete
}
// ---------------------------------------------------------------------
// Section: Title parsings
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Title parsings
// ---------------------------------------------------------------------
/**
@ -1268,9 +1279,9 @@ public class TryToComplete
}
// ---------------------------------------------------------------------
// Section: Simple getter methods
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Simple getter methods
// ---------------------------------------------------------------------
/**
@ -1303,9 +1314,9 @@ public class TryToComplete
}
// ---------------------------------------------------------------------
// Section: Private classes
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Section: Result classes
// ---------------------------------------------------------------------
/**
@ -1313,7 +1324,7 @@ public class TryToComplete
*
* @author tastybento
*/
private class ChallengeResult
class ChallengeResult
{
/**
* This method sets that challenge meets all requirements at least once.
@ -1467,5 +1478,15 @@ public class TryToComplete
* challenge requirements.
*/
private Queue<Entity> entities;
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "ChallengeResult [completed=" + completed + ", meetsRequirements=" + meetsRequirements + ", factor="
+ factor + ", requiredItems=" + requiredItems + ", removedItems=" + removedItems + ", blocks="
+ blocks + ", entities=" + entities + "]";
}
}
}

View File

@ -1,15 +1,13 @@
package world.bentobox.challenges.utils;
import java.util.*;
import org.apache.commons.lang.WordUtils;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
@ -423,4 +421,16 @@ public class GuiUtils
stringList.stream().map(string -> GuiUtils.stringSplit(string, warpLength)).forEach(newList::addAll);
return newList;
}
/**
* Sanitizes the provided input.
* It replaces spaces and hyphens with underscores and lower cases the input.
* @param input input to sanitize
* @return sanitized input
*/
public static String sanitizeInput(String input)
{
return input.toLowerCase(Locale.ENGLISH).replace(" ", "_").replace("-", "_");
}
}

View File

@ -15,14 +15,21 @@
package world.bentobox.challenges.utils;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.lang.reflect.Field;
import java.util.*;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import world.bentobox.bentobox.BentoBox;

View File

@ -1,11 +1,12 @@
package world.bentobox.challenges.utils;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
import world.bentobox.bentobox.BentoBox;
@ -25,7 +26,7 @@ public class Utils
{
List<ItemStack> returnItems = new ArrayList<>(requiredItems.size());
// Group all equal items in singe stack, as otherwise it will be too complicated to check if all
// Group all equal items in single stack, as otherwise it will be too complicated to check if all
// items are in players inventory.
for (ItemStack item : requiredItems)
{

View File

@ -1,11 +1,16 @@
package world.bentobox.challenges.web;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Comparator;
import java.util.List;
import org.bukkit.World;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bukkit.World;
import java.nio.charset.StandardCharsets;
import java.util.*;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
@ -121,7 +126,6 @@ public class WebManager
* @param user User who inits request.
* @param world Target world where challenges should be loaded.
* @param entry Entry that contains information about requested object.
* @return {@code true} if request was successful, {@code false} otherwise.
*/
public void requestEntryGitHubData(User user, World world, LibraryEntry entry)
{

View File

@ -1,11 +1,12 @@
package world.bentobox.challenges.web.object;
import com.google.gson.JsonObject;
import org.bukkit.Material;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import com.google.gson.JsonObject;
/**
* This objects allows to load each Challenges Catalog library entry.

View File

@ -57,3 +57,13 @@ permissions:
skygrid.admin.challenges:
description: Access challenge admin commands
default: op
aoneblock.challenges:
description: Let the player use the '/aoneblock challenges' command
default: true
aoneblock.challenges.multiple:
description: Let the player complete challenge multiple times
default: true
aoneblock.admin.challenges:
description: Access challenge admin commands
default: op

View File

@ -143,7 +143,7 @@
"requiredPermissions": []
}
},
"rewardText": "Change your logs for some clay",
"rewardText": "Exchange your logs for some clay",
"rewardItems": [
"is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: CLAY\n amount: 4\n"
],
@ -151,7 +151,7 @@
"rewardMoney": 0,
"rewardCommands": [],
"repeatable": true,
"repeatRewardText": "Change your logs for some clay balls",
"repeatRewardText": "Exchange your logs for some clay balls",
"maxTimes": 0,
"repeatExperienceReward": 5,
"repeatItemReward": [
@ -586,7 +586,7 @@
"friendlyName": "Pumpkin collector",
"deployed": true,
"description": [
"Grow and collect some pumpkin"
"Grow and collect some pumpkins"
],
"icon": "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: PUMPKIN\n",
"order": 3,
@ -622,7 +622,7 @@
"repeatRewardCommands": []
},
{
"uniqueId": "chisedmaker",
"uniqueId": "chiseledmaker",
"friendlyName": "Chiseled stone bricks crafter",
"deployed": true,
"description": [
@ -663,7 +663,7 @@
},
{
"uniqueId": "crackedmaker",
"friendlyName": "Cracked stone bricks",
"friendlyName": "Cracked stone bricks crafter",
"deployed": true,
"description": [
"Smelt some bricks to get cracked stone bricks."
@ -895,7 +895,7 @@
"requiredPermissions": []
}
},
"rewardText": "Iron for tools crafting and some cats.",
"rewardText": "Iron to craft some tools and a couple of cats.",
"rewardItems": [
"is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: IRON_ORE\n amount: 16\n",
"is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: OCELOT_SPAWN_EGG\n amount: 2\n"
@ -961,7 +961,7 @@
"friendlyName": "Visit nether",
"deployed": true,
"description": [
"Nether is a horrible place, but it has some useful stuff."
"The nether is a horrible place, but it has some useful materials."
],
"icon": "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: NETHERRACK\n",
"order": 3,
@ -1064,7 +1064,6 @@
"requiredPermissions": []
}
},
"rewardText": "Some prismarine shards and sea pickles",
"rewardItems": [
"is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: PRISMARINE_SHARD\n amount: 16\n",
@ -1174,7 +1173,7 @@
"friendlyName": "Iron Farm",
"deployed": true,
"description": [
"Use your villagers to produce free iron golems."
"Use your villagers to spawn free iron golems."
],
"icon": "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: IRON_BLOCK\n",
"order": 1,
@ -1302,7 +1301,7 @@
"friendlyName": "Villager Breeder",
"deployed": true,
"description": [
"Start to create a slave army."
"Start to create a villager army."
],
"icon": "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: EMERALD_BLOCK\n",
"order": 1,
@ -1605,7 +1604,7 @@
"requiredPermissions": []
}
},
"rewardText": "Exchange your iron stuff to some diamond",
"rewardText": "Exchange your iron stuff to some diamonds",
"rewardItems": [
"is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: DIAMOND\n amount: 4\n"
],
@ -1627,7 +1626,7 @@
"friendlyName": "Trader",
"deployed": true,
"description": [
"Use your slaves to get some gems"
"Use your villagers to get some gems"
],
"icon": "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: EMERALD\n",
"order": 4,
@ -1645,7 +1644,7 @@
"requiredPermissions": []
}
},
"rewardText": "Exchange your emeralds to some diamond",
"rewardText": "Exchange your emeralds to some diamonds",
"rewardItems": [
"is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: DIAMOND\n amount: 4\n"
],
@ -2564,7 +2563,7 @@
"mushroomfarm",
"melonfarm",
"melonmaker",
"chisedmaker",
"chiseledmaker",
"crackedmaker",
"treefarm",
"cobblegenerator",

View File

@ -0,0 +1,498 @@
###########################################################################################
# This is a YML file. Be careful when editing. Check your edits in a YAML checker like #
# the one at http://yaml-online-parser.appspot.com #
# #
# Translation by: CZghost #
###########################################################################################
meta:
authors:
- BONNe
challenges:
commands:
admin:
main:
parameters: ''
description: 'Hlavní administrátorský příkaz. Otevře GUI.'
import:
description: 'Importovat výzvy ze souboru challenges.yml|Parametr overwrite znamená, že výzvy nebo úrovně se stejnou ID budou přepsána.'
parameters: '[overwrite]'
reload:
description: 'Znovu načíst výzvy z databáze|Parametr hard znamená, že doplňek zresetuje připojení k databázi.'
parameters: '[hard]'
show:
description: 'Tato metoda vypíše do chatu všechny výzvy, které ve světě existují.'
parameters: ''
defaults:
description: 'Tato metoda ukáže podpříkazy, které umožní import/export výchozích výzev.'
parameters: '[command]'
defaults-import:
description: 'Tato metoda umožňuje import výchozích výzev.'
parameters: ''
defaults-generate:
description: 'Tato metoda umožňuje export existujících výzev do souboru default.json.'
parameters: '[overwrite] - umožní přepsat existující soubor.'
complete:
description: 'Tento příkaz umožňuje dokončit výzvu hráči bez GUI.'
parameters: '<player> <challenge_id>'
reset:
description: 'Tento příkaz umožňuje resetovat výzvu hráči bez GUI. Pokud je "challenge_id" nastaveno na "all", potom příkaz zresetuje hráči všechny výzvy.'
parameters: '<player> <challenge_id>'
migrate:
description: 'Tato metoda umožňuje migrovat data výzev, která referují na svět nynějšího herního módu, do nového formátu úložiště 0.8.0.'
parameters: ''
user:
main:
description: 'Tato metoda otevárá GUI Výzev.'
parameters: ''
complete:
description: 'Tato metoda umožňuje dokončit výzvu bez GUI.'
parameters: '<challenge_id> [count]'
gui:
title:
admin:
gui-title: '&aAdministrace Výzev'
edit-challenge-title: '&aEditovat výzvu'
edit-level-title: '&aEditovat úroveň'
settings-title: '&aEditovat nastavení'
choose-challenge-title: '&aZvolit výzvu'
choose-level-title: '&aZvolit úroveň'
choose-user-title: '&aZvolit hráče'
manage-blocks: '&aSpravovat bloky'
manage-entities: '&aSpravovat entity'
confirm-title: '&aPotvrzení'
manage-items: '&aSpravovat předměty'
manage-numbers: '&aČíselník'
select-block: '&aZvolit blok'
select-challenge: '&aZvolit výzvu'
select-entity: '&aZvolit entitu'
toggle-environment: '&aPřepnout prostředí'
edit-text-fields: '&aEditovat textová pole'
library-title: '&aStáhnutelné knihovny'
lore-add: '&aPřidat řádek příběhu'
lore-remove: '&aOdstranit řádek příběhu'
lore-edit: '&aEditovat příběh'
type-select: "&aZvolit typ výzvy"
challenges: '&6Výzvy'
game-modes: '&6Zvolit herní mód'
multiple-complete: '&6Kolikrát?'
buttons:
admin:
complete: 'Dokončit výzvy hráče'
reset: 'Resetovat výzvy hráče'
create-challenge: 'Přidat novou výzvu'
create-level: 'Přidat novou úroveň'
edit-challenge: 'Editovat výzvu'
edit-level: 'Editovat úroveň'
delete-challenge: 'Odstranit výzvu'
delete-level: 'Odstranit úroveň'
import: 'Importovat výzvy starého pluginu ASkyBlock'
settings: 'Editovat nastavení'
properties: 'Vlastnosti'
requirements: 'Požadavky'
rewards: 'Odměny'
challenges: 'Výzvy'
deployment: 'Zveřejnění'
icon: 'Ikona'
locked-icon: 'Ikona zamčení'
description: 'Popis'
order: 'Pořadí'
environment: 'Prostředí'
remove-on-complete: 'Odstranit po dokončení'
name: 'Viditelný název'
required-entities: 'Požadované entity'
remove-entities: 'Zabít entity'
required-blocks: 'Požadované bloky'
remove-blocks: 'Odstranit bloky'
search-radius: 'Radius hledání'
required-permissions: 'Požadovaná oprávnění'
required-items: 'Požadované předměty'
remove-items: 'Odstranit předměty'
required-experience: 'Požadované zkušenosti'
remove-experience: 'Odstranit zkušenosti'
required-level: 'Požadovaná úroveň ostrova'
required-money: 'Požadované peníze'
remove-money: 'Odstranit peníze'
reward-text: 'Zpráva odměny'
reward-items: 'Odměnit předměty'
reward-experience: 'Odměnit zkušenostmi'
reward-money: 'Odměnit penězmi'
reward-commands: 'Příkazy odměny'
repeatable: 'Opakovatelná'
repeat-count: 'Max. počet opakování'
repeat-reward-text: 'Zpráva opakované odměny'
repeat-reward-items: 'Odměnit předměty po opakování'
repeat-reward-experience: 'Odměnit zkušenostmi po opakování'
repeat-reward-money: 'Odměnit penězmi po opakování'
repeat-reward-commands: 'Odměnit příkazy po opakování'
waiver-amount: 'Nedokončené výzvy'
add-challenge: 'Přidat výzvu'
remove-challenge: 'Odstranit výzvu'
reset-on-new: 'Resetovat na novém ostrově'
broadcast: 'Oznámit dokončení'
remove-completed: 'Odstranit po dokončení'
glow: 'Svítit při dokončení'
free-at-top: 'Výzvy zdarma první'
line-length: 'Délka řádku příběhu'
visibility-mode: 'Mód viditelnosti výzvy'
toggle-user-list: 'Seznam hráčů'
remove-selected: 'Odstranit vybrané'
add: 'Přidat'
show-eggs: 'Přepnout mód zobrazení'
accept: 'Přijmout'
decline: 'Odmítnout'
save: 'Uložit'
cancel: 'Zrušit'
input: 'Vstup'
value: 'Hodnota'
set: '='
increase: '+'
reduce: '-'
multiply: '*'
clear: 'Vyčistit'
remove-empty: 'Odstranit prázdné'
number: '[number]'
level-lore: 'Popis úrovně'
challenge-lore: 'Popis výzvy'
gui-view-mode: 'Ukázat všechny herní módy'
gui-mode: 'Samostatné GUI výzev'
history-store: 'Historie výzev'
history-lifespan: 'Dosah historie'
island-store: 'Ukládat dle ostrovů'
default-locked-icon: 'Ikona zamčené úrovně'
input-mode: 'Přepnout režim vstupu'
title-enable: 'Titul dokončení'
title-showtime: 'Titul ukázky'
default-import: 'Import výchozích výzev'
default-export: 'Export existujících výzev'
complete-wipe: 'Vymazat databáze doplňku'
challenge-wipe: 'Vymazat databáze výzev'
players-wipe: 'Vymazat databáze hráčů'
library: 'Webová knihovna'
download: 'Stáhnout knihovny'
type:
island: '&6Typ ostrova'
inventory: '&6Typ inventáře'
other: '&6Jiný typ'
next: 'Další'
previous: 'Předchozí'
return: 'Zpět'
value: "Dokončeno"
increase: "Zvýšit"
reduce: "Snížit"
descriptions:
admin:
save: 'Uložit a vrátit se do předchozího GUI.'
cancel: 'Vrátit se do předchozího GUI. Změny nebudou uloženy.'
input: 'Otevřít vstup tetového pole.'
set: 'Operace nastavení. Klikání na čísla změní hodnotu na zvolené číslo.'
increase: 'Operace zvýšení. Klikání na čísla zvýší hodnotu o zvolené číslo.'
reduce: 'Operace snížení. Klikání na čísla sníží hodnotu o zvolené číslo.'
multiply: 'Operace násobení. Klikání na čísla znásobí hodnotu zvoleným číslem.'
import: 'Umožňuje import výzev ze starého pluginu ASkyblock.|Klinkutí pravým myšítkem zapíná/vypíná mód přepisování.|Vlož soubor Challenges.yml do složky ./BentoBox/addons/Challenges.'
complete: 'Umožňuje dokončit výzvy jakémukoliv hráči.|Hráči nedostanou odměnu za dokončení.'
reset: 'Umožňuje resetovat dokončené výzvy hráče.|Kliknutí pravým myšítkem zapíná/vypíná funkci resetu všeho.'
create-challenge: 'Umožňuje přidat novou výzvu.|Jako výchozí se objeví v seznamu výzev zdarma.'
create-level: 'Umožňuje přidat novou úroveň.'
edit-challenge: 'Umožňuje editovat nastavení jakékoliv výzvy.'
edit-level: 'Umožňuje editovat nastavení jakékoliv úrovně.'
delete-challenge: 'Umožňuje odstranit jakoukoliv výzvu.'
delete-level: 'Umožňuje odstranit jakoukoliv úroveň.'
settings: 'Umožňuje změnit nastavení doplňku.'
properties: 'Umožňuje změnit obecné nastavení'
requirements: 'Umožňuje spravovat požadavky'
rewards: 'Umožňuje spravovat odměny'
challenges: 'Umožňuje spravovat úroveň výzev (přidat / odebrat).'
deployment: 'Umožňuje hráčům dokončit (zobrazit) výzvu.'
icon-challenge: 'Ikona, která bude zobrazena v GUI panelech pro tuto výzvu.'
icon-level: 'Ikona, která bude zobrazena v GUI panelech pro tuto úroveň.'
locked-icon: 'Ikona, která bude zobrazena v GUI panelech, je-li úroveň zamčena.'
description: 'Umožňuje editovat popis.'
order: 'Umožňuje změnit číslo pořadí.'
environment: 'Umožňuje změnit prostředí, kde výzvy fungují.'
remove-on-complete: 'Umožňuje odebrat výzvu z GUI hráče po jejím dokončení.'
name-challenge: 'Umožňuje změnit viditelné jméno výzvy.'
name-level: 'Umožňuje změnit viditelné jméno úrovně.'
required-entities: 'Umožňuje přidat/editovat/odebrat požadované entity.|Entity:|'
remove-entities: 'Umožňuje odebrat (zabít) entity při dokončení výzvy.'
required-blocks: 'Umožňuje přidat/editovat/odebrat požadované bloky.|Bloky:|'
remove-blocks: 'Umožňuje odebrat (nahradit vzduchem) bloky při dokončení výzvy.'
search-radius: 'Radius okolo umístění hráče, kde se budou požadované entity a bloky hledat.'
required-permissions: 'Požadovaná oprávnění hráče pro možnost dokončit výzvu.|Oprávnění:'
required-items: 'Požadované předměty v inventáři hráče.|Předměty:'
remove-items: 'Umožňuje odebrat předměty z inventáře hráče po dokončení výzvy.'
required-experience: 'Umožňuje definovat požadované zkušenosti hráče pro dokončení výzvy.'
remove-experience: 'Umožňuje odebrat požadované zkušenosti.'
required-level: 'Umožňuje definovat požadovanou úroveň ostrova pro tuto výzvu.|&cVyžaduje doplňek Level.'
required-money: 'Umožňuje definovat požadované peníze v účtu hráče.|&cVyžaduje pluginy Vault a Economy.'
remove-money: 'Umožňuje odebrat pořadované peníze z účtu hráče.|&cVyžaduje pluginy Vault a Economy.'
reward-text: 'Umožňuje změnit zprávu, která se odešle hráči po dokončení výzvy.'
reward-items: 'Umožňuje změnit odměnu za první dokončení výzvy.|Předměty:'
reward-experience: 'Umožňuje změnit zkušenostní odměnu za první dokončení výzvy.'
reward-money: 'Umožňuje změnit peněžní odměnu za první dokončení výzvy.|&cVyžaduje pluginy Vault a Economy.'
reward-commands: 'Umožňuje definovat příkazy odměny, které se vykonají po prvním dokončení výzvy.|***Přidáním "[SELF]" na začátek znamená, že příkaz bude proveden hráčem, např. "/kill"|***Řetězec "[player]" bude nahrazen jménem hráče, např. "/kill [player]" bude nahrazen příkazem "/kill BONNe1704"|Příkazy:'
repeatable: 'Umožňuje definovat, zda je výzva opakovatelná nebo ne.'
repeat-count: 'Umožňuje definovat maximální počet opakování. Pokud je hodnota nastavena na 0 nebo nižší, pak nebude počet opakování limitován.'
repeat-reward-text: 'Umožňuje změnit zprávu, která se odešle hráči po opakovaném dokončení výzvy.'
repeat-reward-items: 'Umožňuje změnit odměnu za opakované dokončení výzvy.|Předměty:'
repeat-reward-experience: 'Umožňuje změnit zkušenostní odměnu za opakované dokončení výzvy.'
repeat-reward-money: 'Umožňuje změnit peněžní odměnu za opakované dokončení výzvy.|&cVyžaduje pluginy Vault a Economy.'
repeat-reward-commands: 'Umožňuje definovat příkazy odměny, které se vykonají po opakovaném dokončení výzvy.|***Přidáním "[SELF]" na začátek znamená, že příkaz bude proveden hráčem, např. "/kill"|***Řetězec "[player]" bude nahrazen jménem hráče, např. "/kill [player]" bude nahrazen příkazem "/kill BONNe1704"|Příkazy:'
waiver-amount: 'Umožňuje nastavit, kolik výzev může zůstat nedokončených k odemčení další úrovně.'
reward-text-level: 'Umožňuje změnit zprávu, která se odešle hráči po dokončení všech výzev v úrovni.'
add-challenge: 'Umožňuje přidat existující výzvu do aktuální úrovně.'
remove-challenge: 'Umožňuje odstranit jakoukoliv výzvu z aktuální úrovně.'
reset-on-new: 'Zapíná/vypíná možnost, která resetuje všechny výzvy hráče, pokud hráč restartuje ostrov, opustí ostrov nebo byl vykopnut.'
broadcast: 'Zapíná/vypíná oznámení online hráčům o prvním dokončení výzvy.'
remove-completed: 'Zapíná/vypíná skrývání výzev, které jsou dokončené a nelze je opakovat.'
glow: 'Zapíná/vypíná efekt záření pro dokončené výzvy.'
free-at-top: 'Umožňuje změnit umístění výzvy zdarma. Skutečně to znamená, že výzvy budou první, jinak poslední.'
line-length: 'Umožňuje modifikovat maximální délku řádku příběhu. To neovlivní uložené objekty.'
toggle-user-list: 'Přepnout na jiný seznam hráčů.'
mode-online: 'Hráči, kteří jsou aktuálně online.'
mode-in-world: 'Hráči, kteří jsou ve světě tohoto herního módu.'
mode-with-island: 'Hráči, kteří mají v tomto herním módu ostrov.'
selected: 'Zvoleno'
remove-selected: 'Odstranit zvolené položky.|Můžeš zvolit položky kliknutím pravým myšítkem.'
show-eggs: 'Přepnout zobrazení mobů mezi spawnovacím vajíčkem nebo hlavou moba.'
level-lore: 'Umožňuje modifikovat, které položky popisu úrovně by měly být viditelné.'
challenge-lore: 'Umožňuje modifikovat, které položky popisu výzvy by měly být viditelné.'
gui-view-mode: 'Umožňuje nastavit, zda GUI /challenges má zobrazit herní módy nebo výzvy ve světě hráče.'
history-store: 'Umožňuje zapnout/vypnout ukládání historie výzev.'
history-lifespan: 'Umožňuje modifikovat, kolik dní budou data historie uložena.|0 znamená navždy.'
island-store: 'Umožňuje zapnout/vypnout ukládání dat výzev dle ostrova. To znamená, že výzvy budou stejné pro celý tým, pokud bude funkce zapnuta.|Toto NEZKONVERTUJE data kliknutím. POSTUP BUDE ZTRACEN.'
default-locked-icon: 'Umožňuje změnit výchozí ikonu zamčené úrovně.|Tato volba může být přepsána každou úrovní.'
gui-mode: 'Umožňuje zapnout/vypnout samostatné GUI výzev.|&2Vyžaduje restart serveru.'
visibility-mode: 'Umožňuje přepnout, zda by se nezveřejněné výzvy měly zobrazovat nebo ne.'
click-to-edit: '&4Klikni sem k editaci vstupu.'
edit-text-line: '&6 Edituj textovou zprávu!'
add-text-line: '&6 Přidej novou textovou zprávu!'
input-mode: 'Přepni mezi módem vstupu v chatu a kovadlině.'
title-enable: 'Umožňuje zapnout/vypnout zprávu titulku, který se ukáže, když hráč dokončí výzvu.'
title-showtime: 'Umožňuje modifikovat, jak dlouho se bude zpráva titulku pro hráče zobrazovat.'
default-import: 'Umožňuje import výchozích výzev.'
default-export: 'Umožňuje export existujících výzev do souboru defaults.json.'
complete-wipe: 'Umožňuje kompletně vymazat všechny databáze výzev doplňku. Zahrnuje data hráčů!'
challenge-wipe: 'Umožňuje kompletně vymazat databáze výzev a jejich úrovní!'
players-wipe: 'Umožňuje kompletně vymazat databázi hráčů!'
library: 'Otevře GUI, které ukáže všechny dostupné veřejné knihovny výzev.'
library-author: 'od &e[author]'
library-version: '&9Vytvořeno ve verzi Challenges [version]'
library-lang: '&aJazyk: [lang]'
library-gamemode: '&aPrimárně pro [gamemode]'
download: 'Umožňuje manuálně aktualizovat dostupné knihovny výzev. |Klikni pravým myšítkem k zapnutí čištění cache.'
download-disabled: 'Stahovač dat GitHub je v pluginu BentoBox zakázán. Bez toho nemůžeš použít knihovny!'
lore:
level: "Řetězec úrovně. | Reprezentuje překlad 'challenges.gui.challenge-description.level'."
status: "Řetězec statusu. | Reprezentuje překlad 'challenges.gui.challenge-description.completed'."
count: "Řetězec počtu dončení. | Reprezentuje překlad pro 'challenges.gui.challenge-description.completed-times', 'challenges.gui.challenge-description.completed-times-of' and 'challenges.gui.challenge-description.maxed-reached'."
description: "Řetězec popisu. | Devinován v objektu výzev - challenge.description."
warnings: "Řetězec varování. | Reprezentuje překlad pro: | 'challenges.gui.challenge-description.warning-items-take' | 'challenges.gui.challenge-description.objects-close-by' | 'challenges.gui.challenge-description.warning-entities-kill' | 'challenges.gui.challenge-description.warning-blocks-remove'."
environment: "Řetězec prostředí. | Definován v objektu výzev - challenge.environment."
requirements: "Řetězec požadavků. | Reprezentuje překlad pro: | 'challenges.gui.challenge-description.required-level' | 'challenges.gui.challenge-description.required-money' | 'challenges.gui.challenge-description.required-experience' | and challenge.requiredItems, challenge.requiredBlocks or challenge.requiredEntities."
reward_text: "Řetězec odměn. | Definován v challenge.rewardText a challenge.repeatRewardText"
reward_other: "Řetězec ostatních odměn. | Reprezentuje překlad pro: | 'challenges.gui.challenge-description.experience-reward' | 'challenges.gui.challenge-description.money-reward' | 'challenges.gui.challenge-description.not-repeatable'."
reward_items: "Předměty odměny. | Seznam předmětů, které budou odměněny, je definován v challenge.rewardItems and challenge.repeatRewardItems."
reward_commands: "Příkazy odměny. | Seznam příkazů, které budou odměněny, je definován v challenge.rewardCommands and challenge.repeatRewardCommands."
level_status: "Řetězec statusu. | Reprezentuje překlad 'challenges.gui.level-description.completed'."
challenge_count: "Řetězec počtu dokončených výzev. | Reprezentuje překlad pro 'challenges.gui.level-description.completed-challenges-of'"
unlock_message: "Řetězec zprávy odemčení. | Definován v objektu výzev Level - challengeLevel.unlockMessage."
waiver_amount: "Řetězec počtu povolených nedokončených výzev k odemčení další úrovně. | Reprezentuje překlad pro 'challenges.gui.level-description.waver-amount'"
level_reward_text: "Řetězec odměn. | Definován v challengeLevel.rewardText"
level_reward_other: "Řetězec ostatních odměn. | Reprezentuje překlad pro: | 'challenges.gui.level-description.experience-reward' | 'challenges.gui.level-description.money-reward'."
level_reward_items: "Předměty odměny. | Seznam předmětů, které budou odměněny, je definován v challengeLevel.rewardItems."
level_reward_commands: "Příkazy odměny. | Seznam příkazů, které budou odměněny, je definován v challengeLevel.rewardCommands."
current-value: '|&6Nynější hodnota: [value].'
enabled: 'Povoleno'
disabled: 'Zakázáno'
type:
island: '&aUmožňuje požadovat bloky nebo moby okolo hráče'
inventory: '&aUmožňuje požadovat předměty v inventáři hráče'
other: '&aUmožňuje požadovat položky z ostatních pluginů/doplňků'
the-end: '- End'
nether: '- Nether'
normal: '- Svět'
entity: '- [entity] : [count]'
block: '- [block] : [count]'
permission: '- [permission]'
item: '- [count] x [item]'
item-meta: ' ([meta])'
item-enchant: ' - [enchant] [level]'
command: '- [command]'
level-unlocked: 'Klikni k zobrazení výzev [level]!'
level-locked: 'Dokonči dalších [count] výzev [level] k odemčení další úrovně!'
increase-by: "&aNavýšit počet dokončení o [value]"
reduce-by: "&cSnížit počet dokončení o [value]"
visibility:
visible: "Všechny výzvy jsou pro všechny viditelné"
hidden: "Jen zveřejněné výzvy jsou viditelné."
toggleable: "Umožňuje přepnout, zda by měly být nezveřejněné výzvy viditelné"
challenge-description:
level: '&FÚroveň: [level]'
completed: '&BDokončeno'
completed-times-of: 'Dokončeno [donetimes] z [maxtimes]'
maxed-reached: 'Dokončeno [donetimes] z [maxtimes]'
completed-times: 'Dokončeno [donetimes]'
warning-items-take: '&cVšechny požadované předměty budou po dokončení výzvy odebrány!'
objects-close-by: '&cVšechny požadované bloky a entity musí být blízko tebe na tvém ostrově!'
warning-entities-kill: '&cVšechny požadované entity budou zabity po dokončení této výzvy!'
warning-blocks-remove: '&cVšechny požadované blocks budou odstraněny po dokončení této výzvy!'
not-repeatable: '&cTato výzva není opakovatelná!'
experience-reward: '&6Zkuš. odměna: [value]'
money-reward: '&6Peněžní odměna: $[value]'
required-experience: '&6Potřebné zkuš.: [value]'
required-money: '&6Potřebné peníze: $[value]'
required-island-level: '&6Potřebná úroveň ostrova: [value]'
environment: 'Požadovaná prostředí:'
reward-items: '&6Odměněné předměty:'
reward-commands: '&6Odměněné příkazy:'
required-items: 'Potřebné předměty:'
required-entities: 'Potřebné entity:'
required-blocks: 'Potřebné bloky:'
level-description:
completed: '&BDokončeno'
completed-challenges-of: '&3Dokončil jsi [number] z [max] výzev v této úrovni.'
waver-amount: '&6Lze přeskočit [value] výzev k odemčení další úrovně.'
experience-reward: '&6Zkuš. odměna: [value]'
money-reward: '&6Peněžní odměna: $[value]'
reward-items: '&6Odměněné předměty:'
reward-commands: '&6Odměněné příkazy:'
item-description:
item: '- [count] x [item]'
item-meta: ' ([meta])'
item-enchant: ' - [enchant] [level]'
item-name: ' [name]'
item-lore: ' Příběh přemětu:'
book-meta: ' [title] od [author]'
recipe-count: ' [count] receptů'
armor-color: ' [color]'
potion-type-extended-upgraded: ' Rozšířen a aktualizován [name]'
potion-type-upgraded: ' Aktualizován [name]'
potion-type-extended: ' Rozšířen [name]'
potion-type: ' [name]'
custom-effects: ' Vlastní efekty:'
potion-effect: ' [effect] x [amplifier] na [duration]t'
skull-owner: ' [owner]'
egg-meta: ' [mob]'
fish-meta: ' [body-color] s [pattern-color] [pattern]'
questions:
prefix: "&2[SERVER]: "
admin:
number: "Napiš číslo do chatu a stiskni Enter k přijetí a opět stiskni Enter."
unique-id: "Napiš unikátní objektové jméno a stiskni Enter."
challenge-name: "Napiš do chatu zobrazované jméno pro aktuální výzvu."
level-name: "Napiš do chatu zobrazované jméno pro aktuální úroveň."
titles:
# Title and subtitle my contain variable in [] that will be replaced with proper message from challenge object.
# [friendlyName] will be replaced with challenge friendly name.
# [level] will be replaced with level friendly name.
# [rewardText] will be replaced with challenge reward text.
challenge-title: 'Úspěšně dokončeno'
challenge-subtitle: '[friendlyName]'
# Title and subtitle my contain variable in [] that will be replaced with proper message from level object.
# [friendlyName] will be replaced with level friendly name.
# [rewardText] will be replaced with level reward text.
level-title: 'Úspěšně dokončeno'
level-subtitle: '[friendlyName]'
messages:
admin:
hit-things: 'Bouchni do věcí pro jejich přidání do seznamu požadovaných věcí. Klikni pravým myšítkem, jakmile budeš hotov.'
you-added: 'Přidal jsi jeden [thing] do výzvy'
challenge-created: '[challenge]&r vytvořeno!'
complete-wipe: '&cDoufám, že máš zálohy, neboť jsi právě vyprázdnil všechny databáze doplňku Challenges!'
challenge-wipe: '&cDoufám, že máš zálohy, neboť jsi právě vyprázdnil výzvy a jejich úrovně z databází!'
players-wipe: '&cDoufám, že máš zálohy, neboť jsi právě vyprázdnil dokončené výzvy hráčů z databází!'
completed: '&2Dokončil jsi výzvu [name] hráči [player]!'
already-completed: '&2Tato výzva již byla dokončena!'
reset: '&2Resetoval jsi výzvu [name] hráči [player]!'
reset-all: '&2Všechny výzvy hráče [player] jsou resetovány!'
not-completed: '&2Tato výzva ještě není dokončena!'
migrate-start: '&2Začít migrovat data doplňku Challenges.'
migrate-end: '&2Data doplňku Challenges jsou aktualizována na nový formát.'
migrate-not: '&2Všechna data jsou platná.'
start-downloading: '&5Začínám stahovat a importovat knihovnu výzev.'
you-completed-challenge: '&2Dokončil jsi výzvu [value]&r&2!'
you-repeated-challenge: '&2Zopakoval jsi výzvu [value]&r&2!'
you-repeated-challenge-multiple: '&2Zopakoval jsi výzvu [value] &r&2[count]x!'
you-completed-level: '&2Dokončil jsi úroveň [value]&r&2!'
name-has-completed-challenge: '&5[name] dokončil výzvu [value]&r&5!'
name-has-completed-level: '&5[name] dokončil úroveň [value]&r&5!'
import-levels: 'Začínám importovat úrovně'
import-challenges: 'Začínám importovat výzvy'
no-levels: 'Varování: Žádné úrovně nejsu definovány v souboru challenges.yml'
import-number: 'Importováno [number] výzev'
load-skipping: '"[value]" již existuje - přeskakuji'
load-overwriting: 'Přepisuji "[value]"'
load-add: 'Přidávám nový objekt: [value]'
defaults-file-overwrite: 'Soubor defaults.json existuje. Bude přepsán.'
defaults-file-completed: 'Soubor defaults.json je naplněn výzvami ze světa [world]!'
errors:
no-name: '&cChybějící název výzvy'
unknown-challenge: '&cNeznámá výzva'
unique-id: '&cUnikátní ID "[id]" není platné.'
wrong-icon: '&cUvedený materiál "[value]" je neplatný a nelze jej použít jako ikonu.'
not-valid-integer: '&cUvedené celé číslo "[value]" je neplatné!|Hodnota by měla být mezi [min] a [max].'
not-a-integer: '&cUvedená hodnota "[value]" není celé číslo!'
not-deployed: '&cVýzva není zveřejněna!'
not-on-island: '&cK tomuto musíš být na svém ostrově!'
challenge-level-not-available: '&cNeodemkl jsi úroveň k dokončení této výzvy.'
not-repeatable: '&cTato výzva není opakovatelná!'
wrong-environment: '&cJsi ve špatném prostředí!'
not-enough-items: '&cNemáš dostatek [items] k dokončení této výzvy!'
not-close-enough: '&cMusíš stát alespoň [number] bloků od požadovaných položek.'
you-still-need: '&cStále potřebuješ [amount] x [item]'
missing-addon: '&cNelze dokončit výzvu. Vyžadovaný doplňek nebo plugin chybí.'
incorrect: '&cNelze dokončit výzvu. Požadavky nejsou správně.'
not-enough-money: '&cJe důležité mít [value] na svém účtu k dokončení této výzvy.'
not-enough-experience: '&cJe důležité mít [value] zkuš. k dokončení této výzvy.'
island-level: '&cÚroveň tvého ostrova musí být [number] k dokončení této výzvy!'
import-no-file: '&cNelze najít soubor challenges.yml k importu!'
no-load: '&cChyba: Nelze načíst soubor challenges.yml. [message]'
load-error: '&cChyba: Nelze načíst [value].'
no-rank: "&cNa toto nemáš hodnost."
cannot-remove-items: '&cNěkteré předměty nelze odebrat z tvého inventáře!'
exist-challenges-or-levels: '&cVe tvém světě již existují výzvy. Nelze pokračovat!'
defaults-file-exist: '&cSoubor defaults.json již existuje. Použij mód přepsání k jeho nahrazení!'
defaults-file-error: '&cVyskytla se chyba během vytváření souboru defaults.json! Podívej se do konzole!'
no-challenges: '&cVýzvy nejsou v aktuálním světě implementovány!'
no-challenges-admin: '&cVýzvy nejsou v aktuálním světě implementovány! Měl bys použít &5/[command] &ck jejich přidání!'
missing-level: '&cÚroveň výzev [level] není v databázi definována. To může způsobit nějaké chyby!'
missing-arguments: '&cPříkaz postrádá argumenty.'
no-multiple-permission: "&cNemáš oprávnění k dokončení výzev vícekrát najednou."
protection:
flags:
CHALLENGES_ISLAND_PROTECTION:
description: "&5&oPřepnout, kdo může\n&5&odokončit výzvy"
name: "Protekce výzev"
CHALLENGES_WORLD_PROTECTION:
description: "&5&oToto umožní zapnout/vypnout\n&5&opožadavky hráčů\n&5&obýt na jejich ostrově\n&5&ok dokončení výzvy."
name: "Limitace výzev na ostrov"
hint: "Žádné výzvy mimo ostrov"
version: 11

View File

@ -0,0 +1,628 @@
---
challenges:
commands:
admin:
main:
description: Hauptadministrationsbefehl. Öffnet GUI.
defaults-generate:
parameters: "[overwrite] - Erlaubt es eine bereits existierende Datei zu überschreiben"
description: Bestehende Herausforderungen in default.json Datei exportieren.
migrate:
description: Migrieren der aktuellen Spielwelt Herausforderungen Daten auf
0.8.0 Speicherformat.
show:
description: Schreibt alle Herausforderungen in den Chat, die es auf dieser
Welt gibt.
defaults:
description: Zeigt Unterbefehle zum Importieren/Exportieren der Standardherausforderungen.
parameters: "[command]"
defaults-import:
description: Importiert die Standardherausforderungen.
complete:
description: Eine Herausforderung für einen Spieler abschließen.
parameters: "<player> <challenge_id>"
reset:
description: Eine Herausforderung für einen Spieler zurücksetzen. Wenn "challenge_id"
auf "all" gesetzt ist, werden alle Herausforderungen zurückgesetzt.
parameters: "<player> <challenge_id>"
import:
description: |-
Herausforderungen aus der challenges.yml importieren
Parameter überschreiben bedeutet, dass Herausforderungen oder Level mit der gleichen ID überschrieben werden.
parameters: "[overwrite]"
reload:
description: |-
Herausforderungen aus der Datenbank neu laden
Parameter hard bedeutet, dass Addon die Verbindung zur Datenbank zurücksetzen wird.
parameters: "[hard]"
user:
main:
description: Herausforderungen GUI öffnen.
complete:
description: Herausforderung abschließen.
parameters: "<challenge_id> [count]"
gui:
title:
admin:
gui-title: "&aHerausforderungen Admin"
edit-challenge-title: "&aBearbeite die Herausforderungen"
edit-level-title: "&aEditiere das Level"
settings-title: "&aEinstellungen bearbeiten"
choose-challenge-title: "&aHerausforderung auswählen"
choose-level-title: "&aStufe wählen"
choose-user-title: "&aSpieler auswählen"
manage-blocks: "&aBlöcke verwalten"
manage-entities: "&aObjekte verwalten"
confirm-title: "&aBestätigung"
manage-items: "&aItems verwalten"
manage-numbers: "&aNummernblock"
select-block: "&aBlock wählen"
select-challenge: "&aHerausforderung auswählen"
select-entity: "&aObjekt auswählen"
toggle-environment: "&aUmschalten der Umgebung"
edit-text-fields: "&aTextfelder bearbeiten"
library-title: "&aDownloadbare Bibliotheken"
lore-add: "&aHinzufügen von Machtelementen"
lore-remove: "&aEntfernen von Überlieferungselement"
lore-edit: "&aBearbeiten von Überlieferungen"
type-select: "&aHerausforderungstyp wählen"
challenges: "&6Herausforderungen"
game-modes: "&6Spielmodus wählen"
multiple-complete: "&6Wie oft?"
buttons:
admin:
complete: Vollständige Benutzerherausforderung
reset: Benutzer-Herausforderung zurücksetzen
create-challenge: Hinzufügen einer neuen Herausforderung
create-level: Hinzufügen eines neuen Levels
edit-challenge: 'Herausforderung bearbeiten '
edit-level: Level bearbeiten
delete-level: Level entfernen
requirements: Anforderungen
rewards: Belohnungen
deployment: Aufstellung
icon: Symbol
locked-icon: Gesperrtes Icon
order: Order
required-experience: Benötigte Erfahrung
remove-experience: Erfahrung entfernen
required-level: Benötigtes Insellevel
reward-items: Item Belohnung
reward-experience: Erfahrungsbelohnung
reward-money: Geld Belohnung
reward-commands: Belohnungs-Befehle
repeat-count: Max Wiederholung
repeat-reward-text: Belohnungsnachricht wiederholen
repeat-reward-items: Item Belohnung wiederholen
repeat-reward-experience: Erfahrungsbelohnung wiederholen
repeat-reward-money: Geld Belohnung wiederholen
repeat-reward-commands: Belohnungsbefehle wiederholen
remove-completed: Nach Fertigstellung entfernen
glow: Leuchtet nach Fertigstellung
line-length: Länge der Striche
cancel: Abbrechen
input: Eingabe
set: "="
increase: "+"
reduce: "-"
multiply: "*"
clear: Löschen
number: "[number]"
history-lifespan: Übersicht Lebensdauer
library: Webbibliothek
download: Download Bibliotheken
type:
island: "&6Inseltyp"
inventory: "&6Inventartyp"
other: "&6Anderer Typ"
import: ASkyblock-Herausforderungen importieren
settings: Einstellungen bearbeiten
name: Freundliche Bezeichnung
required-entities: Erforderliche Einheiten
remove-entities: Töte Einheiten
required-blocks: Erforderliche Blöcke
remove-blocks: Blöcke entfernen
search-radius: Suchradius
required-permissions: Erforderliche Berechtigungen
required-items: Erforderliche Items
remove-items: Items entfernen
waiver-amount: Verzichtsmenge
add-challenge: Herausforderung hinzufügen
remove-challenge: Herausforderung entfernen
reset-on-new: Reset auf neuer Insel
broadcast: Fertigstellung der Übertragung
visibility-mode: Herausforderung Sichtbarkeitsmodus
toggle-user-list: Benutzerliste
remove-selected: Auswahl entfernen
show-eggs: Ansichtsmodus wechseln
level-lore: Level-Beschreibung
challenge-lore: Beschreibung der Herausforderung
gui-view-mode: Alle Spielmodi anzeigen
gui-mode: Einzelne Herausforderungen GUI
history-store: Herausforderungen Historie
island-store: Shop pro Insel
default-locked-icon: Symbol für gesperrte Level
title-showtime: Titel Anzeigezeit
default-import: Importieren von Standardherausforderungen
default-export: Bestehende Herausforderungen exportieren
complete-wipe: Addon-Datenbanken löschen
challenge-wipe: Herausforderungen Datenbank löschen
players-wipe: Benutzerdatenbank löschen
delete-challenge: Herausforderung entfernen
properties: Eigenschaften
challenges: Herausforderungen
description: Beschreibung
environment: Umgebung
remove-on-complete: Nach Fertigstellung entfernen
required-money: Benötigtes Geld
remove-money: Geld entfernen
reward-text: Belohnungsnachricht
repeatable: Wiederholbar
free-at-top: Freie Herausforderungen zuerst
add: Hinzufügen
accept: Akzeptieren
decline: Ablehnen
save: speichern
value: Wert
remove-empty: Leer entfernen
input-mode: Eingabemodus wechseln
title-enable: Fertigstellungstitel
next: Nächste Seite
previous: Vorherige Seite
return: Zurück
value: Abgeschlossen
increase: Erhöhen
reduce: Reduzieren
descriptions:
admin:
input: Öffne Textfeldeingabe.
deployment: Ermöglicht es den Benutzern, die Herausforderung abzuschließen
(anzusehen).
icon-challenge: Symbol, das in GUI-Panels für diese Herausforderung angezeigt
wird.
icon-level: Symbol, das in den GUI-Panels für dieses Level angezeigt wird.
remove-completed: Aktiviert/deaktiviert das Ausblenden von Herausforderungen,
die abgeschlossen sind und nicht wiederholt werden können.
toggle-user-list: Zu einer anderen Spielerliste wechseln.
show-eggs: Wechselt die Ansicht der Objekte zwischen Eimodus oder Kopfmodus.
click-to-edit: "&4Hier klicken, um Eingaben zu bearbeiten."
input-mode: Wechsel zwischen Chat- und Amboss-Eingabemodus.
library-author: by &e[author]
library-lang: "&aSprache: [lang]"
library-gamemode: "&aPrimär für [gamemode]"
download-disabled: GitHub-Daten-Downloader ist in BentoBox deaktiviert. Ohne
ihn können keine Bibliotheken verwendet werden!
create-level: Neues Level hinzufügen.
edit-challenge: Herausforderung-Einstellungen bearbeiten.
edit-level: Level-Einstellungen bearbeiten.
delete-challenge: Eine Herausforderung entfernen.
delete-level: Ein Level entfernen.
settings: Einstellungen ändern.
properties: Allgemeine Eigenschaften ändern
requirements: Anforderungen verwalten
rewards: Belohnungen verwalten
description: Beschreibung bearbeiten.
order: Auftragsnummer ändern.
environment: Herausforderung Umfeld ändern.
name-challenge: Herausforderung Anzeigename ändern.
name-level: Level Anzeigename ändern.
remove-entities: Entferne (töte) Entitäten nach Abschluss der Herausforderung.
remove-blocks: Entferne ( ersetze durch Luft ) Blöcke nach Abschluss der Herausforderung.
search-radius: Radius um den Standort des Spielers, in dem die benötigten
Einheiten und Blöcke gesucht werden.
reward-text: Ändere die Nachricht, die dem Spieler nach Abschluss der Herausforderung
geschickt wird.
repeatable: Definiert, ob die Herausforderung wiederholbar ist oder nicht.
free-at-top: Freie Herausforderungen Standort wechseln. True bedeutet, diese
Herausforderungen werden die Ersten sein, sonst die Letzten.
line-length: Ändern der maximalen Zeilenlänge in der Lore Box. Hat keinen
Einfluss auf gespeicherte Objekte.
level-lore: Ändern welche Elemente der Levelbeschreibung sichtbar sein sollen.
challenge-lore: Ändern welche Elemente der Herausforderungsbeschreibung sichtbar
sein sollen.
gui-view-mode: Festlegen, ob /challenges GUI die Spielmodi oder Herausforderungen
in der Welt des Spielers anzeigen soll.
history-store: Aktivieren/Deaktivieren der Historienspeicherung von Herausforderungen.
default-import: Importieren von Standardherausforderungen.
default-export: Bestehende Herausforderungen in die Datei defaults.json exportieren.
complete-wipe: Vollständig alle Herausforderungen Addon-Datenbanken löschen.
Inklusive Spielerdaten!
challenge-wipe: Vollständig Herausforderungen und deren Leveldatenbanken löschen!
players-wipe: Vollständige Spielerdatenbank löschen!
library: Öffnet ein GUI, das alle verfügbaren öffentlichen Herausforderungen-Bibliotheken
anzeigt.
library-version: "&9Gemacht in Herausforderungen [version]"
save: Speichern und zur vorherigen GUI zurückkehren.
cancel: Rückkehr zur vorherigen GUI. Änderungen werden nicht gesichert.
set: Betrieb einstellen. Durch Anklicken der Zahlen wird der Wert auf die
ausgewählte Zahl geändert.
increase: Betrieb erhöhen. Durch Anklicken der Zahlen wird der Wert um die
gewählte Zahl erhöht.
reduce: Betrieb reduzieren. Durch Anklicken der Zahlen wird der Wert um die
gewählte Zahl reduziert.
multiply: Betrieb multiplizieren. Durch Anklicken der Zahlen wird der Wert
mit der ausgewählten Zahl multipliziert.
challenges: Verwalten von Level-Herausforderungen (hinzufügen/entfernen).
locked-icon: Symbol, das in GUI-Panels angezeigt wird, wenn das Level gesperrt
ist.
remove-on-complete: Entfernen einer Herausforderung aus der GUI eines Spielers,
nachdem sie abgeschlossen ist.
remove-items: Entfernen von Items aus dem Inventar des Spielers nach Abschluss
der Herausforderung.
required-experience: Die erforderliche Erfahrung für einen Benutzer festlegen,
um die Herausforderung abzuschließen.
remove-experience: Erforderliche Erfahrung entfernen.
reward-experience: Ändern der Erfahrungsbelohnung für den ersten Abschluss.
repeat-count: Maximale Anzahl der Wiederholungen festlegen. Wird der Wert
auf 0 gesetzt, gibt es keine Einschränkungen.
repeat-reward-text: Ändern der Nachricht, die dem Spieler nach dem wiederholten
Abschluss der Herausforderung geschickt wird.
repeat-reward-experience: Ändern der Erfahrungsbelohnung für den ersten Abschluss.
waiver-amount: Legt die Anzahl der Herausforderungen fest, die ein Spieler
auslassen kann, um das nächste Level freizuschalten.
reward-text-level: Ändere die Nachricht, die dem Spieler nach Abschluss aller
Herausforderungen in einem Level geschickt wird.
add-challenge: Fügt dem aktuellen Level eine bestehende Herausforderung hinzu.
remove-challenge: Eine Herausforderung aus dem aktuellen Level entfernen.
reset-on-new: Aktiviert/deaktiviert die Resets aller Herausforderungen für
einen Spieler, wenn er neu startet, die Insel verlässt oder von ihr gekickt
wird.
broadcast: Aktiviert/Deaktiviert die Übertragung über den Abschluss der ersten
Herausforderung für alle Spieler die online sind.
glow: Aktiviert/deaktiviert den Leuchteffekt für abgeschlossene Herausforderungen.
mode-online: Spieler, die gerade online sind.
mode-in-world: Spieler in einer Spielmodus-Welt.
mode-with-island: Spieler, die eine Insel in einer Spielmodus-Welt haben.
visibility-mode: Ein-/ausblenden von nicht umgesetzten Herausforderungen.
edit-text-line: "&6Textnachricht bearbeiten!"
add-text-line: "&6Neue Textnachricht hinzufügen!"
title-enable: Aktivieren/deaktivieren der Titelnachricht, die den Spielern
angezeigt wird, wenn sie eine Herausforderung abschließen.
title-showtime: Ändern wie lange Titelmeldungen für den Spieler sichtbar sein
sollen.
import: |-
ASkyblock-Herausforderungen importieren.
Bei Rechtsklick wird der Überschreibmodus aktiviert/deaktiviert.
Platziere die challenges.yml im Ordner ./BentoBox/addons/Challenges.
complete: |-
Herausforderung für jeden Benutzer abschließen.
Der Benutzer erhält keine Belohnung für den Abschluss.
reset: |-
Abgeschlossene Benutzerherausforderungen zurücksetzen.
Rechtsklick aktiviert/deaktiviert zurücksetzen aller Funktionen.
create-challenge: |-
Neue Herausforderung hinzufügen.
Wird standardmäßig in der Liste der freien Herausforderungen stehen.
required-entities: |-
Hinzufügen/Bearbeiten/Entfernen von erforderlichen Einheiten.
Einheiten:
required-blocks: |-
Erforderliche Blöcke hinzufügen/bearbeiten/entfernen.
Blöcke:
required-permissions: |-
Benötigte Berechtigungen für den Spieler, um diese Herausforderung abzuschließen.
Berechtigung:
required-items: |-
Benötigte Items im Inventar des Spielers.
Items:
required-level: |-
Legt das für diese Herausforderung erforderliche Insellevel fest.
&cBenötigt Level-Addon.'
required-money: |-
Legt das erforderliche Geld auf dem Spielerkonto fest.
&cErfordert Vault und ein Economy-Plugin.'
remove-money: |-
Entfernt das erforderliche Geld vom Spielerkonto.
&cErfordert Vault und ein Economy-Plugin.'
reward-items: |-
Ändere die Itembelohnungen für den erstmaligen Abschluss.
Items:
reward-money: |-
Ändere die Geldbelohnung für den ersten Abschluss.
&cErfordert Vault und Economy-Plugin.
reward-commands: |-
Legt Belohnungsbefehle fest, die nach der ersten Ausführung aufgerufen werden.
***Das Hinzufügen von "[SELF]" am Anfang bedeutet, dass der Befehl vom Spieler ausgeführt wird, z.B. "/kill".
***Zeichenfolge "[player]" wird durch den Spielernamen ersetzt, z.B. wird "/kill [player]" in "/kill BONNe1704" umgewandelt
Befehle:
repeat-reward-items: |-
Ändert die Itembelohungen für den wiederholten Abschluss.
Items:
repeat-reward-money: |-
Ändert die Geldbelohnung für den wiederholten Abschluss.
&cErfordert Vault und ein Economy-Plugin.
repeat-reward-commands: |-
Legt Belohnungsbefehle fest, die nach wiederholter Ausführung der Herausforderung ausgeführt werden.
***Hinzufügen von "[SELF]" am Anfang bedeutet, dass der Befehl vom Spieler ausgeführt wird, z.B. "/kill".
***Zeichenfolge "[player]" wird durch den Spielernamen ersetzt, z.B. wird "/kill [player]" in "/kill BONNe1704" umgewandelt
Befehle:
remove-selected: |-
Ausgewählte Elemente entfernen.
Elemente mit der rechten Maustaste auswählen.
history-lifespan: |-
Ändern für wie viele Tage die Daten der Historie gespeichert werden sollen.
0 bedeutet für immer.
island-store: |-
Aktivieren/Deaktivieren der Herausforderungen Datenspeicherung pro Insel. Das bedeutet, dass die Herausforderungen für das gesamte Team gleich sind, wenn dies aktiviert ist.
&cWird NICHT bei Klick Daten konvertieren. DER FORTSCHRITT GEHT VERLOREN.
default-locked-icon: |-
Ändert das Standardsymbol des gesperrten Levels.
Diese Option kann von jedem Level überschrieben werden.'
gui-mode: |-
Aktivieren/Deaktivieren einzelner Herausforderungen GUI.
&2Erfordert einen Server-Neustart.'
download: |-
Manuelle Aktualisierung der verfügbaren Herausforderungen-Bibliotheken.
Rechtsklick zum Aktivieren der Cache-Leerung.'
lore:
level: |-
Level-Zeichenfolge.
Stellt die Übersetzung challenge.gui.challenge-description.level dar.
status: |-
Status-Zeichenfolge.
Stellt die Übersetzung challenge.gui.challenge-description.completed dar.
count: |-
Zeichenfolge für den Abschluss der Zählung.
Stellt die Übersetzung für challenges.gui.challenge-description.completed-times dar.
challenges.gui.challenge-description.completed-times-of
und challenges.gui.challenge-description.maxed-reached
description: |-
Beschreibung Zeichenfolge.
Festgelegt in Challenge-Objekt - challenge.description.
warnings: |-
Warnzeichenfolge.
Stellt die Übersetzung dar für:
challenges.gui.challenge-description.warning-items-take
challenges.gui.challenge-description.objects-close-by
challenges.gui.challenge-description.warning-entities-kill
challenges.gui.challenge-description.warning-blocks-remove
environment: |-
Umgebung Zeichenkette.
Festgelegt in Challenges Objekt - challenge.environment.
requirements: |-
Anforderungszeichenfolge.
Stellt die Übersetzung dar von:
challenges.gui.challenge-description.required-level
challenges.gui.challenge-description.required-money
challenges.gui.challenge-description.required-experience
challenge.requiredItems'
challenge.requiredBlocks'
or challenge.requiredEntities.
reward_text: |-
Belohnungs-Zeichenfolge.
Festgelegt in challenge.rewardText und challenge.repeatRewardText
reward_other: |-
Belohnung andere Zeichenfolge.
Stellt die Übersetzung dar für:
challenges.gui.challenge-description.experience-reward
challenges.gui.challenge-description.money-reward
challenges.gui.challenge-description.not-repeatable
reward_items: |-
Itembelohnungen.
Liste der Items, die zu Belohnungen werden, festgelegt in challenge.rewardItems und challenge.repeatRewardItems.
reward_commands: |-
Belohnungsbefehle.
Liste der Befehle, die Belohnen sollen, festgelegt in challenge.rewardCommands und challenge.repeatRewardCommands.
level_status: |-
Status-Zeichenfolge.
Stellt die Übersetzung von challenges.gui.level-description.completed dar.
challenge_count: |-
Abgeschlossener Herausforderung Zähl Zeichenfolge
Stellt die Übersetzung für challenges.gui.level-description.completed-challenges-of dar.
unlock_message: |-
Entsperren der Nachricht Zeichenfolge.
Festgelegt in Herausforderungen Levelobjekt - challengeLevel.unlockMessage
waiver_amount: |-
Die Anzahl der versetzbaren Herausforderungen, um die nächste Level-Zeichenkette freizuschalten.
Stellt die Übersetzung für challenges.gui.level-description.waver-amount dar
level_reward_text: |-
Belohnungs-Zeichenfolge.
Festgelegt in challengeLevel.rewardText
level_reward_other: |-
Belohnung anderer Zeichenfolge.
Stellt die Übersetzung dar für:
challenges.gui. level-description. experience-reward.
challenges.gui. level-description. money-reward
level_reward_items: |-
Itembelohnungen.
Liste der Items, die zu Belohnungen werden, festgelegt in challengeLevel.rewardItems
level_reward_commands: |-
Belohnungsbefehle.
Liste der Befehle, die zu Belohnungen führen, festgelegt in challengeLevel.rewardCommands
selected: Ausgewählt
the-end: "- End"
nether: "- Nether"
normal: "- Oberwelt"
entity: "- [entity] : [count]"
block: "- [block] : [count]"
permission: "- [permission]"
item: "- [count] x [item]"
item-meta: "([meta])"
item-enchant: "- [enchant] [level]"
command: "- [command]"
level-unlocked: Klicke, um [level] Herausforderungen zu sehen!
level-locked: Schließe [count] weitere [level] Herausforderungen ab, um dieses
Level freizuschalten!
increase-by: "&aErhöhung der Fertigstellung um [value]"
reduce-by: "&cReduzierung der Fertigstellungen um [value]"
visibility:
hidden: Nur eingesetzte Herausforderungen sind sichtbar.
visible: Alle Herausforderungen sind für jeden sichtbar
toggleable: Umschalten, ob nicht verteilte Herausforderungen angezeigt werden
sollen
type:
island: "&aErfordert Blöcke oder Mobs um Spieler"
other: "&aErfordert Dinge von anderen Plugins/Addons"
inventory: "&aErforderliche Items im Inventar des Spielers"
current-value: "&6Aktueller Wert: [value]."
enabled: Aktiv
disabled: Deaktiviert
challenge-description:
completed-times-of: "[donetimes] erledigt aus [maxtimes]"
maxed-reached: "[donetimes] erledigt aus [maxtimes]"
completed-times: "[donetimes] erledigt"
objects-close-by: "&cAlle benötigten Blöcke und Objekte müssen sich in deiner
Nähe auf deiner Insel befinden!"
warning-entities-kill: "&cAlle erforderlichen Einheiten werden getötet, wenn
du diese Herausforderung abschließt!"
warning-blocks-remove: "&cAlle benötigten Blöcke werden entfernt, wenn du diese
Herausforderung abschließt!"
not-repeatable: "&cDiese Herausforderung ist nicht wiederholbar!"
experience-reward: "&6Exp Belohnung: [value]"
money-reward: "&6Geld Belohnung: $[value]"
required-experience: "&6Erforderliche Exp: [value]"
required-money: "&6Erforderliches Geld: $[value]"
required-island-level: "&6Erforderliches Insellevel: [value]"
reward-items: "&6Item Belohnungen:"
reward-commands: "& 6Belohnungsbefehle:"
required-items: 'Erforderliche Items:'
level: "&fLevel: [level]"
completed: "&bAbgeschlossen"
warning-items-take: "&cAlle erforderlichen Items werden aus deinem Inventar
genommen, wenn du diese Herausforderung abschließt!"
environment: 'Erforderliche Umgebungen:'
required-entities: 'Erforderliche Einheiten:'
required-blocks: 'Erforderliche Blöcke:'
level-description:
experience-reward: "&6Exp Belohnung: [value]"
money-reward: "&6Geldbelohnung: $[value]"
reward-items: "&6Item Belohnungen:"
reward-commands: "&6Belohnungsbefehle:"
waver-amount: "&6[value] Herausforderungen können übersprungen werden, um das
nächste Level freizuschalten."
completed: "&bAbgeschlossen"
completed-challenges-of: "&3Du hast [number] aus [max] Herausforderungen in
diesem Level abgeschlossen."
item-description:
item: "- [count] x [item]"
item-meta: "([meta])"
item-enchant: "- [enchant] [level]"
item-name: "[name]"
item-lore: 'Item Lore:'
book-meta: "[title] von [author]"
recipe-count: "[count] Rezepte"
armor-color: "[color]"
potion-type-extended-upgraded: Erweitert und verbessert [name]
potion-type-upgraded: Aktualisiert [name]
potion-type-extended: Erweitert [name]
potion-type: "[name]"
custom-effects: 'Benutzerdefinierte Effekte:'
potion-effect: "[effect] x [amplifier] für [duration]t"
skull-owner: "[owner]"
egg-meta: "[mob]"
fish-meta: "[body-color] mit [pattern-color] [pattern]"
questions:
prefix: "&2[SERVER]:"
admin:
unique-id: Schreibe den eindeutigen Namen des Objekts und drücke die Eingabetaste.
number: Schreibe eine Zahl in den Chat und drücke die Eingabetaste.
challenge-name: Schreibe den Anzeigenamen für die aktuelle Herausforderung
in den Chat.
level-name: Schreibe den Anzeigenamen für das aktuelle Level in den Chat.
titles:
challenge-subtitle: "[friendlyName]"
level-subtitle: "[friendlyName]"
challenge-title: Erfolgreich abgeschlossen
level-title: Erfolgreich abgeschlossen
messages:
admin:
you-added: Du hast der Herausforderung eine [thing] hinzugefügt
challenge-created: "[challenge] &r erstellt!"
completed: Du hast Herausforderung [name] für [player] abgeschlossen!
already-completed: "&2Diese Herausforderung wurde bereits abgeschlossen!"
reset: "&2Du setzt Herausforderung [name] für [player] zurück!"
reset-all: "&2Alle [Player] Herausforderungen wurden zurückgesetzt!"
not-completed: "&2Diese Herausforderung ist noch nicht abgeschlossen!"
migrate-start: "&2Beginne Migration von Herausforderungen Addon-Daten."
migrate-not: "&2Alle Daten sind gültig."
start-downloading: "&5Starten des Downloads und Imports der Herausforderungen-Bibliothek."
migrate-end: "&2Herausforderungen Addon-Daten auf neues Format aktualisiert."
hit-things: Anklicken der Dinge, um sie zur Liste der benötigten Dinge hinzuzufügen.
Rechtsklick, wenn du fertig bist.
complete-wipe: "&cHoffentlich hast du Backups, denn du hast gerade alle Datenbanken
des Challenges Addons gelöscht!"
challenge-wipe: "&cHoffentlich hast du Backups, denn du hast gerade alle Herausforderungen
und ihre Level gelöscht!"
players-wipe: "&cHoffentlich hast du Backups, denn du löschst einfach alle abgeschlossenen
Herausforderungen des Spielers!"
you-completed-challenge: "&2Du hast die [value] &r&2Herausforderungen abgeschlossen!"
you-repeated-challenge: "&2Du hast die [value] &r&2Herausforderung wiederholt!"
you-repeated-challenge-multiple: "&2Du hast die [value] &r&2Herausforderungen
[count] mal wiederholt!"
you-completed-level: "&2Du hast den [value] &r&2level abgeschlossen!"
name-has-completed-challenge: "&5[name] hat die [value] &r&5-Herausforderung abgeschlossen!"
name-has-completed-level: "&5[name] hat den [value] &r&5Level abgeschlossen!"
import-levels: Startet Importieren von Leveln
import-challenges: Startet Importieren von Herausforderungen
no-levels: 'Warnung: Keine Level in der challenges.yml definiert'
import-number: "[number] Herausforderungen importiert"
load-skipping: '"[value]" existiert bereits - überspringen'
load-overwriting: Überschreibt "[value]"
load-add: 'Neues Objekt hinzufügen: [value]'
defaults-file-overwrite: defaults.json existiert. Sie wird überschrieben.
defaults-file-completed: defaults.json Datei ist mit Herausforderungen von [world]
belegt!
errors:
no-name: "&cFehlender Herausforderungsname"
unknown-challenge: "&cUnbekannte Herausforderung"
unique-id: '&cEindeutige ID "[id]" ist nicht gültig.'
wrong-icon: '&cGegebenes Material "[value]" ist nicht gültig und kann nicht als
Symbol verwendet werden.'
not-deployed: "&cHerausforderung wird nicht eingesetzt!"
not-on-island: "&cDu musst auf deiner Insel sein, um das zu tun!"
not-repeatable: "&cDiese Herausforderung ist nicht wiederholbar!"
not-enough-items: "&cDu hast nicht genug [items], um diese Herausforderung abzuschließen!"
not-close-enough: "&cDu musst innerhalb von [number] Blöcken aller benötigten
Positionen stehen."
you-still-need: "&cDu brauchst noch [amount] x [item]"
not-enough-money: "&cEs ist notwendig, [value] auf deinem Konto zu haben, um die
Herausforderung abzuschließen."
import-no-file: "&cEs konnte keine challenges.yml Datei zum Importieren gefunden
werden!"
no-load: "&cFehler: Die challenges.yml konnte nicht geladen werden.[message]"
load-error: "&cFehler: [value] kann nicht geladen werden."
defaults-file-exist: "&cdefaults.json existiert bereits. Benutze den Überschreibungsmodus,
um sie zu ersetzen!"
defaults-file-error: "&cBeim Erstellen der Datei defaults.json ist ein Fehler
aufgetreten! Konsole überprüfen!"
missing-arguments: "&cDem Befehl fehlen Argumente."
wrong-environment: "&cDu bist in der falschen Umgebung!"
missing-addon: "&cKann die Herausforderung nicht vollenden: Benötigtes Addon oder
Plugin fehlt."
exist-challenges-or-levels: "&cDie Herausforderung existiert bereits in deiner
Welt. Kann nicht fortfahren!"
no-challenges: "&cDie Herausforderungen sind in dieser Welt noch nicht implementiert!"
no-challenges-admin: "&cDie Herausforderungen sind in dieser Welt noch nicht implementiert!
Verwende &5/[command] &cum sie hinzuzufügen!"
missing-level: "&cHerausforderung Level [level] ist in der Datenbank nicht festgelegt.
Dies kann Fehler verursachen!"
no-multiple-permission: "&cDu hast keine Berechtigung, diese Herausforderung mehrmals
hintereinander auszuführen."
not-a-integer: '&cDer angegebene Wert "[value]" ist keine ganze Zahl!'
challenge-level-not-available: "&cDu hast das erforderliche Level nicht freigeschaltet,
um diese Herausforderung abzuschließen."
incorrect: "&cKann die Herausforderung nicht abschließen: Anforderungen sind falsch."
not-enough-experience: "&cEs ist notwendig [value] EXP zu haben, um diese Herausforderung
abzuschließen."
island-level: "&cDeine Insel muss mindestens Level [number] oder höher sein, um
diese Herausforderung abzuschließen!"
no-rank: "&cDu hast keinen Rang, der hoch genug ist, um das zu tun."
cannot-remove-items: "&cEinige Items können nicht aus deinem Inventar entfernt
werden!"
not-valid-integer: |-
&cDie Angabe der ganzen Zahl "[value]" ist nicht gültig!
Der Wert sollte zwischen [min] und [max] liegen.
protection:
flags:
CHALLENGES_ISLAND_PROTECTION:
description: "&5&Umschalten, wer &5&Herausforderungen erledigen kann"
name: Herausforderungen Schutz
CHALLENGES_WORLD_PROTECTION:
description: "&5&oAktivieren/Deaktivieren von \n&5&oAnforderung für Spieler,\n&5&oauf
ihrer Insel zu sein, um \n&5&oeine Herausforderung abzuschließen."
name: Herausforderungen Inselbegrenzung
hint: Keine Herausforderungen außerhalb der Insel
version: 11
meta:
authors:
- xXjojoXx

View File

@ -14,38 +14,42 @@ challenges:
parameters: ''
description: 'Main admin command. Opens GUI.'
import:
description: 'Import challenges from challenges.yml|Parameter overwrite means that challenges or levels with the same ID will be overwritten.'
description: |-
Import challenges from challenges.yml
Parameter overwrite means that challenges or levels with the same ID will be overwritten.
parameters: '[overwrite]'
reload:
description: 'Reload challenges from the database|Parameter hard means that addon will reset connection to database.'
description: |-
Reload challenges from the database
Parameter hard means that addon will reset the connection to the database.
parameters: '[hard]'
show:
description: 'This method prints in chat all challenges that exist in world.'
description: 'Prints all challenges in the chat which exist in this world.'
parameters: ''
defaults:
description: 'This method shows subcommands that allows to import/export default challenges.'
description: 'Shows subcommands to import/export the default challenges.'
parameters: '[command]'
defaults-import:
description: 'This method allows to import default challenges.'
description: 'Import the default challenges.'
parameters: ''
defaults-generate:
description: 'This method allows to export existing challenges into default.json file.'
description: 'Export existing challenges to default.json file.'
parameters: '[overwrite] - allows to overwrite existing file.'
complete:
description: 'This command allows to complete challenge for player without GUI.'
description: 'Complete a challenge for a player.'
parameters: '<player> <challenge_id>'
reset:
description: 'This command allows to reset challenge for player without GUI. If "challenge_id" is set to "all", then it will reset all challenges.'
description: 'Reset a challenge for a player. If "challenge_id" is set to "all", then it will reset all challenges.'
parameters: '<player> <challenge_id>'
migrate:
description: 'This method allows to migrate challenges data that refers to current game mode world to new 0.8.0 storage format.'
description: 'Migrate current game world challenges data to 0.8.0 storage format.'
parameters: ''
user:
main:
description: 'This method opens Challenges GUI.'
description: 'Open Challenges GUI.'
parameters: ''
complete:
description: 'This method allows to complete challenge without GUI.'
description: 'Complete challenge.'
parameters: '<challenge_id> [count]'
gui:
title:
@ -89,8 +93,8 @@ challenges:
edit-level: 'Edit level'
delete-challenge: 'Remove challenge'
delete-level: 'Remove level'
import: 'Import ASkyblock Challenges'
settings: 'Edit Settings'
import: 'Import ASkyblock challenges'
settings: 'Edit settings'
properties: 'Properties'
requirements: 'Requirements'
rewards: 'Rewards'
@ -102,15 +106,15 @@ challenges:
order: 'Order'
environment: 'Environment'
remove-on-complete: 'Remove after completion'
name: 'Friendly Name'
required-entities: 'Required Entities'
remove-entities: 'Kill Entities'
required-blocks: 'Required Blocks'
remove-blocks: 'Remove Blocks'
search-radius: 'Search Radius'
required-permissions: 'Required Permissions'
required-items: 'Required Items'
remove-items: 'Remove Items'
name: 'Friendly name'
required-entities: 'Required entities'
remove-entities: 'Kill entities'
required-blocks: 'Required blocks'
remove-blocks: 'Remove blocks'
search-radius: 'Search radius'
required-permissions: 'Required permissions'
required-items: 'Required items'
remove-items: 'Remove items'
required-experience: 'Required experience'
remove-experience: 'Remove experience'
required-level: 'Required island level'
@ -128,20 +132,20 @@ challenges:
repeat-reward-experience: 'Repeat reward experience'
repeat-reward-money: 'Repeat reward money'
repeat-reward-commands: 'Repeat reward commands'
waiver-amount: 'Waiver Amount'
add-challenge: 'Add Challenge'
remove-challenge: 'Remove Challenge'
reset-on-new: 'Reset On New Island'
broadcast: 'Broadcast Completion'
waiver-amount: 'Waiver amount'
add-challenge: 'Add challenge'
remove-challenge: 'Remove challenge'
reset-on-new: 'Reset on new island'
broadcast: 'Broadcast completion'
remove-completed: 'Remove after complete'
glow: 'Glow when completed'
free-at-top: 'Free challenges first'
line-length: 'Lore line length'
visibility-mode: 'Challenge Visibility Mode'
toggle-user-list: 'User List'
remove-selected: 'Remove Selected'
visibility-mode: 'Challenge visibility mode'
toggle-user-list: 'User list'
remove-selected: 'Remove selected'
add: 'Add'
show-eggs: 'Switch View mode'
show-eggs: 'Switch view mode'
accept: 'Accept'
decline: 'Decline'
save: 'Save'
@ -155,22 +159,22 @@ challenges:
clear: 'Clear'
remove-empty: 'Remove empty'
number: '[number]'
level-lore: 'Level Description'
challenge-lore: 'Challenge Description'
gui-view-mode: 'Display All GameModes'
gui-mode: 'Single Challenges GUI'
history-store: 'Challenges History'
level-lore: 'Level description'
challenge-lore: 'Challenge description'
gui-view-mode: 'Display all GameModes'
gui-mode: 'Single challenges GUI'
history-store: 'Challenges history'
history-lifespan: 'History LifeSpan'
island-store: 'Store per Island'
default-locked-icon: 'Locked Level Icon'
island-store: 'Store per island'
default-locked-icon: 'Locked level icon'
input-mode: 'Switch input mode'
title-enable: 'Completion title'
title-showtime: 'Title Show Time'
default-import: 'Import Default Challenges'
default-export: 'Export Existing Challenges'
complete-wipe: 'Wipe Addon Databases'
challenge-wipe: 'Wipe Challenges Database'
players-wipe: 'Wipe User Database'
title-showtime: 'Title show time'
default-import: 'Import default challenges'
default-export: 'Export existing challenges'
complete-wipe: 'Wipe addon databases'
challenge-wipe: 'Wipe challenges database'
players-wipe: 'Wipe user database'
library: 'Web Library'
download: 'Download Libraries'
@ -188,142 +192,246 @@ challenges:
reduce: "Reduce"
descriptions:
admin:
save: 'Save and return to previous GUI.'
cancel: 'Return to previous GUI. Changes will not be saved.'
save: 'Save and return to the previous GUI.'
cancel: 'Return to the previous GUI. Changes will not be saved.'
input: 'Open text field input.'
set: 'Set operation. Clicking on numbers will change value to selected number.'
increase: 'Increase operation. Clicking on numbers will increase value by selected number.'
reduce: 'Reduce operation. Clicking on numbers will reduce value by selected number.'
multiply: 'Multiply operation. Clicking on numbers will multiply value by selected number.'
import: 'Allows to import ASkyblock Challenges.|On right click it enables/disables overwrite mode.|Place Challenges.yml inside ./BentoBox/addons/Challenges folder.'
complete: 'Allows to complete challenges for any user.|User will not get reward for completion.'
reset: 'Allows to reset completed user challenges.|Right click enables/disables Reset all functionality.'
create-challenge: 'Allows to add new Challenge.|By default it will be in free challenges list.'
create-level: 'Allows to add new Level.'
edit-challenge: 'Allows to edit any Challenge settings.'
edit-level: 'Allows to edit any Level settings.'
delete-challenge: 'Allows remove any Challenge.'
delete-level: 'Allows remove any Level.'
settings: 'Allows to change addon settings.'
properties: 'Allows to change general properties'
requirements: 'Allows to manage requirements'
rewards: 'Allows to manage rewards'
challenges: 'Allows to manage level challenges (add / remove).'
set: 'Set operation. Clicking on the numbers will change the value to the selected number.'
increase: 'Increase operation. Clicking on the numbers will increase the value by the selected number.'
reduce: 'Reduce operation. Clicking on the numbers will reduce the value by the selected number.'
multiply: 'Multiply operation. Clicking on the numbers will multiply the value by the selected number.'
import: |-
Import ASkyblock challenges.
On right click it enables/disables overwrite mode.
Place challenges.yml inside the ./BentoBox/addons/Challenges folder.
complete: |-
Complete challenges for any user.
The user will not get any reward for completion.
reset: |-
Reset completed user challenges.
Right click enables/disables Reset all functionality.
create-challenge: |-
Add new challenge.
Will be in free challenges list by default.
create-level: 'Add new Level.'
edit-challenge: 'Edit Challenge settings.'
edit-level: 'Edit Level settings.'
delete-challenge: 'Remove a Challenge.'
delete-level: 'Remove a Level.'
settings: 'Change settings.'
properties: 'Change general properties'
requirements: 'Manage requirements'
rewards: 'Manage rewards'
challenges: 'Manage level challenges (add / remove).'
deployment: 'Allows users to complete (view) challenge.'
icon-challenge: 'Icon that will be displayed in GUI panels for this challenge.'
icon-level: 'Icon that will be displayed in GUI panels for this level.'
locked-icon: 'Icon that will be displayed in GUI panels if level is locked.'
description: 'Allows to edit description.'
order: 'Allows to change order number.'
environment: 'Allows to change environment where challenge operates.'
remove-on-complete: 'Allows to remove challenge from player GUI after it is completed.'
name-challenge: 'Allows to change challenge display name.'
name-level: 'Allows to change level display name.'
required-entities: 'Allows to add/edit/remove required entities.|Entities:|'
remove-entities: 'Allows to remove (kill) entities on challenge completion.'
required-blocks: 'Allows to add/edit/remove required blocks.|Blocks:|'
remove-blocks: 'Allows to remove (replace with air) blocks on challenge completion.'
search-radius: 'Radius around player location where required entities and blocks will be searched.'
required-permissions: 'Required permissions for player to be able to complete challenge.|Permission:'
required-items: 'Required items in player"s inventory.|Items:'
remove-items: 'Allows to remove items from player inventory after challenge completion.'
required-experience: 'Allows to define required experience for user to complete challenge.'
remove-experience: 'Allows to remove remove required experience.'
required-level: 'Allows to define required island level for this challenge.|&cRequires Level addon.'
required-money: 'Allows to define required money in player"s account.|&cRequires Vault and Economy plugin.'
remove-money: 'Allows to remove required money from player"s account.|&cRequires Vault and Economy plugin.'
reward-text: 'Allows to change message that will be sent to player after challenges completion.'
reward-items: 'Allows to change first time completion reward items.|Items:'
reward-experience: 'Allows to change first time completion reward Experience.'
reward-money: 'Allows to change first time completion reward Money.|&cRequires Vault and Economy plugin.'
reward-commands: 'Allows to define reward commands that will be called after first time completion.|***Adding "[SELF]" at the start means that command will be run by player, f.e. "/kill"|***String "[player]" will be replaced with player name, f.e. "/kill [player]" will be transformed to "/kill BONNe1704"|Commands:'
repeatable: 'Allows to define if challenge is repeatable or not.'
repeat-count: 'Allows to define maximal repeat count. If value is set 0 or smaller, then there are no limitations.'
repeat-reward-text: 'Allows to change message that will be sent to player after challenge repeated completion.'
repeat-reward-items: 'Allows to change repeated completion reward items.|Items:'
repeat-reward-experience: 'Allows to change repeated completion reward Experience.'
repeat-reward-money: 'Allows to change repeated completion reward Money.|&cRequires Vault and Economy plugin.'
repeat-reward-commands: 'Allows to define reward commands that will be called after challenge repeated completion.|***Adding "[SELF]" at the start means that command will be run by player, f.e. "/kill"|***String "[player]" will be replaced with player name, f.e. "/kill [player]" will be transformed to "/kill BONNe1704"|Commands:'
waiver-amount: 'Allows to set how many challenges can be left undone to unlock next level.'
reward-text-level: 'Allows to change message that will be sent to player after completing all challenges in level.'
add-challenge: 'Allows to add existing challenge to current level.'
remove-challenge: 'Allows remove any challenge from current level.'
reset-on-new: 'Enables/Disables option, that resets all player challenges if player restarts island, leave island or was kicked out.'
broadcast: 'Enables/Disables broadcast to online players about first time challenge completion.'
locked-icon: 'Icon that will be displayed in GUI panels if the level is locked.'
description: 'Edit description.'
order: 'Change order number.'
environment: 'Change challenge environment.'
remove-on-complete: 'Remove a challenge from a player"s GUI after it is completed.'
name-challenge: 'Change challenge display name.'
name-level: 'Change level display name.'
required-entities: |-
Add/edit/remove required entities.
Entities:
remove-entities: 'Remove (kill) entities on challenge completion.'
required-blocks: |-
Add/edit/remove required blocks.
Blocks:
remove-blocks: 'Remove (replace with air) blocks on challenge completion.'
search-radius: "Radius around player's location where required entities and blocks will be searched."
required-permissions: |-
Required permissions a for player to be able to complete this challenge.
Permission:
required-items: |-
Required items in player"s inventory.
Items:
remove-items: 'Remove items from player"s inventory after challenge completion.'
required-experience: 'Define required experience for a user to complete the challenge.'
remove-experience: 'Remove required experience.'
required-level: |-
Define the required island level for this challenge.
&cRequires Level addon.'
required-money: |-
Define the required money in player"s account.
&cRequires Vault and an Economy plugin.'
remove-money: |-
Remove required money from player"s account.
&cRequires Vault and an Economy plugin.'
reward-text: 'Change message that will be sent to player after challenges completion.'
reward-items: |-
Change first time completion reward items.
Items:
reward-experience: 'Change first time completion reward experience.'
reward-money: |-
Change first time completion reward money.
&cRequires Vault and Economy plugin.
reward-commands: |-
Define reward commands that will be called after first time completion.
***Adding "[SELF]" at the start means that command will be run by player, e.g. "/kill"
***String "[player]" will be replaced with player name, e.g. "/kill [player]" will be transformed to "/kill BONNe1704"
Commands:
repeatable: 'Define if challenge is repeatable or not.'
repeat-count: 'Define maximal repeat count. If the value is set 0, there are no limitations.'
repeat-reward-text: 'Change message that will be sent to the player after challenge repeated completion.'
repeat-reward-items: |-
Change repeated completion reward items.
Items:
repeat-reward-experience: 'Change repeated completion reward experience.'
repeat-reward-money: |-
Change repeated completion reward money.
&cRequires Vault and an Economy plugin.
repeat-reward-commands: |-
Define reward commands that will be executed after challenge repeated completion.
***Adding "[SELF]" at the start means that command will be run by player, e.g. "/kill"
***String "[player]" will be replaced with player name, e.g. "/kill [player]" will be transformed to "/kill BONNe1704"
Commands:
waiver-amount: 'Set the amount of challenges a player can leave out to unlock the next level.'
reward-text-level: 'Change the message that will be sent to the player after completing all challenges in a level.'
add-challenge: 'Add an existing challenge to the current level.'
remove-challenge: 'Remove a challenge from the current level.'
reset-on-new: 'Enables/Disables resets of all challenges for a player if they restart, leave or get kicked from an island.'
broadcast: 'Enables/Disables the broadcast about the first time challenge completion to all online players.'
remove-completed: 'Enables/Disables hiding challenges that are completed and cannot be repeated.'
glow: 'Enables/Disables glowing effect for completed challenges.'
free-at-top: 'Allows to change free challenges location. True mean that challenges will be first, otherwise they will be last.'
line-length: 'Allows to modify maximal line length in lore box. Will not affect stored objects.'
glow: 'Enables/Disables the glowing effect for completed challenges.'
free-at-top: 'Change free challenges location. True means that challenges will be first, otherwise they will be last.'
line-length: 'Modify the maximum line length in lore box. Will not affect stored objects.'
toggle-user-list: 'Switch to different player list.'
mode-online: 'Players which currently are online.'
mode-in-world: 'Players which is in GameMode world.'
mode-with-island: 'Players which has island in GameMode.'
mode-online: 'Players which are currently online.'
mode-in-world: 'Players in a GameMode world.'
mode-with-island: 'Players that have an island in a GameMode world.'
selected: 'Selected'
remove-selected: 'Remove selected elements.|You can select elements with right mouse button.'
remove-selected: |-
Remove selected elements.
Select elements with the right mouse button.
show-eggs: 'Switch entity view between Egg mode or Head mode.'
level-lore: 'Allows to modify which elements of level description should be visible.'
challenge-lore: 'Allows to modify which elements of challenge description should be visible.'
gui-view-mode: 'Allows to set if /challenges GUI should show GameModes or challenges in players world.'
history-store: 'Allows to enable/disable challenges history storage.'
history-lifespan: 'Allows to modify how many days history data will be saved.|0 means forever.'
island-store: 'Allows to enable/disable challenges data storing per island. This means that challenges will be the same on whole team, if this is enabled.|Will NOT convert data on click. PROGRESS WILL BE LOST.'
default-locked-icon: 'Allows to change default locked level icon.|This option can be overwritten by each level.'
gui-mode: 'Allows to enable/disable single challenges GUI.|&2Requires server restart.'
visibility-mode: 'Allows to switch if undeployed challenges should be displayed or not.'
level-lore: 'Modify which level description elements should be visible.'
challenge-lore: 'Modify which challenge description elements should be visible.'
gui-view-mode: "Set if /challenges GUI should show GameModes or challenges in player's world."
history-store: 'Enable/disable challenges history storage.'
history-lifespan: |-
Modify how many days history data should be stored.
0 means forever.
island-store: |-
Enable/disable challenges data storing per island. This means that challenges will be the same for the whole team if this is enabled.
&cWill NOT convert data on click. PROGRESS WILL BE LOST.'
default-locked-icon: |-
Change default locked level icon.
This option can be overwritten by each level.'
gui-mode: |-
Enable/disable single challenges GUI.
&2Requires a server restart.'
visibility-mode: 'Show/hide undeployed challenges.'
click-to-edit: '&4Click here to edit input.'
edit-text-line: '&6 Edit text message!'
add-text-line: '&6 Add new text message!'
edit-text-line: '&6Edit text message!'
add-text-line: '&6Add new text message!'
input-mode: 'Switch between chat and anvil input modes.'
title-enable: 'Allows to enable/disable title message that will be showed when player complete challenge.'
title-showtime: 'Allows to modify how long title message will be visible for player.'
default-import: 'Allows to import default challenges.'
default-export: 'Allows to export existing challenges into defaults.json file.'
complete-wipe: 'Allows to completely clear all challenges addon databases. Includes player data!'
title-enable: 'Enable/disable the title message that will be shown to player"s when they complete a challenge.'
title-showtime: 'Modify how long title messages will be visible to the player.'
default-import: 'Import default challenges.'
default-export: 'Export existing challenges to defaults.json file.'
complete-wipe: 'Completely clear all challenges addon databases. Includes player data!'
challenge-wipe: 'Allows to completely clear challenges and their level databases!'
players-wipe: 'Allows to completely clear player database!'
challenge-wipe: 'Completely clear challenges and their level databases!'
players-wipe: 'Completely clear player database!'
library: 'Opens GUI that shows all available public Challenges Libraries.'
library: 'Open GUI that shows all available public Challenges Libraries.'
library-author: 'by &e[author]'
library-version: '&9Made on Challenges [version]'
library-version: '&9Made in Challenges [version]'
library-lang: '&aLanguage: [lang]'
library-gamemode: '&aPrimary for [gamemode]'
download: 'Allows manually update available challenges libraries. |Right click to enable cache clearing.'
download: |-
Manually update available challenges libraries.
Right click to enable cache clearing.'
download-disabled: 'GitHub data downloader is disabled in BentoBox. Without it, you cannot use Libraries!'
lore:
level: "Level string. | Represents translation 'challenges.gui.challenge-description.level'."
status: "Status string. | Represents translation 'challenges.gui.challenge-description.completed'."
count: "Completion count string. | Represents translation for 'challenges.gui.challenge-description.completed-times', 'challenges.gui.challenge-description.completed-times-of' and 'challenges.gui.challenge-description.maxed-reached'."
description: "Description string. | Defined in challenges object - challenge.description."
warnings: "Warning string. | Represents translation for: | 'challenges.gui.challenge-description.warning-items-take' | 'challenges.gui.challenge-description.objects-close-by' | 'challenges.gui.challenge-description.warning-entities-kill' | 'challenges.gui.challenge-description.warning-blocks-remove'."
environment: "Environment string. | Defined in challenges object - challenge.environment."
requirements: "Requirement string. | Represents translation for: | 'challenges.gui.challenge-description.required-level' | 'challenges.gui.challenge-description.required-money' | 'challenges.gui.challenge-description.required-experience' | and challenge.requiredItems, challenge.requiredBlocks or challenge.requiredEntities."
reward_text: "Reward string. | Defined in challenge.rewardText and challenge.repeatRewardText"
reward_other: "Reward other String. | Represents translation for: | 'challenges.gui.challenge-description.experience-reward' | 'challenges.gui.challenge-description.money-reward' | 'challenges.gui.challenge-description.not-repeatable'."
reward_items: "Reward Items. | List of items that will be rewarded defined in challenge.rewardItems and challenge.repeatRewardItems."
reward_commands: "Reward Commands. | List of commands that will be rewarded defined in challenge.rewardCommands and challenge.repeatRewardCommands."
level_status: "Status string. | Represents translation 'challenges.gui.level-description.completed'."
challenge_count: "Completed challenge count string. | Represents translation for 'challenges.gui.level-description.completed-challenges-of'"
unlock_message: "Unlock message string. | Defined in challenges Level object - challengeLevel.unlockMessage."
waiver_amount: "Shippable challenge count to unlock next level string. | Represents translation for 'challenges.gui.level-description.waver-amount'"
level_reward_text: "Reward string. | Defined in challengeLevel.rewardText"
level_reward_other: "Reward other String. | Represents translation for: | 'challenges.gui.level-description.experience-reward' | 'challenges.gui.level-description.money-reward'."
level_reward_items: "Reward Items. | List of items that will be rewarded defined in challengeLevel.rewardItems."
level_reward_commands: "Reward Commands. | List of commands that will be rewarded defined in challengeLevel.rewardCommands."
current-value: '|&6Current value: [value].'
level: |-
Level string.
Represents translation challenges.gui.challenge-description.level
status: |-
Status string.
Represents translation challenges.gui.challenge-description.completed
count: |-
Completion count string.
Represents translation for challenges.gui.challenge-description.completed-times
challenges.gui.challenge-description.completed-times-of
and challenges.gui.challenge-description.maxed-reached
description: |-
Description string.
Defined in challenges object - challenge.description.
warnings: |-
Warning string.
Represents translation for:
challenges.gui.challenge-description.warning-items-take
challenges.gui.challenge-description.objects-close-by
challenges.gui.challenge-description.warning-entities-kill
challenges.gui.challenge-description.warning-blocks-remove
environment: |-
Environment string.
Defined in challenges object - challenge.environment.
requirements: |-
Requirement string.
Represents translation for:
challenges.gui.challenge-description.required-level
challenges.gui.challenge-description.required-money
challenges.gui.challenge-description.required-experience
challenge.requiredItems'
challenge.requiredBlocks'
or challenge.requiredEntities.
reward_text: |-
Reward string.
Defined in challenge.rewardText and challenge.repeatRewardText
reward_other: |-
Reward other string.
Represents translation for:
challenges.gui.challenge-description.experience-reward
challenges.gui.challenge-description.money-reward
challenges.gui.challenge-description.not-repeatable
reward_items: |-
Reward items.
List of items that will be rewarded defined in challenge.rewardItems and challenge.repeatRewardItems.
reward_commands: |-
Reward commands.
List of commands that will be rewarded defined in challenge.rewardCommands and challenge.repeatRewardCommands.
level_status: |-
Status string.
Represents translation challenges.gui.level-description.completed
challenge_count: |-
Completed challenge count string.
Represents translation for challenges.gui.level-description.completed-challenges-of
unlock_message: |-
Unlock message string.
Defined in challenges Level object - challengeLevel.unlockMessage
waiver_amount: |-
Shippable challenge count to unlock next level string.
Represents translation for challenges.gui.level-description.waver-amount
level_reward_text: |-
Reward string.
Defined in challengeLevel.rewardText
level_reward_other: |-
Reward other string.
Represents translation for:
challenges.gui.level-description.experience-reward
challenges.gui.level-description.money-reward
level_reward_items: |-
Reward items.
List of items that will be rewarded defined in challengeLevel.rewardItems
level_reward_commands: |-
Reward commands.
List of commands that will be rewarded defined in challengeLevel.rewardCommands
current-value: |-
&6Current value: [value].
enabled: 'Active'
disabled: 'Disabled'
type:
island: '&aallows to require blocks or mobs around player'
inventory: '&aallows to require items in players inventory'
other: '&aallows to require things from other plugins/addons'
island: '&arequire blocks or mobs around player'
inventory: '&arequire items in the player"s inventory'
other: '&arequire things from other plugins/addons'
the-end: '- The End'
nether: '- Nether'
normal: '- Overworld'
@ -341,17 +449,17 @@ challenges:
reduce-by: "&cReduce completion count by [value]"
visibility:
visible: "All challenges are visible for everyone"
visible: "All challenges are visible to everyone"
hidden: "Only Deployed challenges are visible."
toggleable: "Allows to toggle if undeployed challenges should be displayed"
toggleable: "Toggle if undeployed challenges should be displayed"
challenge-description:
level: '&FLevel: [level]'
completed: '&BCompleted'
level: '&fLevel: [level]'
completed: '&bCompleted'
completed-times-of: 'Completed [donetimes] out of [maxtimes]'
maxed-reached: 'Completed [donetimes] out of [maxtimes]'
completed-times: 'Completed [donetimes]'
warning-items-take: '&cAll required items are taken when you complete this challenge!'
warning-items-take: '&cAll required items are taken from your inventory when you complete this challenge!'
objects-close-by: '&cAll required blocks and entities must be close to you on your island!'
warning-entities-kill: '&cAll required entities will be killed when you complete this challenge!'
warning-blocks-remove: '&cAll required blocks will be removed when you complete this challenge!'
@ -368,9 +476,9 @@ challenges:
required-entities: 'Required Entities:'
required-blocks: 'Required Blocks:'
level-description:
completed: '&BCompleted'
completed-challenges-of: '&3You have completed [number] of [max] challenges in this level.'
waver-amount: '&6Can skip [value] challenges to unlock next level.'
completed: '&bCompleted'
completed-challenges-of: '&3You have completed [number] out of [max] challenges in this level.'
waver-amount: '&6[value] challenges can be skipped to unlock next level.'
experience-reward: '&6Exp reward: [value]'
money-reward: '&6Money reward: $[value]'
reward-items: '&6Reward Items:'
@ -398,32 +506,32 @@ challenges:
prefix: "&2[SERVER]: "
admin:
number: "Write a number in chat and press enter to accept it and press enter."
unique-id: "Write object unique name and press enter."
challenge-name: "Write in chat display name for current challenge."
level-name: "Write in chat display name for current level."
number: "Write a number in the chat and press enter."
unique-id: "Write the object's unique id and press enter."
challenge-name: "Write the display name in the chat for the current challenge."
level-name: "Write the display name in chat for the current level."
titles:
# Title and subtitle my contain variable in [] that will be replaced with proper message from challenge object.
# Title and subtitle may contain variables in [] that will be replaced with a proper message from the challenge object.
# [friendlyName] will be replaced with challenge friendly name.
# [level] will be replaced with level friendly name.
# [rewardText] will be replaced with challenge reward text.
# [rewardText] will be replaced with the challenge reward text.
challenge-title: 'Successfully completed'
challenge-subtitle: '[friendlyName]'
# Title and subtitle my contain variable in [] that will be replaced with proper message from level object.
# Title and subtitle may contain variables in [] that will be replaced with a proper message from the level object.
# [friendlyName] will be replaced with level friendly name.
# [rewardText] will be replaced with level reward text.
# [rewardText] will be replaced with the level reward text.
level-title: 'Successfully completed'
level-subtitle: '[friendlyName]'
messages:
admin:
hit-things: 'Hit things to add them to the list of things required. Right click when done.'
hit-things: 'Click the things to add them to the list of required things. Right click when done.'
you-added: 'You added one [thing] to the challenge'
challenge-created: '[challenge]&r created!'
complete-wipe: '&cHope you have backups, as you just empty all Challenges Addon databases!'
complete-wipe: '&cHopefully you have backups, because you just erased all the Challenges Addon databases!'
challenge-wipe: '&cHope you have backups, as you just empty Challenges and their levels from databases!'
players-wipe: '&cHope you have backups, as you just empty player completed challenges from databases!'
challenge-wipe: '&cHopefully you have backups, because you just erased all the Challenges and their levels!'
players-wipe: '&cHopefully you have backups, because you just erase all the player completed challenges!'
completed: '&2You completed challenge [name] for [player]!'
already-completed: '&2This challenge was already completed!'
@ -432,7 +540,7 @@ challenges:
not-completed: '&2This challenge is not completed yet!'
migrate-start: '&2Start migrating challenges addon data.'
migrate-end: '&2Challenges addon data is updated to new format.'
migrate-end: '&2Challenges addon data updated to new format.'
migrate-not: '&2All data is valid.'
start-downloading: '&5Starting to download and import Challenges Library.'
@ -456,41 +564,43 @@ challenges:
unknown-challenge: '&cUnknown challenge'
unique-id: '&cUniqueID "[id]" is not valid.'
wrong-icon: '&cGiven material "[value]" is not valid and cannot be used as icon.'
not-valid-integer: '&cGiven integer "[value]" is not valid!|Value should be between [min] and [max].'
not-a-integer: '&cGiven value "[value]" is not integer!'
not-valid-integer: |-
&cGiven integer "[value]" is not valid!
Value should be between [min] and [max].
not-a-integer: '&cGiven value "[value]" is not an integer!'
not-deployed: '&cChallenge is not deployed!'
not-on-island: '&cYou must be on your island to do that!'
challenge-level-not-available: '&cYou have not unlocked level to complete this challenge.'
challenge-level-not-available: '&cYou have not unlocked the required level to complete this challenge.'
not-repeatable: '&cThis challenge is not repeatable!'
wrong-environment: '&cYou are in wrong environment!'
wrong-environment: '&cYou are in the wrong environment!'
not-enough-items: '&cYou do not have enough [items] to complete this challenge!'
not-close-enough: '&cYou must be standing within [number] blocks of all required items.'
you-still-need: '&cYou still need [amount] x [item]'
missing-addon: '&cCannot complete challenge. Required addon or plugin is missing.'
incorrect: '&cCannot complete challenge. Requirements are incorrect.'
missing-addon: '&cCannot complete challenge: Required addon or plugin is missing.'
incorrect: '&cCannot complete challenge: Requirements are incorrect.'
not-enough-money: '&cIt is necessary to have [value] on your account to complete the challenge.'
not-enough-experience: '&cIt is necessary to have [value] EXP to complete challenge.'
island-level: '&cYour island must be level [number] to complete this challenge!'
not-enough-experience: '&cIt is necessary to have [value] EXP to complete this challenge.'
island-level: '&cYour island must be level [number] or greater to complete this challenge!'
import-no-file: '&cCould not find challenges.yml file to import!'
no-load: '&cError: Could not load challenges.yml. [message]'
load-error: '&cError: Cannot load [value].'
no-rank: "&cYou do not have rank to do that."
cannot-remove-items: '&cSome items cannot be removed from inventory!'
exist-challenges-or-levels: '&cIn your world already exist challenges. Cannot proceed!'
no-rank: "&cYou do not have rank that is high enough to do that."
cannot-remove-items: '&cSome items cannot be removed from your inventory!'
exist-challenges-or-levels: '&cChallenges already exist in your world. Cannot proceed!'
defaults-file-exist: '&cdefaults.json already exists. Use overwrite mode to replace it!'
defaults-file-error: '&cThere was an error while creating defaults.json file! Check console!'
no-challenges: '&cChallenges are not implemented in current world!'
no-challenges-admin: '&cChallenges are not implemented in current world! You should use &5/[command] &cto adding them!'
missing-level: '&cChallenge Level [level] is not defined in database. It may case some errors!'
no-challenges: '&cChallenges are not implemented in this world yet!'
no-challenges-admin: '&cChallenges are not implemented in this world yet! Use &5/[command] &cto add them!'
missing-level: '&cChallenge Level [level] is not defined in the database. It may cause errors!'
missing-arguments: '&cCommand is missing arguments.'
no-multiple-permission: "&cYou do not have permission to complete challenge multiple times at once."
no-multiple-permission: "&cYou do not have permission to complete this challenge multiple times at once."
protection:
flags:
CHALLENGES_ISLAND_PROTECTION:
description: "&5&oToggle who can\n&5&ocomplete challenges"
name: "Challenges protection"
CHALLENGES_WORLD_PROTECTION:
description: "&5&oThis allows to enable/disable\n&5&orequirement for players to\n&5&obe on their island to\n&5&ocomplete a challenge."
description: "&5&oEnable/disable\n&5&orequirement for players to\n&5&obe on their island to\n&5&ocomplete a challenge."
name: "Challenges Island limitation"
hint: "No challenges outside island"
version: 11

View File

@ -1,345 +1,624 @@
###########################################################################################################
# Este es un archivo YML. Tenga cuidado al editar. Revisa tus ediciones en un verificador de YAML como #
# el de http://yaml-online-parser.appspot.com #
###########################################################################################################
meta:
authors:
- SrAcosta
---
challenges:
commands:
admin:
main:
parameters: ''
description: 'Comando de administrador principal. Abrir GUI.'
complete:
description: 'Marcar desafío completado'
parameters: '<player> <unique challenge name>'
create:
description: 'Abre el GUI que permite crear desafío..'
parameters: '<unique challenge name>'
surrounding:
description: 'Crea un desafío envolvente.'
parameters: '<challenge name>'
import:
description: 'Importar retos desde challenges.yml'
parameters: '<overwrite>'
reload:
description: 'Recargar retos de la base de datos'
parameters: ''
reset:
description: 'Restablecer el desafío a 0 veces / incompleto'
parameters: '<player> <unique challenge name>'
show:
description: 'Este método imprime en el chat todos los desafíos que existen en el mundo.'
parameters: ''
user:
description: 'Este método abre el GUI de los desafíos.'
parameters: ''
gui:
title:
admin:
gui-title: '&aDesafíos de Admin'
edit-challenge-title: '&aEditar desafio'
edit-level-title: '&aEditar nivel'
settings-title: '&aEditar configuracion'
choose-challenge-title: '&aElegir desafío'
choose-level-title: '&aElegir nivel'
choose-user-title: '&aElegir jugador'
manage-blocks: '&aAdministrar bloques'
manage-entities: '&aAdministrar Entidades'
confirm-title: '&aConfirmación'
manage-items: '&aAdministrar items'
manage-numbers: '&aTeclado numérico'
select-block: '&aSeleccionar bloque'
select-challenge: '&aSeleccione Desafío'
select-entity: '&aSelecione entidad'
toggle-environment: '&aModificar ambiente'
edit-text-fields: '&aEditar campos de texto'
challenges: '&aDesafios'
buttons:
admin:
complete: 'Completar los desafios del usuario'
reset: 'Reiniciar los desafios del usuario'
create-challenge: 'Agregar nuevo desafio'
create-level: 'Agregar nuevo nivel'
edit-challenge: 'Editar desafio'
edit-level: 'Editar nivel'
delete-challenge: 'Remover desafio'
delete-level: 'Remover nivel'
import: 'Importar desafios de ASkyblock'
backward: 'Importar desafios 0.3.0'
backward-player: 'Arreglar 0.3.0 PlayerData'
settings: 'Editar configuracion'
properties: 'Propiedades'
requirements: 'Requerimientos'
rewards: 'Recompensas'
challenges: 'Desafios'
type: 'Tipo de desafio'
deployment: 'Despliegue'
icon: 'Icono'
locked-icon: 'Icono de bloqueo'
description: 'Descripcion'
order: 'Orrden'
environment: 'Ambientet'
remove-on-complete: 'Eliminar después de la finalización'
name: 'Nombre amigable'
required-entities: 'Requiere entidades'
remove-entities: 'Remover entidades'
required-blocks: 'Requiere bloques'
remove-blocks: 'Remover bloques'
search-radius: 'Buscar radios'
required-permissions: 'Requiere Permisos'
required-items: 'Requiere Items'
remove-items: 'Remover items'
required-experience: 'Requiere experiencia'
remove-experience: 'Remover experiencia'
required-level: 'Requiere nivel de isla'
required-money: 'Requiere dinero'
remove-money: 'Remover dinero'
reward-text: 'Mensaje de recompensa'
reward-items: 'Items de recompensa'
reward-experience: 'Experiencia de recompensa'
reward-money: 'Dinero de recompensa'
reward-commands: 'Comandos de recompensa'
repeatable: 'Repetible'
repeat-count: 'Tiempos máximos'
repeat-reward-text: 'Repetir recompensa de mensaje'
repeat-reward-items: 'Repetir recompensa de items'
repeat-reward-experience: 'Repetir la experiencia de recompensa'
repeat-reward-money: 'Repetir recompensa dinero'
repeat-reward-commands: 'Repetir los comandos de recompensa'
waiver-amount: 'Cantidad de exención'
add-challenge: 'Añadir desafío'
remove-challenge: 'Eliminar desafío'
reset-on-new: 'Restablecer en la isla nueva'
broadcast: 'Emitir completacion'
remove-completed: 'Eliminar después de completar'
glow: 'Resplandor cuando se completa'
free-at-top: 'Los desafíos libres primero'
line-length: 'Longitud de la línea del lore'
toggle-user-list: 'Lista de usuarios'
remove-selected: 'Eliminar selección'
add: 'Agregar'
show-eggs: 'Cambiar modo de vista'
accept: 'Aceptar'
decline: 'Denegar'
save: 'Guardar'
cancel: 'Cancelar'
input: 'Input'
value: 'Valor'
set: '='
increase: '+'
reduce: '-'
multiply: '*'
clear: 'Limpiar'
remove-empty: 'Remover vacio'
number: '[number]'
level-lore: 'Descripcion de nivel'
challenge-lore: 'Descripcion de desafio'
gui-view-mode: 'Mostrar todos los modos de juego'
gui-mode: 'Gui simple de desafios'
history-store: 'Historial de desafios'
history-lifespan: 'Historia LifeSpan'
island-store: 'Tienda por isla'
default-locked-icon: 'Icono de nivel bloqueado'
next: 'Siguiente'
previous: 'Anterior'
return: 'Regreso'
descriptions:
admin:
save: 'Guardar y volver a la anterior GUI.'
cancel: 'Regresar a la anterior GUI. Los cambios no serán guardados.'
input: 'Abrir entrada de campo de texto.'
set: 'Configuración de la operación. Al hacer clic en los números cambiará el valor al número seleccionado.'
increase: 'Aumente la operación. Al hacer clic en los números aumentará el valor por el número seleccionado.'
reduce: 'Reducir la operación. Al hacer clic en los números se reducirá el valor por el número seleccionado.'
multiply: 'Multiplicar la operación. Al hacer clic en los números se multiplicará el valor por el número seleccionado.'
import: 'Permite importar Desafíos de ASkyblock. | Al hacer click con el botón derecho, habilita / deshabilita el modo de sobrescritura.'
complete: 'Permite completar desafíos para cualquier usuario. | El usuario no obtendrá una recompensa por completar.'
reset: 'Permite restablecer los desafíos completados del usuario. | El click derecho habilita / inhabilita la función Restablecer todas.'
create-challenge: 'Permite agregar un nuevo desafío. | Por defecto estará en la lista de desafíos gratis.'
create-level: 'Permite agregar nuevo nivel.'
edit-challenge: 'Permite editar cualquier configuración de desafío.'
edit-level: 'Permite editar cualquier configuración de nivel.'
delete-challenge: 'Permite eliminar cualquier Desafío.'
delete-level: 'Permite eliminar cualquier nivel.'
backward: 'Permite importar desafíos desde 0.3.0 y por debajo de la versión adicional.'
backward-player: 'Permite corregir PlayerData dañado desde la versión 0.3.0|&2ÚSELO SOLO SI ES NECESARIO|&2PUEDE NO TRABAJAR EN TODAS LAS SITUACIONES'
settings: 'Permite cambiar la configuración del addon.'
properties: 'Permite cambiar propiedades generales'
requirements: 'Permite gestionar requerimientos'
rewards: 'Permite gestionar recompensas'
challenges: 'Permite gestionar retos de nivel (add / remove).'
deployment: 'Permite a los usuarios completar (view) desafio.'
icon-challenge: 'Icono que se mostrará en los paneles GUI para este desafío.'
icon-level: 'Icono que se mostrará en los paneles GUI para este nivel.'
locked-icon: 'Icono que se mostrará en los paneles de la GUI si el nivel está bloqueado.'
description: 'Permite editar la descripción.'
order: 'Permite cambiar el número de pedido.'
environment: 'Permite cambiar el ambiente donde opera el desafío.'
type: 'Permite cambiar el tipo de desafío. Cada tipo tiene sus propios requisitos.'
remove-on-complete: 'Permite eliminar el desafío de la GUI del jugador una vez completado.'
name-challenge: 'ermite cambiar el nombre de visualización del desafío.'
name-level: 'Permite cambiar el nombre de visualización de nivel.'
required-entities: 'Permite a añadir / editar / eliminar Entidades requeridas.|Entities:|'
remove-entities: 'Permite eliminar (kill) Entidades en la finalización del desafío.'
required-blocks: 'Permite agregar / editar / eliminar bloques requeridos.|Blocks:|'
remove-blocks: 'Permite eliminar (reemplazar con aire) bloques al completar el desafío.'
search-radius: 'Radio alrededor de la ubicación del jugador donde se buscarán las entidades y bloques requeridos.'
required-permissions: 'Permisos requeridos para que el jugador pueda completar el desafío.|Permission:'
required-items: 'Elementos requeridos en el inventario del jugador.|Items:'
remove-items: 'Permite eliminar objetos del inventario del jugador después de completar el desafío.'
required-experience: 'Permite definir la experiencia requerida para que el usuario complete el desafío.'
remove-experience: 'Permite eliminar la experiencia requerida.'
required-level: 'Permite definir el nivel de isla requerido para este desafío.|&cRequires Level addon.'
required-money: 'Permite definir el dinero requerido en la cuenta del jugador.|&cRequires Vault and Economy plugin.'
remove-money: 'Permite eliminar el dinero requerido de la cuenta del jugador.|&cRequires Vault and Economy plugin.'
reward-text: 'Permite cambiar el mensaje que se enviará al jugador después de completar los desafíos.'
reward-items: 'Permite cambiar los elementos de recompensa por primera vez.|Items:'
reward-experience: 'Permite cambiar la recompensa de experiencia por primera vez.'
reward-money: 'Permite cambiar la recompensa de dinero por primera vez.|&cRequires Vault and Economy plugin.'
reward-commands: 'Permite definir los comandos de recompensa que se llamarán después de que se completen por primera vez. | *** Agregar "[SELF]" en el inicio significa que el jugador ejecutará el comando, es decir, "/ kill" | *** String "[player]" se reemplazará con el nombre del jugador, por ejemplo. "/ kill [jugador]" se transformará en "/ kill BONNe1704"|Commands:'
repeatable: 'Permite definir si el desafío es repetible o no.'
repeat-count: 'Permite definir el recuento máximo de repeticiones. Si el valor se establece en 0 o menos, entonces no hay limitaciones.'
repeat-reward-text: 'Permite cambiar el mensaje que se enviará al jugador después de completar el desafío repetidamente.'
repeat-reward-items: 'Permite cambiar los elementos de recompensa de finalización repetida.|Items:'
repeat-reward-experience: 'Permite cambiar la recompensa de experiencia de finalización repetida.'
repeat-reward-money: 'Permite cambiar el dinero de recompensa de finalización repetida.|&cRequires Vault and Economy plugin.'
repeat-reward-commands: 'Permite definir los comandos de recompensa que se llamarán después de completar el desafío repetidamente. | *** Agregar "[SELF]" en el inicio significa que el jugador ejecutará el comando, es decir, "/ kill" | *** String "[player]" se reemplazará con el nombre del jugador, por ejemplo. "/ kill [jugador]" se transformará en "/ kill BONNe1704"|Commands:'
waiver-amount: 'Permite establecer cuántos desafíos pueden dejarse para deshacer para desbloquear el siguiente nivel.'
reward-text-level: 'Permite cambiar el mensaje que se enviará al jugador después de completar todos los desafíos en el nivel.'
add-challenge: 'Permite agregar desafío existente al nivel actual.'
remove-challenge: 'Permite eliminar cualquier desafío del nivel actual.'
reset-on-new: 'Habilita / deshabilita la opción, que restablece todos los desafíos del jugador si el jugador reinicia la isla, deja la isla o fue expulsado.'
broadcast: 'Habilita / deshabilita la transmisión a los jugadores en línea cuando se completa el primer desafío.'
remove-completed: 'Habilita / deshabilita los desafíos de ocultación que se completan y no se pueden repetir.'
glow: 'Habilita / deshabilita el efecto brillante para los desafíos completados.'
free-at-top: 'Permite cambiar la ubicación de los desafíos libres. Cierto significa que los desafíos serán los primeros, de lo contrario serán los últimos.'
line-length: 'Permite modificar la longitud máxima de la línea en el cuadro de conocimientos. No afectará a los objetos almacenados.'
toggle-user-list: 'Cambiar a la lista de jugadores diferentes.'
mode-online: 'Jugadores que actualmente están en línea.'
mode-in-world: 'Jugadores que está en el mundo de GameMode.'
mode-with-island: 'Jugadores que tiene isla en GameMode.'
selected: 'Seleccionado'
remove-selected: 'Eliminar elementos seleccionados. | Puede seleccionar elementos con el botón derecho del ratón.'
show-eggs: 'Cambia la vista de entidad entre el modo Huevo o el modo Cabeza.'
level-lore: 'Permite modificar qué elementos de la descripción de nivel deben ser visibles.'
challenge-lore: 'Permite modificar qué elementos de la descripción de desafío deberían ser visibles.'
gui-view-mode: 'Permite establecer si / desafíos GUI debe mostrar GameModes o desafíos en el mundo de los jugadores.'
history-store: 'Permite habilitar / deshabilitar el almacenamiento del historial de desafíos.'
history-lifespan: 'Permite modificar cuántos días se guardarán los datos históricos. | 0 significa para siempre.'
island-store: 'Permite activar / desactivar cadenas de datos de desafíos por isla. Esto significa que los desafíos serán los mismos en todo el equipo, si esto está habilitado. NO convertirá los datos al hacer click. EL PROGRESO SE PERDERÁ.'
default-locked-icon: 'Permite cambiar el ícono de nivel bloqueado predeterminado. | Esta opción puede ser sobrescrita por cada nivel.'
gui-mode: 'Permite habilitar / deshabilitar la GUI de desafíos individuales. |&2Requiere reinicio del servidor.
'
current-value: '|&6Valor actual: [value].'
enabled: 'Activo'
disabled: 'Desactivado'
type:
island: '- Tipo de isla: | (Permite requerir bloques o mobs alrededor del jugador).'
inventory: '- Tipo de inventario: | (permite requerir objetos en el inventario de jugadores)'
other: '- Otro tipo: | (permite requerir cosas de otros complementos / complementos)'
the-end: '- El End'
nether: '- Nether'
normal: '- Sobre mundo'
entity: '- [entity] : [count]'
block: '- [block] : [count]'
permission: '- [permission]'
item: '- [count] x [item]'
item-meta: ' ([meta])'
item-enchant: ' - [enchant] [level]'
command: '- [command]'
level-unlocked: 'Click para ver [level] desafios!'
level-locked: 'Completa [count] mas [level] desafios para desbloquear el siguiente nivel!'
challenge-description:
level: '&FNivel: [level]'
completed: '&BCompletadp'
completed-times-of: 'Completado [donetimes] de [maxtimes]'
maxed-reached: 'Completado [donetimes] de [maxtimes]'
completed-times: 'Completado [donetimes]'
warning-items-take: '&cTodos los elementos necesarios se toman cuando completa este desafío!'
objects-close-by: '&cTodos los bloques y entidades requeridos deben estar cerca de usted en su isla!'
warning-entities-kill: '&cTodas las entidades requeridas serán eliminadas cuando completes este desafío!'
warning-blocks-remove: '&cTodos los bloques requeridos serán eliminados cuando completes este desafío!'
not-repeatable: '&cEste reto no es repetible!'
experience-reward: '&6Recompensa de XP: [value]'
money-reward: '&6Recompensa de dinero: $[value]'
required-experience: '&6Requiere XP: [value]'
required-money: '&6Requiere Dinero: $[value]'
required-island-level: '&6Nivel de isla requerido: [value]'
environment: 'Entornos Requeridos:'
reward-items: '&6Artículos de recompensa:'
reward-commands: '&6Comandos de recompensa:'
required-items: 'Objetos requeridos:'
required-entities: 'Entidades Requeridas:'
required-blocks: 'Bloques requeridos:'
level-description:
completed: '&BCompletado'
completed-challenges-of: '&3Haz completado [number] de [max] desafios en este nivel.'
waver-amount: '&6Puede saltar [value] desafíos para desbloquear el siguiente nivel.'
experience-reward: '&6Recompensa de XP: [value]'
money-reward: '&6Recompensa de dinero: $[value]'
reward-items: '&6Artículos de recompensa:'
reward-commands: '&6Comandos de recompensa:'
questions:
prefix: "&2[SERVER]: "
admin:
number: "Write a number in chat and press enter to accept it and press enter."
unique-id: "Write object unique name and press enter."
challenge-name: "Write in chat display name for current challenge."
level-name: "Write in chat display name for current level."
messages:
admin:
hit-things: 'Golpea cosas para agregarlas a la lista de cosas requeridas. Haga click derecho cuando haya terminado.'
you-added: 'Has añadido uno [thing] al desafio'
challenge-created: '[challenge] creado!'
you-completed-challenge: '&2Completaste el [value] desafio!'
you-repeated-challenge: '&2Repetiste el [value] desafio!'
you-completed-level: '&2Completaste el [value] nivel!'
name-has-completed-challenge: '&5[name] ha completado el [value] desafio!'
name-has-completed-level: '&5[name] ha completado el [value] nivel!'
import-levels: 'Empezar a importar niveles'
import-challenges: 'Empezar a importar desafios'
no-levels: 'Advertencia: No hay niveles definidos en challenges.yml'
import-number: 'Importado [number] desafios'
load-skipping: '"[value]" ya existe - saltando'
load-overwriting: 'Sobrescribiendo "[value]"'
load-add: 'Añadiendo nuevo objeto: [value]'
errors:
no-name: '&cFalta el nombre del desafío'
unknown-challenge: '&cDesafío desconocido'
unique-id: '&cIdentificación única "[id]" no es valida.'
wrong-icon: '&cMaterial dado "[value]" no es válido y no puede ser usado como icono.'
not-valid-integer: '&cEntero dado "[value]" no es válido! | El valor debe estar entre [min] y [max].'
not-a-integer: '&cValor dado "[value]" no es entero!'
not-deployed: '&cEl desafío no está desplegado!'
not-on-island: '&cDebes estar en tu isla para hacer eso!'
challenge-level-not-available: '&cNo has desbloqueado el nivel para completar este desafío.e.'
not-repeatable: '&cEste reto no es repetible.!'
wrong-environment: '&cEstás en el entorno incorrecto!'
not-enough-items: '&cNo tienes [ítems] suficientes para completar este desafío! !'
not-close-enough: '&cDebes estar dentro de los bloques [number] de todos los elementos requeridos.'
you-still-need: '&cUsted todavía necesita [amount] x [item]'
missing-addon: '&cNo puedo completar el desafío. Falta el addon o plugin requerido'
incorrect: '&cNo se pudo completar el desafío. Los requisitos son incorrectos.'
not-enough-money: '&cEs necesario tener [value] en su cuenta para completar el desafío.'
not-enough-experience: '&cEs necesario tener [value] EXP para completar este desafio.'
island-level: '&cTu isla debe ser de nivel [number] para completar este desafío!'
import-no-file: '&cNo se puede encontrar el archivo challenge.yml para importar'
no-load: '&cError: No se pudieron cargar challenge.yml. [message]'
load-error: '&cError: No se pudo cargar [value].'
no-rank: "&cNo tienes rango para hacer eso."
commands:
admin:
create:
description: Abre el GUI que permite crear desafío..
parameters: "<unique challenge name>"
main:
description: Comando de administrador principal. Abrir GUI.
surrounding:
description: Crea un desafío envolvente.
parameters: "<challenge name>"
import:
parameters: "[overwrite]"
description: |-
Importar desafíos desde challenge.yml
La sobrescritura de parámetros significa que se sobrescribirán los desafíos o niveles con la misma ID.
defaults-generate:
parameters: "[overwrite] - permite sobrescribir el archivo existente."
description: Exportar los desafíos existentes al archivo default.json.
complete:
parameters: "<player> <challange_id>"
description: Completar un desafío para un jugador.
reset:
parameters: "<player> <challange_id>"
description: Restablecer un desafío para un jugador. Si "challenge_id" se
establece en "all", restableceran todos los desafíos.
defaults-import:
description: Importar los desafíos predeterminados.
reload:
description: |-
Recargar desafíos desde la base de datos
El parámetro hard significa que el addon restablecerá la conexión a la base de datos.
parameters: "[hard]"
defaults:
parameters: "[command]"
description: Muestra subcomandos para importar / exportar los desafíos predeterminados.
migrate:
description: Migrar los datos actuales de los desafíos del mundo del juego
al formato de almacenamiento 0.8.0.
show:
description: Imprime todos los desafíos en el chat que existen en este mundo.
user:
description: Este método abre el GUI de los desafíos.
complete:
parameters: "<challenge_id> [count]"
description: Completa el desafío.
main:
description: Abrir GUI de Desafíos.
errors:
load-error: "&cError: No se pudo cargar [value]."
no-name: "&cFalta el nombre del desafío"
unknown-challenge: "&cDesafío desconocido"
unique-id: '&cLa UniqueID "[id]" no es valida.'
wrong-icon: '&cEl material dado "[value]" no es válido y no puede ser usado como
icono.'
not-deployed: "&c¡El desafío no está desplegado!"
not-on-island: "&c¡Debes estar en tu isla para hacer eso!"
not-repeatable: "&c¡Este reto no es repetible!"
not-enough-items: "&c¡No tienes [ítems] suficientes para completar este desafío!"
not-close-enough: "&cYou must be standing within [number] blocks of all required
items."
you-still-need: "&cTodavía necesitas [amount] x [item]"
not-enough-money: "&cEs necesario tener [value] en tu cuenta para completar el
desafío."
import-no-file: "&c¡No se puede encontrar el archivo challenge.yml para importar!"
no-load: "&cError: No se pudo cargar challenge.yml. [message]"
defaults-file-exist: "&cdefaults.json ya existe. ¡Utiliza el modo de sobrescritura
para reemplazarlo!"
defaults-file-error: "&c¡Se produjo un error al crear el archivo defaults.json!
¡Compruebe la consola!"
missing-arguments: "&cFaltan argumentos de comando."
wrong-environment: "&c¡Estás en el entorno equivocado!"
missing-addon: "&cNo se puede completar el desafío: falta un addon o plugin requerido."
exist-challenges-or-levels: "&cLos desafíos ya existen en tu mundo. ¡No se puede
proceder!"
no-challenges: "&c¡Los desafíos aún no se han implementado en este mundo!"
no-challenges-admin: "&c¡Los desafíos aún no se han implementado en este mundo!
¡Usa &5/[command] &cpara agregarlos!"
missing-level: "&cEl nivel de desafío [level] no está definido en la base de datos.
¡Puede causar errores!"
no-multiple-permission: "&cNo tienes permiso para completar este desafío varias
veces a la vez."
not-a-integer: '&c¡El valor dado "[value]" no es entero!'
challenge-level-not-available: "&cNo has desbloqueado el nivel requerido para
completar este desafío."
incorrect: "&cNo se puede completar el desafío: los requisitos son incorrectos."
not-enough-experience: "&cEs necesario tener [value] EXP para completar este desafío."
island-level: "&c¡Tu isla debe ser de nivel [number] o mayor para completar este
desafío!"
no-rank: "&cNo tienes un rango lo suficientemente alto como para hacer eso."
cannot-remove-items: "&c¡Algunos items no se pueden eliminar de tu inventario!"
not-valid-integer: |-
&cEl número entero "[value]" no es válido.
El valor debe estar entre [min] y [max].
gui:
buttons:
admin:
accept: Aceptar
add: Agregar
backward: Importar desafios 0.3.0
backward-player: Arreglar 0.3.0 PlayerData
cancel: Cancelar
clear: Limpiar
create-level: Agregar nuevo nivel
decline: Denegar
deployment: Despliegue
edit-level: Editar nivel
history-lifespan: Historia LifeSpan
icon: Icono
increase: "+"
input: Input
line-length: Longitud de la línea del lore
multiply: "*"
number: "[number]"
properties: Propiedades
reduce: "-"
remove-empty: Remover vacio
remove-experience: Remover experiencia
remove-money: Remover dinero
repeatable: Repetible
repeat-count: Tiempos máximos
requirements: Requerimientos
reward-commands: Comandos de recompensa
reward-experience: Experiencia de recompensa
reward-items: Items de recompensa
reward-money: Dinero de recompensa
rewards: Recompensas
reward-text: Mensaje de recompensa
save: Guardar
set: "="
value: Valor
complete: Completar los desafíos del usuario
reset: Reiniciar los desafíos del usuario
create-challenge: Agregar nuevo desafío
edit-challenge: Editar desafío
delete-challenge: Eliminar desafio
delete-level: Eliminar nivel
challenges: Desafíos
locked-icon: Icono bloqueado
description: Descripción
order: Orden
environment: Ambiente
remove-on-complete: Remover al finalizar
required-experience: Experiencia requerida
required-level: Nivel de isla requerido
required-money: Dinero requerido
repeat-reward-text: Repetir mensaje de recompensa
repeat-reward-items: Repetir items de recompensa
repeat-reward-experience: Repetir experiencia de recompensa
repeat-reward-money: Repetir dinero de recompensa
repeat-reward-commands: Repetir comandos de recompensa
remove-completed: Remover al completar
glow: Brillar (glow) al completar
free-at-top: Desafíos libres primero
input-mode: Cambiar modo de entrada (input)
type:
island: "&6Tipo de isla"
inventory: "&6Tipo de inventario"
other: "&6Otro tipo"
required-items: Items requeridos
remove-items: Eliminar items
gui-mode: GUI de Desafíos individuales
complete-wipe: Limpiar bases de datos de addon
challenge-wipe: Limpiar base de datos de desafíos
players-wipe: Limpiar base de datos del usuario
title-enable: Título de finalización
library: Biblioteca web
download: Descargar bibliotecas
import: Importar desafíos ASkyblock
settings: Editar configuración
name: Nombre amigable
required-entities: Entidades requeridas
remove-entities: Matar entidades
required-blocks: Bloques requeridos
remove-blocks: Eliminar bloques
search-radius: Radio de búsqueda
required-permissions: Permisos requeridos
waiver-amount: Cantidad de exención
add-challenge: Añadir desafío
remove-challenge: Eliminar desafío
reset-on-new: Restablecer en nueva isla
broadcast: Difusión completada
visibility-mode: Modo de visibilidad de desafío
toggle-user-list: Lista de usuarios
remove-selected: Eliminar selección
show-eggs: Cambiar modo de vista
level-lore: Descripción del nivel
challenge-lore: Descripción del desafío
gui-view-mode: Mostrar todos los modos de juego
history-store: Desafíos de la historia
island-store: Almacenar por isla
default-locked-icon: Icono de nivel bloqueado
title-showtime: Tiempo de presentación del título
default-import: Importar desafíos predeterminados
default-export: Exportar desafíos existentes
next: Siguiente
previous: Anterior
return: Volver
value: Completar
increase: Incrementar
reduce: Reducir
challenge-description:
completed-times: Completado [donetimes]
completed-times-of: Completado [donetimes] de [maxtimes]
maxed-reached: Completado [donetimes] de [maxtimes]
required-blocks: 'Bloques requeridos:'
required-island-level: "&6Nivel de isla requerido: [value]"
reward-commands: "&6Comandos de recompensa:"
objects-close-by: "&c¡Todos los bloques y entidades requeridos deben estar cerca
de ti en tu isla!"
warning-entities-kill: "&c¡Todas las entidades requeridas serán eliminadas cuando
completes este desafío!"
warning-blocks-remove: "&c¡Todos los bloques requeridos serán eliminados cuando
completes este desafío!"
not-repeatable: "&c¡Este desafío no es repetible!"
experience-reward: "&6Recompensa de EXP: [value]"
money-reward: "&6Recompensa de dinero: [value]$"
required-experience: "&6EXP requerida: [value]"
required-money: "&6Dinero requerido: [value]$"
environment: 'Entornos requeridos:'
reward-items: "&6Items de recompensa:"
required-items: 'Items requeridos:'
required-entities: 'Entidades requeridas:'
level: "&fNivel: [level]"
completed: "&bCompletado"
warning-items-take: "&c¡Todos los items necesarios son tomados de tu inventario
cuando se completa este desafío!"
descriptions:
admin:
backward: Permite importar desafíos desde 0.3.0 y por debajo de la versión
adicional.
backward-player: Permite corregir PlayerData dañado desde la versión 0.3.0|&2ÚSELO
SOLO SI ES NECESARIO|&2PUEDE NO TRABAJAR EN TODAS LAS SITUACIONES
deployment: Permite a los usuarios completar (view) desafio.
icon-challenge: Icono que se mostrará en los paneles GUI para este desafío.
icon-level: Icono que se mostrará en los paneles GUI para este nivel.
input: Abrir entrada de campo de texto.
selected: Seleccionado
remove-completed: Habilitar / deshabilitar la ocultación de desafíos que se
completan y no se pueden repetir.
toggle-user-list: Cambiar a una lista de jugadores diferente.
show-eggs: Cambiar la vista de entidad entre el modo Huevo o el modo Cabeza.
click-to-edit: "&4Haga clic aquí para editar la entrada (input)."
input-mode: Cambiar entre los modos de entrada (input) de chat y yunque.
library-author: por &e[author]
library-lang: "&aIdioma: [lang]"
library-gamemode: "&aPrimariamente para [gamemode]"
edit-challenge: Editar configuración del desafío.
description: Editar descripción.
name-challenge: Cambiar el nombre del desafío.
name-level: Cambiar el nombre del nivel.
remove-entities: Eliminar (kill) entidades al completar el desafío.
remove-blocks: Eliminar (reemplazar con aire) bloques al completar el desafío.
reward-text: Cambiar el mensaje que se enviará al jugador después de completar
los desafíos.
repeatable: Definir si el desafío es repetible o no.
free-at-top: Cambiar la ubicación de los desafíos gratuitos. Verdadero (true)
significa que los desafíos serán los primeros, de lo contrario serán los
últimos.
line-length: Modificar la longitud máxima de la línea en el "Lore box". No
afectará a los objetos almacenados.
level-lore: Modificar qué elementos de descripción de nivel deben estar visibles.
challenge-lore: Modificar qué elementos de descripción de desafío deben estar
visibles.
gui-view-mode: Establecer si "/challenges GUI" debe mostrar Modos de Juego
o desafíos en el mundo del jugador.
default-export: Exportar los desafíos existentes al archivo defaults.json.
complete-wipe: Limpiar completamente todas las bases de datos del addon de
desafíos. ¡Incluye datos del jugador!
challenge-wipe: "¡Los desafíos y sus bases de datos de nivel han sido completamente
limpiados!"
players-wipe: La base de datos del jugador se ha limpiado completamente!
library: Abrir GUI que muestre todas las bibliotecas públicas de desafíos
disponibles.
library-version: "&9Hecho en Challenges [versión]"
cancel: Volver a la GUI anterior. Los cambios no se guardarán.
challenges: Gestionar nivel de desafíos (agregar / eliminar).
remove-on-complete: Eliminar un desafío de la GUI del jugador después de completarlo.
remove-items: Retirar los items del inventario del jugador después de completar
el desafío.
required-experience: Definir la experiencia requerida para que un usuario
complete el desafío.
remove-experience: Eliminar experiencia requerida.
reward-experience: Cambiar la recompensa de experiencia por completar por
primera vez
repeat-reward-text: Cambiar el mensaje que se enviará al jugador después de
completar un desafío repetido.
repeat-reward-experience: Cambiar la recompensa de experiencia por completar
repetido.
add-challenge: Agregar un desafío existente al nivel actual.
remove-challenge: Eliminar un desafío del nivel actual.
reset-on-new: Habilitar / deshabilitar el reinicio de todos los desafíos del
jugador si se reinicia, se va o es expulsado de una isla.
broadcast: Habilitar / deshabilitar la transmisión sobre la primera vez que
se completa el desafío para todos los jugadores en línea.
glow: Habilitar / deshabilitar el efecto brillante para los desafíos completados.
edit-text-line: "&6¡Editar mensaje de texto!"
add-text-line: "&6¡Agregar un nuevo mensaje de texto!"
title-enable: Habilitar / deshabilitar el mensaje de título que se mostrará
a los jugadores cuando completen un desafío.
title-showtime: Modificar cuánto tiempo serán visibles los mensajes de título
para el jugador.
import: |-
Importar desafíos ASkyblock.
Al hacer clic derecho, habilitar/deshabilita el modo de sobrescritura.
Coloque challenges.yml dentro de la carpeta ./BentoBox/addons/Challenges.
complete: |-
Completar desafíos para cualquier usuario.
El usuario no recibirá ninguna recompensa por completarlo.
required-items: |-
items necesarios en el inventario del jugador.
Items:
required-level: |-
Definir el nivel de isla requerido para este desafío.
&cRequiere el addon Level.
required-money: |-
Definir el dinero requerido en la cuenta del jugador.
&cRequiere Vault y el plugin de Economy.
remove-money: |-
Retirar el dinero requerido de la cuenta del jugador.
&cRequiere Vault y el plugin de Economy.
reward-items: |-
Cambiar los items de recompensa de finalización por primera vez.
Items:
reward-money: |-
Cambiar el dinero de recompensa de finalización por primera vez.
&cRequiere el complemento Vault and Economy.
reward-commands: |-
Definir los comandos de recompensa que se invocarán una vez que se completen por primera vez.
*** Agregar "[SELF]" al comienzo significa que el comando será ejecutado por el jugador, por ejemplo, "/ kill"
*** La cadena "[player]" se reemplazará con el nombre del jugador, por ejemplo, "/ kill [player]" se transformará en "/ kill BONNe1704"
Comandos:
repeat-reward-items: |-
Cambiar los items de recompensa de finalización repetida.
Items:
repeat-reward-money: |-
Cambiar la recompensa de dinero por finalización repetida.
&cRequiere Vault y el plugin Economy.
repeat-reward-commands: |-
Definir los comandos de recompensa que se ejecutarán después de completar el desafío repetidamente.
*** Agregar "[SELF]" al comienzo significa que el comando será ejecutado por el jugador, por ejemplo, "/ kill"
*** La cadena "[player]" se reemplazará con el nombre del jugador, por ejemplo, "/ kill [player]" se transformará en "/ kill BONNe1704"
Comandos:
history-lifespan: |-
Modificar cuántos días deben almacenarse los datos del historial.
0 significa para siempre.
island-store: |-
Habilitar/deshabilitar el almacenamiento de datos de desafíos por isla. Esto significa que los desafíos serán los mismos para todo el equipo si está habilitado.
&cNO convertirá datos al hacer clic. EL PROGRESO SE PERDERÁ.
default-locked-icon: |-
Cambiar el icono de nivel bloqueado predeterminado.
Esta opción puede ser sobrescrita por cada nivel.
gui-mode: |-
Habilitar / deshabilitar GUI de desafíos únicos.
&2Requiere reiniciar el servidor.
download: |-
Actualizar manualmente las bibliotecas de desafíos disponibles.
Haz clic derecho para habilitar la limpieza de caché.
lore:
level: |-
Cadena de nivel.
Representa la traducción challenges.gui.challenge-description.level
status: |-
Cadena de estado.
Representa la traducción challenges.gui.challenge-description.completed
count: |-
Cadena de contador de finalizado/completado.
Representa la traducción de challenges.gui.challenge-description.completed-times challenges.gui.challenge-description.completed-times-of and challenges.gui.challenge-description.maxed-reached
description: |-
Cadena de descripción.
Definido en el objeto de desafíos - challenge.description.
warnings: |-
Cadena de advertencia.
Representa la traducción para:
challenges.gui.challenge-description.warning-items-take challenges.gui.challenge-description.objects-close-by challenges.gui.challenge-description.warning-entities-kill challenges.gui.challenge-description.warning-blocks-remove
environment: |-
Cadena de entorno.
Definido en el objeto de desafíos: challenge.environment.
requirements: |-
Cadena de requisitos.
Representa la traducción para:
challenges.gui.challenge-description.required-level challenges.gui.challenge-description.required-money challenges.gui.challenge-description.required-experience challenge.requiredItems' challenge.requiredBlocks' o challenge.requiredEntities.
reward_text: |-
Cadena de recompensa.
Definido en challenge.rewardText y challenge.repeatRewardText
reward_other: |-
Cadena de otra recompensa.
Representa la traducción para:
challenges.gui.challenge-description.experience-reward challenges.gui.challenge-description.money-reward challenges.gui.challenge-description.not-repeatable
reward_items: |-
Items de recompensa.
Lista de elementos que se recompensarán definidos en challenge.rewardItems y challenge.repeatRewardItems.
reward_commands: |-
Comandos de recompensa.
Lista de comandos que serán recompensados definidos en challenge.rewardCommands y challenge.repeatRewardCommands.
level_status: |-
Cadena de estado.
Representa la traducción challenges.gui.level-description.completed
challenge_count: |-
Cadena de contador de desafíos completados.
Representa la traducción de challenges.gui.level-description.completed-challenges-of
unlock_message: |-
Cadena de mensaje desbloqueado.
Definido en Nivel de objeto de desafíos - challengeLevel.unlockMessage
waiver_amount: |-
Cadena de contador de desafíos enviables para desbloquear el siguiente nivel.
Representa la traducción de challenges.gui.level-description.waver-amount
level_reward_text: |-
Cadena de recompensa.
Definido en challengeLevel.rewardText
level_reward_other: |-
Cadena de otra recompensa.
Representa la traducción para:
challenges.gui.level-description.experience-reward challenges.gui.level-description.money-reward
level_reward_items: |-
Items de recompensa.
Lista de elementos que se recompensarán definidos en challengeLevel.rewardItems
level_reward_commands: |-
Comandos de recompensa.
Lista de comandos que serán recompensados definidos en challengeLevel.rewardCommands
download-disabled: El descargador de datos de GitHub está deshabilitado en
BentoBox. ¡Sin él, no puedes usar Bibliotecas!
create-level: Añadir nuevo nivel.
edit-level: Editar configuración de nivel.
delete-challenge: Eliminar un desafío.
delete-level: Eliminar un nivel.
settings: Cambiar ajustes.
properties: Cambiar propiedades generales
requirements: Administrar requisitos
rewards: Administrar recompensas
order: Cambiar número de orden.
environment: Cambiar el entorno del desafío.
search-radius: Radio alrededor de la ubicación del jugador donde se buscarán
las entidades y los bloques necesarios.
history-store: Habilitar / deshabilitar el almacenamiento del historial de
desafíos.
default-import: Importar desafíos predeterminados.
save: Guardar y volver a la GUI anterior.
set: Establecer operación. Al hacer clic en los números cambiará el valor
al número seleccionado.
increase: Aumentar la operación. Al hacer clic en los números, aumentará el
valor en el número seleccionado.
reduce: Reduce la operación. Al hacer clic en los números se reducirá el valor
en el número seleccionado.
multiply: Multiplicar la operación. Al hacer clic en los números, se multiplicará
el valor por el número seleccionado.
locked-icon: Icono que se mostrará en los paneles de la GUI si el nivel está
bloqueado.
repeat-count: Definir recuento de repetición máxima. Si el valor se establece
en 0, no hay limitaciones.
waiver-amount: Establece la cantidad de desafíos que un jugador puede dejar
fuera para desbloquear el siguiente nivel.
reward-text-level: Cambia el mensaje que se enviará al jugador después de
completar todos los desafíos en un nivel.
mode-online: Jugadores que están actualmente en línea.
mode-in-world: Jugadores en un mundo GameMode.
mode-with-island: Jugadores que tienen una isla en un mundo GameMode.
visibility-mode: Mostrar / ocultar desafíos no implementados.
reset: |-
Restablecer desafíos de usuario completados.
El clic derecho habilita / deshabilita Restablecer toda la funcionalidad.
create-challenge: |-
Agrega un nuevo desafío.
Estará en la lista de desafíos gratuitos de forma predeterminada.
required-entities: |-
Agregar / editar / eliminar entidades requeridas.
Entidades:
required-blocks: |-
Agregar / editar / eliminar bloques necesarios.
Bloques:
required-permissions: |-
Permisos requeridos a para que el jugador pueda completar este desafío.
Permiso:
remove-selected: |-
Eliminar elementos seleccionados.
Seleccione elementos con el botón derecho del mouse.
block: "- [block] : [count]"
command: "- [command]"
disabled: Desactivado
entity: "- [entity] : [count]"
item: "- [count] x [item]"
item-enchant: " - [enchant] [level]"
item-meta: " ([meta])"
nether: "- Nether"
permission: "- [permission]"
the-end: "- El End"
enabled: Activado
normal: "- Overworld"
level-unlocked: Click para ver los desafíos de nivel [level]!
level-locked: Completa [count] desafíos mas de nivel [level] para desbloquear
el siguiente nivel!
increase-by: '&aIncrementar contador de "Finalizado" en [valor]'
reduce-by: '&cReducir contador de "Finalizado" en [valor]'
type:
island: "&arequire bloques o mobs alrededor del jugador"
other: "&arequiere cosas de otros plugins/addons"
inventory: "&aRequiere items en el inventario del jugador"
current-value: "&6Valor actual: [value]."
visibility:
hidden: Solo los desafíos desplegados son visibles.
visible: Todos los desafíos son visibles para todos
toggleable: Alternar si se deben mostrar desafíos no implementados
level-description:
reward-commands: "&6Comandos de recompensa:"
experience-reward: "&6Recompensa de EXP: [value]"
money-reward: "&6Recompensa de dinero: [value]$"
reward-items: "&6Items de recompensa:"
waver-amount: "&6Se pueden omitir [value] desafíos para desbloquear el siguiente
nivel."
completed: "&bCompletado"
completed-challenges-of: "&3Has completado [number] de [max] desafíos en este
nivel."
questions:
prefix: "&2[SERVER]: "
admin:
number: Escribie un número en el chat y presiona Entrar.
challenge-name: Escribe en el chat el nombre para el desafío actual.
level-name: Escribe en el chat el nombre para el nivel actual.
unique-id: Escriba el nombre único del objeto y presione Entrar.
title:
admin:
choose-challenge-title: "&aElegir desafío"
choose-level-title: "&aElegir nivel"
choose-user-title: "&aElegir jugador"
confirm-title: "&aConfirmación"
edit-level-title: "&aEditar nivel"
edit-text-fields: "&aEditar campos de texto"
manage-blocks: "&aAdministrar bloques"
manage-items: "&aAdministrar items"
manage-numbers: "&aTeclado numérico"
select-block: "&aSeleccionar bloque"
settings-title: "&aEditar configuracion"
toggle-environment: "&aModificar ambiente"
gui-title: "&aAdministrador de Desafíos"
edit-challenge-title: "&aEditar desafío"
manage-entities: "&aAdministrar entidades"
select-challenge: "&aSeleccionar desafío"
select-entity: "&aSelecionar entidad"
library-title: "&aBibliotecas descargables"
lore-add: "&aAgregar elemento Lore"
lore-remove: "&aEliminar Elemento Lore"
lore-edit: "&aEditar Lore"
type-select: "&aElegir el tipo de desafío"
challenges: "&6Desafíos"
game-modes: "&6Elegir modo de juego"
multiple-complete: "&6¿Cuántas veces?"
item-description:
item: "- [count] x [item]"
item-enchant: "- [enchant] [level]"
item-name: "[name]"
item-lore: 'Descripción del item:'
potion-type-upgraded: "[name] actualizado"
potion-type: "[name]"
skull-owner: "[owner]"
egg-meta: "[mob]"
book-meta: "[title] por [author]"
recipe-count: "[count] recetas"
potion-type-extended-upgraded: Extendido y actualizado [name]
potion-type-extended: "[name] extendido"
potion-effect: "[effect] x [amplifier] por [duration]t"
fish-meta: "[body-color] con [patter-color] [pattern]"
item-meta: "([meta])"
armor-color: "[color]"
custom-effects: 'Efectos personalizados:'
messages:
import-challenges: Empezar a importar desafios
import-levels: Empezar a importar niveles
load-add: 'Añadiendo nuevo objeto: [value]'
load-overwriting: Sobrescribiendo "[value]"
load-skipping: '"[value]" ya existe - saltando'
no-levels: 'Advertencia: No hay niveles definidos en challenges.yml'
admin:
you-added: Has añadido un/a [thing] al desafio
challenge-created: "[challenge]&r creado!"
completed: "&2¡Has completado el desafío [name] para [player]!"
already-completed: "&2¡Este desafío ya se completó!"
reset: "&2¡Has reiniciado el desafío [name] para [player]!"
reset-all: "&2¡Todos los desafíos de [player] se han reiniciado!"
not-completed: "&2¡Este desafío aún no se ha completado!"
migrate-start: "&2Iniciar la migración de los datos de addon de desafíos."
migrate-not: "&2Todos los datos son válidos."
start-downloading: "&5Comenzar a descargar e importar la Biblioteca de desafíos."
migrate-end: "&2Datos de addon de desafíos actualizados a nuevo formato."
hit-things: Haz clic en las cosas para agregarlas a la lista de cosas requeridas.
Haz clic derecho cuando hayas terminado.
complete-wipe: "¡Espero que tengas copias de seguridad, porque acabas de borrar
todas las bases de datos del addon de Desafíos!"
players-wipe: "¡Espero que tengas copias de seguridad, porque acabas de borrar
todos los desafíos completados por el jugador!"
challenge-wipe: "¡Espero que tengas copias de seguridad, porque acabas de borrar
todos los desafíos y sus niveles!"
you-completed-challenge: "&2¡Has completado el desafío [value]!"
you-repeated-challenge: "&2¡Has repetido el desafío [value]!"
you-repeated-challenge-multiple: "&2¡Has repetido el &r&2desafío [value] [count]
veces!"
you-completed-level: "&2¡Has completado el nivel [value]!"
name-has-completed-challenge: "&5¡[name] ha completado el desafío [value]!"
name-has-completed-level: "&5¡[name] ha completado el nivel [value]!"
import-number: Se han importado [number] desafíos
defaults-file-overwrite: defaults.json ya existe. Se sobrescribirá.
defaults-file-completed: "¡El archivo defaults.json está lleno de desafíos de
[world]!"
titles:
challenge-subtitle: "[friendlyName]"
level-subtitle: "[friendlyName]"
challenge-title: Completado con éxito
level-title: Completado con éxito
meta:
authors:
- BONNe
protection:
flags:
CHALLENGES_ISLAND_PROTECTION:
description: "&5&oModifica quien puede\n&5&ocompletar desafios"
name: "Proteccion de desafios"
CHALLENGES_WORLD_PROTECTION:
description: "&5&oTEsto permite habilitar/deshabilitar\n&5&olos requisito para que los jugadores al\n&5&oestar en su isla puedan\n&5&ocompletar un reto."
name: "Limitaciones de la isla"
hint: "No hay retos fuera de la isla"
version: 9
flags:
CHALLENGES_ISLAND_PROTECTION:
name: Proteccion de desafios
description: |-
&5&oModifica quien puede
&5&ocompletar desafíos
CHALLENGES_WORLD_PROTECTION:
name: Limitaciones de la isla
hint: No hay desafíos fuera de la isla
description: "&5&oHabilitar/deshabilitar &5&orequerimiento para que los jugadores
&5&o esten en su isla para &5&ocompletar un desafío."
version: 11

View File

@ -0,0 +1,613 @@
---
challenges:
commands:
admin:
main:
description: Основная команда администратора. Открывает GUI.
import:
parameters: "[overwrite]"
description: |-
Импортировать челленджи из challenge.yml
Перезапись параметра означает, что челленджи или уровни с одинаковым ID будут перезаписаны.
reload:
parameters: "[hard]"
description: |-
Перезагрузить челленджей из базы данных
Параметр hard означает, что аддон сбросит соединение с базой данных.
defaults:
parameters: "[command]"
description: Показывает подкоманды для импорта/экспорта челленджей по умолчанию.
defaults-generate:
parameters: "[overwrite] - позволяет перезаписать существующий файл."
description: Экспортируйте существующие челленджи в файл default.json.
complete:
parameters: "<игрок> <челлендж_id>"
description: Завершите челлендж для игрока.
reset:
parameters: "<игрок> <челлендж_id>"
description: Сбросить челлендж для игрока. Если «challenge_id» установлен
на «all», он сбросит все челленджи.
migrate:
description: Миграция текущего игрового мира и данных о заданиях в формат
хранения 0.8.0.
show:
description: Отображает все челленджи в чате, которые существуют в этом мире.
defaults-import:
description: Импорт челленджей по умолчанию.
user:
complete:
parameters: "<челлендж_id> [count]"
description: Завершить челлендж.
main:
description: Открытый GUI челленджей.
gui:
title:
admin:
gui-title: "&aУправление челленджами и заданиями"
edit-challenge-title: "&aРедактировать задание"
edit-level-title: "&aРедактировать уровень"
settings-title: "&aИзменить настройки"
choose-challenge-title: "&aВыберите челлендж"
choose-level-title: "&aВыберите уровень"
choose-user-title: "&aВыберите игрока"
manage-blocks: "&aУправление блоками"
manage-entities: "&aУправление сущностями"
confirm-title: "&aПодтверждение"
manage-items: "&aУправление предметами"
manage-numbers: "&aЦифровая панель"
select-block: "&aВыберите блок"
select-challenge: "&aВыберите челлендж"
select-entity: "&aВыберите сущность"
toggle-environment: "&aПереключить окружение"
edit-text-fields: "&aРедактировать текстовые поля"
library-title: "&aЗагружаемые библиотеки"
lore-add: "&aДобавить элемент описания"
lore-remove: "&aУдалить элемент описания"
lore-edit: "&aРедактировать описание"
type-select: "&aВыберите тип челленджа"
challenges: "&6Челленджи"
game-modes: "&6Выберите игровой режим"
multiple-complete: "&6Сколько раз?"
buttons:
admin:
complete: Завершить челлендж игрока
reset: Сбросить челлендж игрока
create-challenge: Добавить новый челлендж
create-level: Добавить новый уровень
edit-challenge: Редактировать челлендж
edit-level: Редактировать уровень
delete-challenge: Удалить челлендж
delete-level: Удалить уровень
properties: Свойства
requirements: Требования
rewards: Награды
challenges: Челленджи
deployment: Отображение
icon: Иконка
locked-icon: Заблокированная иконка
description: Описание
order: Порядок
environment: Окружение
remove-on-complete: Удалить после завершения
required-experience: Требуемый опыт
remove-experience: Удалить опыт
required-level: Требуемый уровень острова
required-money: Требуемое кол-во денег
remove-money: Удалить деньги
reward-text: Сообщение награды
reward-items: Предметы в награду
reward-experience: Награда в виде опыта
reward-money: Денежная награда
reward-commands: Награда в виде команды
repeatable: Повторяемость
repeat-count: Макс. Раз
repeat-reward-text: Повторное сообщение награды
repeat-reward-items: Повторный предмет в награде
repeat-reward-experience: Повторный опыт в награде
repeat-reward-money: Повторная денежная награда
repeat-reward-commands: Повторная команда в награде
remove-completed: Удалить после завершения
glow: Свечение, когда закончено
free-at-top: Сначала свободные челленджи
line-length: Длина линии описания
add: Добавить
accept: Принять
decline: Отклонить
save: Сохранить
cancel: Отменить
input: Ввод
value: Значение
clear: Очистить
remove-empty: Удалить пустое
history-lifespan: История LifeSpan
input-mode: Переключить режим ввода
title-enable: Заглавие при завершении
library: Веб-библиотека
download: Скачать библиотеки
type:
island: "&6Тип острова"
inventory: "&6Тип инвентаря"
other: "&6Другой тип"
import: Импортировать челленджи из ASkyblock
settings: Изменить настройки
name: Дружественное имя
required-entities: Требуемые сущности
remove-entities: Убить сущностей
required-blocks: Требуемые блоки
remove-blocks: Удалить блоки
search-radius: Радиус поиска
required-permissions: Требуемые разрешения
required-items: Требуемые предметы
remove-items: Удалить предметы
waiver-amount: Сумма отказа
add-challenge: Добавить челлендж
remove-challenge: Удалить челлендж
reset-on-new: Сбросить на новом острове
broadcast: Оповещение о завершении
visibility-mode: Режим видимости челленджа
toggle-user-list: Список игроков
remove-selected: Удалить выбранные
show-eggs: Переключить режим просмотра
level-lore: Описание уровня
challenge-lore: Описание челленджа
gui-view-mode: Отображать игровые режимы
gui-mode: Единый GUI челленджей
history-store: История челленджей
island-store: Хранить на острове
default-locked-icon: Иконка заблокированного уровня
title-showtime: Время показа заглавия
default-import: Импорт челленджей по умолчанию
default-export: Экспорт челленджей по умолчанию
complete-wipe: Очистит базу данных аддона
challenge-wipe: Очистит базу данных челленджей
players-wipe: Очистит базу данных игроков
set: "="
increase: "+"
reduce: "-"
multiply: "*"
number: "[number]"
next: Следующая
previous: Предыдущая
return: Назад
value: Завершить
increase: Увеличить
reduce: Уменьшить
descriptions:
admin:
input: Открыть текстовое поле ввода.
deployment: Позволяет игрокам завершить (просмотреть) челлендж.
icon-challenge: Иконка, который будет отображаться в GUI для этой задачи.
icon-level: Иконка, который будет отображаться в GUI для этого уровня.
remove-completed: Включает/Отключает скрытие челленджей, которые выполнены
и не могут быть повторены.
toggle-user-list: Переключиться на другой список игроков.
selected: Выбрано
show-eggs: Переключить вид сущности между режимом Egg или Head.
click-to-edit: "&4Нажмите здесь, чтобы редактировать ввод."
input-mode: Переключайтесь между режимами ввода чата и наковальни.
library-lang: "&aЯзык: [lang]"
library-gamemode: "&aОсновной для [gamemode]"
download-disabled: Загрузчик данных GitHub отключен в BentoBox. Без этого
вы не можете использовать библиотеки!
create-level: Добавить новый уровень.
edit-challenge: Изменить настройки челленджа.
edit-level: Изменить настройки уровня.
delete-challenge: Удалить челлендж.
delete-level: Удалить уровень.
settings: Изменить настройки.
properties: Изменить общие свойства
requirements: Управление требованиями
rewards: Управление наградами
description: Редактировать описание.
order: Изменить номер порядка.
environment: Измените окружение челленджа.
name-challenge: Изменить отображаемое название челленджа.
name-level: Изменить отображаемое название уровня.
remove-entities: Удалит (убьет) сущности по завершению челленджа.
remove-blocks: Удалит (заменит на воздух) блоки по завершению челленджа.
search-radius: Радиус вокруг местоположения игрока, где будут находиться нужные
сущности и блоки.
reward-text: Изменить сообщение, которое будет отправлено игроку после завершения
челленджа.
repeatable: Определите, можно ли будет перепройти челлендж или нет.
free-at-top: Поменяйте местами челленджи. Истина означает, что вызовы будут
первыми, иначе - они будут последними.
line-length: Измените максимальную длину строки в поле описания. Не повлияет
на хранимые объекты.
level-lore: Изменить, какие элементы описания уровня должны быть видны.
challenge-lore: Изменить, какие элементы описания челленджа должны быть видимыми.
gui-view-mode: Укажите, должен ли /challenge GUI отображать игровые режимы
или челленджи в мире игрока.
history-store: Включить/Отключить хранение истории челленджей.
default-import: Импорт челленджей по умолчанию.
default-export: Экспор существующих челленджей в файл defaults.json.
complete-wipe: Полностью очистить все проблемы базы данных аддона. Включает
в себя данные игрока!
challenge-wipe: Полная чистка базы данных челленджей и их уровней!
players-wipe: Полностью очищенная база данных игроков!
library: Откройте GUI, который показывает все доступные публичные библиотеки.
library-version: "&9Сделано в Челленджах [version]"
save: Сохраните и вернитесь к предыдущему GUI.
cancel: Вернитесь к предыдущему GUI. Изменения не будут сохранены.
set: Установить сумму. Нажатие на цифру установит значение на выбранный число.
increase: Увеличить сумму. Нажатие на цифру увеличит значение на выбранный
число.
reduce: Уменьшить сумму. Нажатие на цифру уменьшит значение на выбранный число.
multiply: Умножьте сумму. Нажатие на цифру умножит значение на выбранное число.
challenges: Управляйте уровнями челленджей (добавляйте/удаляйте).
locked-icon: Иконка, который будет отображаться на панелях GUI, если уровень
заблокирован.
remove-on-complete: Удалить челлендж из GUI игрока после его завершения.
remove-items: Удалить предметы из инвентаря игрока после завершения челленджа.
required-experience: Определите необходимый опыт для игрока, чтобы выполнить
челлендж.
remove-experience: Удалить необходимый опыт.
reward-experience: Изменить опыт-награду за первое завершение челленджа.
repeat-count: Определите максимальное количество повторений. Если значение
установлено на 0, ограничений нет.
repeat-reward-text: Изменить сообщение, которое будет отправлено игроку после
повторного завершения челленджа.
repeat-reward-experience: Изменить опыт-награду за повторное завершение челленджа.
waiver-amount: Установите количество челленджей, которые игрок сможет пропустить,
чтобы разблокировать следующий уровень.
reward-text-level: Измените сообщение, которое будет отправлено игроку после
завершения всех челленджей на уровне.
add-challenge: Добавить существующий челлендж на текущий уровень.
remove-challenge: Удалить челлендж с текущего уровня.
reset-on-new: Включает/Отключает сброс всех челленджей для игрока, если он
перезайдет, выйдет или будет выгнан с острова.
broadcast: Включает/Отключает оповещение на первое прохождения челленджа для
всех онлайн игроков.
glow: Включает/Отключает эффект свечения для выполненных челленджей.
mode-online: Игроки, которые сейчас онлайн.
mode-in-world: Игроки в GameMode мире.
mode-with-island: Игроки, у которых есть остров в GameMode мире.
visibility-mode: Показать/Cкрыть неразрешенные челленджи.
edit-text-line: "&6Редактировать текстовое сообщение!"
add-text-line: "&6Добавить новое текстовое сообщение!"
title-enable: Включите/Отключите заглавное сообщение, которое будет показано
игрокам, когда они выполнят челлендж.
title-showtime: Измените, как долго заглавные сообщения будут видны игроку.
import: |-
Импортировать вызовы из ASkyblock.
При щелчке правой кнопкой он включает/отключает режим перезаписи.
Поместите challenge.yml в папку ./BentoBox/addons/Challenges.
complete: |-
Выполняйте челленджи для любого пользователя.
Пользователь не получит вознаграждение за завершение.
reset: |-
Сброс завершенных пользовательских челленджей.
Правый клик включает/отключает сброс всех функций.
create-challenge: |-
Добавить новый челлендж.
По умолчанию будет в списке свободных челленджей.
required-entities: |-
Добавить/редактировать/удалить требуемые сущности.
Сущности:
required-blocks: |-
Добавить/редактировать/удалить требуемые блоки.
Блоки:
required-permissions: |-
Требуемые разрешения для игрока, чтобы иметь возможность выполнить этот челлендж.
Разрешение:
required-items: 'Необходимые предметы в инвентаре игрока. Предметы:'
required-level: |-
Укажите необходимый уровень острова для этого челленджа.
&cТребуется аддон Level.'
required-money: |-
Укажите необходимое кол-во денег на счету игрока.
&cТребуется Vault и любой плагин на экономику.'
remove-money: |-
Снять необходимое кол-во денег со счета игрока.
&cТребуется Vault и любой плагин на экономику.'
reward-items: 'Изменить награду в виде предмета за первое завершение челленджа.
Предметы:'
reward-money: |-
Изменить денежное вознаграждение за первое выполнение челленджа.
&cТребуется Vault и любой плагин на экономику.
reward-commands: |-
Установите вознаграждения в виде команд, которые будут выполняться после первого завершения.
***Добавление "[SELF]" в начале, означает, что команда будет запущена игроком, например, "/kill"
***Строка "[player]" будет заменено на имя игрока, например "/kill [player]" будет выполняться как "/kill BONNe1704"
Команды:
repeat-reward-items: |-
Изменить предметы в награде за повторное выполнение челленджа.
Предметы:
repeat-reward-money: |-
Изменить денежное вознаграждение за повторное выполнение челленджа.
&cТребуется Vault и любой плагин на экономику.
repeat-reward-commands: |-
Установите команды в виде награды, которые будут выполняться после повторного выполнения челленджа.
***Добавление "[SELF]" в начале, означает, что команда будет запущена игроком, например, "/kill"
***Строка "[player]" будет заменено на имя игрока, например "/kill [player]" будет выполняться как "/kill BONNe1704"
Команды:
remove-selected: |-
Удалить выбранные элементы.
Выделите элементы правой кнопкой мыши.
history-lifespan: |-
Изменить, сколько дней, данные истории должны храниться.
Значение 0 - означает навсегда.
island-store: |-
Включить/Отключить хранение данных челленджей на каждом острове. Это означает, что челленджи будут одинаковыми для всей команды, если это включено.
&cНЕ будет конвертировать данные по клику. Прогресс будет потерян.'
default-locked-icon: |-
Изменить иконку заблокированного уровня по умолчанию.
Эта опция может быть перезаписана каждым уровнем.
gui-mode: |-
Включить/Отключить одиночный вызов GUI.
&2Потребуется перезапустить сервер.'
download: |-
Обновить вручную доступные библиотеки челленджей.
Щелкните правой кнопкой мыши, чтобы включить очистку кэша.'
lore:
level: |-
Строка уровня.
Представляет перевод challenges.gui.challenge-description.level
status: |-
Строка состояния.
Представляет перевод challenges.gui.challenge-description.completed
count: |-
Строка подсчета завершений.
Представляет перевод для challenges.gui.challenge-description.completed-times
challenges.gui.challenge-description.completed-times-of
and challenges.gui.challenge-description.maxed-reached
description: |-
Строка описания.
Определенный в челленджах объект - challenge.description.
warnings: |-
Строка предупреждения.
Представляет перевод для:
challenges.gui.challenge-description.warning-items-take
challenges.gui.challenge-description.objects-close-by
challenges.gui.challenge-description.warning-entities-kill
challenges.gui.challenge-description.warning-blocks-remove
environment: |-
Строка среды.
Определенный в задачах объект - challenge.environment.
requirements: |-
Строка требования.
Представляет перевод для:
challenges.gui.challenge-description.required-level
challenges.gui.challenge-description.required-money
challenges.gui.challenge-description.required-experience
challenge.requiredItems'
challenge.requiredBlocks'
or challenge.requiredEntities.
reward_text: |-
Строка вознаграждения.
Определено в challenge.rewardText и challenge.repeatRewardText
reward_other: |-
Другая строка награды.
Представляет перевод для:
challenges.gui.challenge-description.experience-reward
challenges.gui.challenge-description.money-reward
challenges.gui.challenge-description.not-repeatable
reward_items: |-
Предметы в награду.
Список предметов, которые будут выданы в виде награды, определены в challenge.rewardItems and challenge.repeatRewardItems.
reward_commands: |-
Награда в виде команды.
Список команд которые будут выполнены в виде награды, определены в challenge.rewardCommands and challenge.repeatRewardCommands.
level_status: |-
Строка состояния.
Представляет перевод challenges.gui.level-description.completed
challenge_count: |-
Строка количества завершенных челленджей.
Представляет перевод для challenges.gui.level-description.completed-challenges-of
unlock_message: |-
Строка сообщения разблокировки.
Определен в объекте уровня челленджа - challengeLevel.unlockMessage
waiver_amount: |-
Строка количества выпадающих челленджей, чтобы разблокировать следующий уровень.
Представляет перевод для challenges.gui.level-description.waver-amount
level_reward_text: |-
Строка вознаграждения.
Определено в challengeLevel.rewardText
level_reward_other: |-
Строка с другой наградой.
Представляет перевод для:
challenges.gui.level-description.experience-reward
challenges.gui.level-description.money-reward
level_reward_items: |-
Предметы в награду.
Список предметов, которые будут выданы как награда, определены в challengeLevel.rewardItems
level_reward_commands: |-
Команды в виде награды.
Список команды которые будут выполнены в виде награды, определены в challengeLevel.rewardCommands
library-author: автор &e[автор]
enabled: Включено
disabled: Отключено
the-end: "- Край"
nether: "- Ад"
normal: "- Верхний мир"
entity: "- [entity] : [count]"
permission: "- [permission]"
level-unlocked: Нажмите, чтобы увидеть [level] челленджей!
level-locked: Заверши больше [count] заданий, уровня [level], чтобы открыть
этот уровень!
increase-by: "&aУвеличьте кол-во завершений на [value]"
reduce-by: "&aУменьшите кол-во завершений на [value]"
visibility:
hidden: Видны только отображаемые челленджи.
visible: Все челленджи видны всем
toggleable: Переключить, если неиспользуемые челленджи должны отображаться
type:
island: "&aтребовать блоков или мобов вокруг игрока"
other: "&aтребовать предметы от других плагинов/аддонов"
inventory: "&aтребовать предметы в инвентаре игрока"
current-value: "&6Текущее значение: [value]."
block: "- [block] : [count]"
item: "- [count] x [item]"
item-meta: "([meta])"
item-enchant: "- [enchant] [level]"
command: "- [command]"
challenge-description:
completed-times-of: Завершено [donetimes] из [maxtimes]
maxed-reached: Завершено [donetimes] из [maxtimes]
completed-times: Завершено [donetimes]
objects-close-by: "&cВсе необходимые блоки и сущности должны быть рядом с вами,
на вашем острове!"
warning-entities-kill: "&cВсе необходимые сущности будут убиты, когда вы завершите
этот челлендж!"
warning-blocks-remove: "&cВсе необходимые блоки будут удалены, когда вы выполните
этот челлендж!"
not-repeatable: "&cЭтот челлендж нельзя повторить!"
experience-reward: "&6Опыта в награде: [value]"
money-reward: "&6Денежная награда: $[value]"
required-experience: "&6Требуется опыта: [value]"
required-money: "&6Требуется денег: $[value]"
required-island-level: "&6Требуемый уровень острова: [value]"
environment: 'Обязательные условия:'
reward-items: "&6Пердметы в награде:"
reward-commands: "&6Команды в награде:"
required-items: 'Требуемые предметы:'
required-entities: 'Требуемые сущности:'
required-blocks: 'Требуемые блоки:'
level: "&fУровень: [level]"
completed: "&bЗавершено"
warning-items-take: "&cВсе необходимые предметы будут изъяты из вашего инвентаря,
когда вы завершите этот челлендж!"
level-description:
experience-reward: "&6Опыта в награде: [value]"
money-reward: "&6Денежная награда: $[value]"
reward-items: "&6Предметы в награде:"
reward-commands: "&6Команды в награде:"
waver-amount: "&6[value] челленджи могут быть пропущены, чтобы разблокировать
следующий уровень."
completed: "&bЗавершено"
completed-challenges-of: "&3Вы завершили [number] из [max] челленджей на этом
уровне."
item-description:
item: "- [count] x [item]"
potion-type-extended-upgraded: Расширен и обновлен [name]
potion-type-upgraded: Улучшен [name]
potion-type-extended: Расширен [name]
custom-effects: 'Индивидуальные эффекты:'
potion-effect: "[effect] x [amplifier] для [duration]t"
fish-meta: "[body-color] с [pattern-color] [pattern]"
item-meta: "([meta])"
item-enchant: "- [enchant] [level]"
item-name: "[name]"
armor-color: "[color]"
potion-type: "[name]"
skull-owner: "[owner]"
egg-meta: "[mob]"
item-lore: 'уздечка:'
book-meta: "[title] [author]"
recipe-count: "[count] рецептов"
questions:
prefix: "&2[СЕРВЕР]:"
admin:
unique-id: Введите уникальное имя объекта и нажмите клавишу ENTER.
number: Напишите номер в чате и нажмите ENTER.
challenge-name: Напишите отображаемое имя в чате для текущего челленджа.
level-name: Напишите отображаемое имя в чате для текущего уровня.
titles:
challenge-title: Успешно завершено
challenge-subtitle: "[friendlyName]"
level-title: Успешно завершено
level-subtitle: "[friendlyName]"
messages:
admin:
you-added: Вы добавили один [thing] в челлендж
challenge-created: "[challenge]&r создан!"
completed: "&2Вы завершили челлендж [name] для игрока [player]!"
already-completed: "&2Этот челлендж уже был выполнен!"
reset: "&2Вы сбрасываете челлендж [name] для игрока [player]!"
reset-all: "&2Все [player] челленджи были сброшены!"
not-completed: "&2Этот челлендж еще не завершен!"
migrate-start: "&2Начать миграцию данных аддона для челленджей."
migrate-not: "&2Все данные действительны."
start-downloading: "&5Начинаем скачивать и импортировать Challenges Library."
migrate-end: "&2Данные аддона челленджей обновлены до нового формата."
hit-things: Нажмите на предметы, чтобы добавить их в список необходимых предметов.
Щелкните правой кнопкой мыши, когда закончите.
complete-wipe: "&cНадеюсь, у вас есть резервные копии, потому что вы просто
стерли все данные из базы аддона Challenges!"
challenge-wipe: "&cНадеюсь, у вас есть резервные копии, потому что вы просто
стерли все челленджи и их уровни!"
players-wipe: "&cНадеюсь, у вас есть резервные копии, потому что вы просто стерли
все выполненные игроками челленджи!"
you-completed-challenge: "&2Вы завершили [value] &r&2челлендж!"
you-repeated-challenge: "&2Ты перепрошел [value] &r&2челлендж!"
you-repeated-challenge-multiple: "&2Вы перепрошли [value] &r&2челлендж [count]
раз!"
you-completed-level: "&2Вы завершили [value] &r&2уровень!"
name-has-completed-challenge: "&5[name] завершил [value] &r&5челлендж!"
name-has-completed-level: "&5[name] завершил [value] &r&5уровень!"
import-levels: Начало импорта уровней
import-challenges: Начало импорта челленджей
no-levels: 'Предупреждение: Уровни не определены в challenge.yml'
import-number: Импортировано [number] челленджей
load-skipping: '"[value]" уже существует - пропуск'
load-overwriting: Перезапись "[value]"
load-add: 'Добавление нового объекта: [value]'
defaults-file-overwrite: defaults.json существует. Это будет перезаписано.
defaults-file-completed: defaults.json файл заполнен челленджами из [world]!
errors:
no-name: "&cОтсутствует имя челленджа"
unknown-challenge: "&cНеизвестный челлендж"
unique-id: '&cУникальный идентификатор "[id]" недействителен.'
wrong-icon: '&cДанный материал "[value]" недействителен и не может использоваться
в качестве иконки.'
not-deployed: "&cЧеллендж не отображается!"
not-on-island: "&cВы должны быть на своем острове, чтобы сделать это!"
not-repeatable: "&cЭтот челлендж нельзя пройти повторно!"
not-enough-items: "&cУ тебя недостаточно [items] чтобы завершить этот челлендж!"
not-close-enough: "&cВы должны стоять в пределах [number] блоков от всех необходимых
предметов."
you-still-need: "&cВам еще нужно [amount] x [item]"
not-enough-money: "&cНеобходимо иметь [value] на вашем аккаунте, чтобы завершить
челлендж."
import-no-file: "&cНе могу найти challenges.yml файл для импорта!"
no-load: "&cОшибка: Не смог загрузить challenges.yml. [message]"
load-error: "&cОшибка: Не удается загрузить [value]."
defaults-file-exist: "&cdefaults.json уже существует. Используйте режим перезаписи,
чтобы заменить его!"
defaults-file-error: "&cПроизошла ошибка при создании файла defaults.json! Проверьте
консоль!"
missing-arguments: "&cВ команде отсутствуют аргументы."
wrong-environment: "&cВы находитесь в неправильном окружении!"
missing-addon: "&cНевозможно выполнить задание: отсутствует обязательный аддон
или плагин."
exist-challenges-or-levels: "&cЧелленджи уже существуют в вашем мире. Не могу
продолжить!"
no-challenges: "&cЧелленджи еще не реализованы в этом мире!"
no-challenges-admin: "&cЧелленджи еще не реализованы в этом мире! Используйте
\ &5/[command] &cчтобы добавить их!"
missing-level: "&cУровень челленджа [level] не определен в базе данных. Это может
привести к ошибкам!"
no-multiple-permission: "&cУ вас нет разрешения на выполнение этого задания несколько
раз одновременно."
not-a-integer: '&cДанное значение "[value]" не является целым числом!'
challenge-level-not-available: "&cВы не разблокировали необходимый уровень для
выполнения этого челленджа."
incorrect: "&cНевозможно выполнить челлендж: требования неверны."
not-enough-experience: "&cНеобходимо иметь [value] опыта, чтобы завершить этот
челлендж."
island-level: "&cВаш остров должен быть [number] уровня или больше, чтобы завершить
этот челлендж!"
no-rank: "&cУ вас нет достаточно высокого ранга, чтобы сделать это."
cannot-remove-items: "&cНекоторые предметы не могут быть удалены из вашего инвентаря!"
not-valid-integer: |-
&cЗаданное целое число "[value]" не является действительным!
Значение должно быть между [min] и [max].
protection:
flags:
CHALLENGES_ISLAND_PROTECTION:
description: |-
&5&oПереключить, кто может
&5&oзавершить челлендж
name: Защита челленджа
CHALLENGES_WORLD_PROTECTION:
name: Ограничения острова челленджей
hint: Нет челленджей за пределами острова
description: |-
&5&oВключить/Выключить
&5&oтребование к игрокам
&5&oбыть на их острове, чтобы
&5&oвыполнить челлендж.
version: 11
meta:
authors:
- BONNe

View File

@ -1,405 +1,471 @@
###########################################################################################
# This is a YML file. Be careful when editing. Check your edits in a YAML checker like #
# the one at http://yaml-online-parser.appspot.com #
###########################################################################################
### Credits ###
meta:
authors: []
---
challenges:
commands:
admin:
main:
parameters: ''
description: '打开管理员菜单'
import:
description: '从challenges.yml文件中导入挑战以及挑战等级'
parameters: '[overwrite]'
reload:
description: '重载挑战组件'
parameters: '[hard]'
show:
description: '在聊天中列出当前世界的所有挑战'
parameters: ''
defaults:
description: '显示导入/导出插件自带挑战的子指令'
parameters: '[command]'
defaults-import:
description: '导入插件自带挑战'
parameters: ''
defaults-generate:
description: '将现有的挑战导出到default.json文件中。'
parameters: '[overwrite] - allows to overwrite existing file.'
complete:
description: '通过指令让某个玩家完成指定挑战'
parameters: '<player> <challenge_id>'
user:
main:
description: '打开空岛挑战菜单'
parameters: ''
complete:
description: '通过指令完成挑战'
parameters: '<challenge_id> [count]'
gui:
title:
admin:
gui-title: '&a岛屿挑战管理'
edit-challenge-title: '&a编辑挑战'
edit-level-title: '&a编辑挑战等级'
settings-title: '&a编辑设定'
choose-challenge-title: '&a选择挑战'
choose-level-title: '&a选择挑战等级'
choose-user-title: '&a选择玩家'
manage-blocks: '&a管理方块'
manage-entities: '&a管理实体'
confirm-title: '&a确认'
manage-items: '&a管理物品'
manage-numbers: '&a数字垫'
select-block: '&a选择方块'
select-challenge: '&a选择挑战'
select-entity: '&a选择实体'
toggle-environment: '&a切换环境'
edit-text-fields: '&a编辑文本字段'
challenges: '&a岛屿挑战'
game-modes: '&a选择游戏模式'
buttons:
admin:
complete: '完成某个玩家的挑战'
reset: '重置某个玩家的挑战'
create-challenge: '创建新的挑战'
create-level: '创建新的挑战等级'
edit-challenge: '编辑挑战'
edit-level: '编辑挑战等级'
delete-challenge: '删除挑战'
delete-level: '删除挑战等级'
import: '导入ASkyBlock插件的挑战内容'
settings: '编辑设定'
properties: '属性'
requirements: '要求'
rewards: '奖励'
challenges: '挑战'
type: '挑战类型'
deployment: '是否开启该挑战'
icon: '图标'
locked-icon: '图标锁'
description: '介绍'
order: '顺序'
environment: '环境'
remove-on-complete: '完成后删除该挑战'
name: '挑战名称'
required-entities: '检测的实体'
remove-entities: '完成任务后是否杀死实体'
required-blocks: '检测的方块'
remove-blocks: '完成任务后是否删除方块'
search-radius: '搜索半径'
required-permissions: '需要的权限'
required-items: '需要的物品'
remove-items: '完成任务后是否删除物品'
required-experience: '需要的经验值'
remove-experience: '完成任务后是否删除经验值'
required-level: '需要的岛屿等级'
required-money: '需要的金钱'
remove-money: '完成任务后是否删除金钱'
reward-text: '奖励信息'
reward-items: '物品奖励'
reward-experience: '经验奖励'
reward-money: '金钱奖励'
reward-commands: '指令奖励'
repeatable: '是否可重复挑战'
repeat-count: '最大时间'
repeat-reward-text: '重复奖励信息'
repeat-reward-items: '重复物品奖励'
repeat-reward-experience: '重复经验奖励'
repeat-reward-money: '重复金钱奖励'
repeat-reward-commands: '重复指令奖励'
waiver-amount: '豁免金额'
add-challenge: '添加挑战'
remove-challenge: '删除挑战'
reset-on-new: '在新的岛屿上重置'
broadcast: '成功任务后发出广播'
remove-completed: '完成任务后删除图标'
glow: '完成任务后发光'
free-at-top: '免费挑战优先排列'
line-length: 'Lore长度'
toggle-user-list: '用户列表'
remove-selected: '删除选定'
add: '添加'
show-eggs: '切换视图模式'
accept: '接受'
decline: '拒绝'
save: '保存'
cancel: '取消'
input: '输入'
value: '值'
set: '='
increase: '+'
reduce: '-'
multiply: '*'
clear: '清空'
remove-empty: '删除空栏'
number: '[number]'
level-lore: '等级介绍'
challenge-lore: '挑战介绍'
gui-view-mode: '显示所有GameModes'
gui-mode: '挑战GUI'
history-store: '挑战历史'
history-lifespan: '历史LifeSpan'
island-store: '每个岛屿的商店'
default-locked-icon: '等级图标锁'
input-mode: '切换输入模式'
title-enable: '显示标题'
title-showtime: '标题显示时间'
default-import: '导入默认挑战'
default-export: '导出现有挑战'
complete-wipe: '抹除插件数据库!'
next: '下一页'
previous: '上一页'
return: '返回上一级'
descriptions:
admin:
save: '保存并返回上一级菜单'
cancel: '取消任何操作并返回上一级菜单'
input: '打开文本字段输入'
set: '设置操作,击数字会将值更改为所选数字。'
increase: '增加操作。 单击数字将增加所选数字的值。'
reduce: '减少操作。 单击数字将减少所选数字的值。'
multiply: '乘法运算。 单击数字会将值乘以所选数字。'
import: '导入ASkyblock挑战。|右键单击它启用/禁用覆盖模式。|将Challenges.yml放在./BentoBox/addons/Challenges文件夹中。'
complete: '为某个玩家完成某个挑战|玩家无法获得完成奖励。'
reset: '重置已完成的玩家挑战。|右键单击启用/禁用重置所有功能。'
create-challenge: '添加新挑战。|默认情况下,它将在免费挑战列表中。'
create-level: '添加新的挑战等级。'
edit-challenge: '编辑某个挑战设定'
edit-level: '编辑某个挑战等级设定'
delete-challenge: '删除某个挑战'
delete-level: '删除某个挑战等级'
settings: '修改组件设定'
properties: '修改常规属性'
requirements: '修改挑战需求'
rewards: '修改挑战奖励'
challenges: '管理挑战级别 (添加/删除).'
deployment: '查看某玩家已完成的挑战'
icon-challenge: '将在此挑战的GUI面板中显示的图标。'
icon-level: '将在此级别的GUI面板中显示的图标。'
locked-icon: '如果级别被锁定将在GUI面板中显示的图标。'
description: '编辑介绍'
order: '更改挑战顺序'
environment: '改变挑战运作的环境。'
type: '更改挑战类型(不同类型的挑战侦测方式不同)'
remove-on-complete: '在玩家完成挑战后是否删除该挑战图标于任务面板中'
name-challenge: '修改挑战名称'
name-level: '修改挑战等级名称'
required-entities: '修改挑战需要的实体.|实体:|'
remove-entities: '是否在挑战结束后删除挑战需要的实体'
required-blocks: '修改挑战需要的方块.|方块:|'
remove-blocks: '是否在挑战结束后删除任务需求方块(替换为空气)'
search-radius: '玩家完成挑战时检测实体/方块的范围(半径)'
required-permissions: '玩家需要具有以下权限才能完成挑战|权限:'
required-items: '玩家背包中需要有以下物品才能完成挑战|物品:'
remove-items: '是否在完成挑战后删除玩家背包中的挑战需求物品'
required-experience: '玩家需要有该项目所设置的经验值才可以完成挑战'
remove-experience: '是否在玩家完成挑战后删除任务需求的经验值'
required-level: '玩家需要岛屿等级达到该项目所设置的等级才能完成挑战.|&c需要 Level 组件.'
required-money: '玩家需要有该项目所设置的金钱才能完成挑战.|&c需要经济前置.'
remove-money: '是否在玩家完成挑战后删除任务需求的金钱.|&c需要经济前置.'
reward-text: '设置完成任务后的奖励信息'
reward-items: '设置完成任务后的物品奖励.|物品:'
reward-experience: '设置完成任务后的经验奖励.'
reward-money: '设置完成任务后的金钱奖励.|&c需要经济前置.'
reward-commands: '设置完成任务后的指令奖励.|指令:'
repeatable: '挑战是否可以重复'
repeat-count: '重复挑战的次数如果设置为0则为无限制'
repeat-reward-text: '重复挑战完成后的信息'
repeat-reward-items: '重复挑战完成后的物品奖励.|物品:'
repeat-reward-experience: '重复挑战完成后的经验奖励.'
repeat-reward-money: '重复挑战完成后的金钱奖励.|&c需要经济前置.'
repeat-reward-commands: '重复挑战完成后的指令奖励.||指令:'
waiver-amount: '完成该数量的挑战玩家方能解锁下一挑战级别的挑战'
reward-text-level: '完成某挑战级别所有挑战后发送给玩家的信息'
add-challenge: '将现有挑战添加到当前挑战级别'
remove-challenge: '从当前级别删除挑战'
reset-on-new: '允许/禁止,当玩家重置/踢出岛屿后都会重置挑战'
broadcast: '允许/禁止,当玩家完成第一次挑战后向全服玩家广播'
remove-completed: '允许/禁止,在玩家挑战列表中隐藏已完成的挑战'
glow: '允许/禁用,在已完成的挑战中加上附魔效果'
free-at-top: '改变免费挑战的位置如果为true免费挑战会放在前排如果为false免费挑战将放在后排'
line-length: '修改每条lore的最大长度'
toggle-user-list: '切换到不同的玩家列表'
mode-online: '目前在线的玩家'
mode-in-world: '属于游戏模式中的世界的玩家.'
mode-with-island: '属于游戏模式中的岛屿的玩家.'
selected: '已选中'
remove-selected: '删除所选目标|您可以使用鼠标右键选择目标'
show-eggs: '在Egg模式或Head模式之间切换实体视图'
level-lore: '修改挑战级别介绍的哪些目标是可见的'
challenge-lore: '修改挑战介绍的哪些目标是可见的'
gui-view-mode: '如果玩家输入/challenges菜单应该显示GameModes还是挑战'
history-store: '允许启用/禁用质询历史存储'
history-lifespan: '允许修改将保存历史数据的天数| 0表示永久'
island-store: '启用/禁用挑战每个岛的数据存储。如果启用此选项,整个岛屿团队的挑战进度将是相同的。|不会在点击时转换数据。进展将会失败。'
default-locked-icon: '更改默认锁定级别图标。|此级别可以覆盖此选项。'
gui-mode: '启用/禁用单一挑战GUI。|&2要求服务器重启。'
click-to-edit: '&4点击此处编辑输入.'
edit-text-line: '&6编辑文本!'
add-text-line: '&6 添加新的文本!'
input-mode: '在聊天和铁砧输入模式之间切换。'
title-enable: '启用/禁用玩家完成挑战时显示的标题消息。'
title-showtime: '修改标题消息对玩家可见的时间。'
default-import: '导入插件自带挑战'
default-export: '将现有的挑战导出至 defaults.json 文件中.'
complete-wipe: '清空插件数据库中的所有挑战,包括玩家的挑战数据!'
current-value: '|&6当前值: [value].'
enabled: '有效'
disabled: '禁用'
type:
island: '- 岛屿类型:| (主要通过检测玩家身边的方块和生物)'
inventory: '- 库存类型:| (主要通过检测玩家的背包物品)'
other: '- 其他类型:| (主要通过检测服务器的其他插件/组件)'
the-end: '- 末地'
nether: '- 地狱'
normal: '- 主世界'
entity: '- [entity] : [count]'
block: '- [block] : [count]'
permission: '- [permission]'
item: '- [count] x [item]'
item-meta: ' ([meta])'
item-enchant: ' - [enchant] [level]'
command: '- [command]'
level-unlocked: '点击查看 [level] 级别的挑战!'
level-locked: '请完成 [count] 个 [level] 级别的挑战来解锁这个挑战级别!'
challenge-description:
level: '&F挑战级别: [level]'
completed: '&B已完成'
completed-times-of: '完成次数: [donetimes] 上限: [maxtimes]'
maxed-reached: '完成次数: [donetimes] 上限: [maxtimes]'
completed-times: '已完成 [donetimes]'
warning-items-take: '&c完成此挑战后该挑战的需要物品将会被清空'
objects-close-by: '&c任务需求的方块/生物不能离你太远!(超出侦测范围)'
warning-entities-kill: '&c完成此挑战后该挑战需要的生物将会被清空'
warning-blocks-remove: '&c完成此挑战后该挑战需要的方块将会被清空'
not-repeatable: '&c该挑战不可重复!'
experience-reward: '&6经验奖励: [value]'
money-reward: '&6金钱奖励: $[value]'
required-experience: '&6所需经验: [value]'
required-money: '&6所需金钱: $[value]'
required-island-level: '&6所需岛屿等级: [value]'
environment: '所需实体:'
reward-items: '&6物品奖励:'
reward-commands: '&6指令奖励:'
required-items: '所需物品:'
required-entities: '所需实体:'
required-blocks: '所需方块:'
level-description:
completed: '&B已完成'
completed-challenges-of: '&你已经完成 [number] 个该级别的挑战,达到了 [max]个挑战.'
waver-amount: '&6可以跳过[value] 个挑战来解锁下一个挑战级别.'
experience-reward: '&6经验奖励: [value]'
money-reward: '&6金钱奖励: $[value]'
reward-items: '&6物品奖励:'
reward-commands: '&6指令奖励:'
item-description:
item: '- [count] x [item]'
item-meta: ' ([meta])'
item-enchant: ' - [enchant] [level]'
item-name: ' [name]'
item-lore: ' 物品Lore:'
book-meta: ' [title] by [author]'
recipe-count: ' [count] recipes'
armor-color: ' [color]'
potion-type-extended-upgraded: ' [name]'
potion-type-upgraded: ' Upgraded [name]'
potion-type-extended: ' Extended [name]'
potion-type: ' [name]'
custom-effects: ' 自定义效果:'
potion-effect: ' [effect] x [amplifier] for [duration]t'
skull-owner: ' [owner]'
egg-meta: ' [mob]'
fish-meta: ' [body-color] with [pattern-color] [pattern]'
questions:
prefix: "&2[SERVER]: "
admin:
number: "Write a number in chat and press enter to accept it and press enter."
unique-id: "Write object unique name and press enter."
challenge-name: "Write in chat display name for current challenge."
level-name: "Write in chat display name for current level."
titles:
# Title and subtitle my contain variable in [] that will be replaced with proper message from challenge object.
# [friendlyName] will be replaced with challenge friendly name.
# [level] will be replaced with level friendly name.
# [rewardText] will be replaced with challenge reward text.
challenge-title: '完成挑战'
challenge-subtitle: '[friendlyName]'
# Title and subtitle my contain variable in [] that will be replaced with proper message from level object.
# [friendlyName] will be replaced with level friendly name.
# [rewardText] will be replaced with level reward text.
level-title: '成功挑战级别'
level-subtitle: '[friendlyName]'
messages:
admin:
hit-things: '点击物品将它们添加到所需的事物列表中。 完成后右键单击。'
you-added: '你在挑战中添加了一个[thing]'
challenge-created: '[challenge]&r created!'
complete-wipe: '&c希望你有备份因为你已经创建了所有Challenges Addon数据库'
completed: '&2已为[player]完成挑战[name]!'
already-completed: '&2这个挑战已经完成'
you-completed-challenge: '&2你已经完成了 [value] &r&2挑战!'
you-repeated-challenge: '&2你已经重复完成了 [value] &r&2挑战!'
you-repeated-challenge-multiple: '&2你重复完成了 [value] &r&2挑战 [count] 次!'
you-completed-level: '&2你完成了 [value] &r&2级别!'
name-has-completed-challenge: '&5[name] 已完成 [value] &r&5挑战!'
name-has-completed-level: '&5[name] 已完成 [value] &r&5挑战级别!'
import-levels: '开始导入挑战级别'
import-challenges: '开始导入挑战'
no-levels: '警告: challenges.yml文件中没有定义挑战级别'
import-number: '导入 [number] 个挑战'
load-skipping: '"[value]" 已存在 - 跳过'
load-overwriting: '覆盖 "[value]"'
load-add: '添加新的对象: [value]'
defaults-file-overwrite: 'defaults.json存在。 它将被覆盖。'
defaults-file-completed: 'defaults.json文件填充了来自[world]的挑战!'
errors:
no-name: '&c缺少挑战名称'
unknown-challenge: '&c未知挑战'
unique-id: '&cUniqueID "[id]" 无效.'
wrong-icon: '&c给定材料“[value]”无效且不能用作图标。'
not-valid-integer: '&c给定整数“[value]”无效!|值应介于[min]和[max]之间。'
not-a-integer: '&c给定值“[value]”不是整数!'
not-deployed: '&c未开启挑战'
not-on-island: '&c你必须在你的岛上做到这一点'
challenge-level-not-available: '&c你没有解锁挑战级别来完成这个挑战。'
not-repeatable: '&c这个挑战是不可重复的'
wrong-environment: '&c你在错误的环境中'
not-enough-items: '&c你没有足够的[items]来完成这个挑战!'
not-close-enough: '&c你必须站在拥有[number]个任务需求方块的旁边.'
you-still-need: '&c你还需要 [amount] x [item]'
missing-addon: '&c无法完成挑战。 缺少必需的插件或组件。'
incorrect: '&c无法完成挑战。 要求不正确。'
not-enough-money: '&c您的帐户必须有[value]金钱才能完成挑战。.'
not-enough-experience: '&c必须有[value]EXP才能完成挑战'
island-level: '&c你的岛屿等级需要达到[number]才能完成挑战'
import-no-file: '&c找不到challenge.yml文件导入'
no-load: '&c错误无法加载challenge.yml。 [message]'
load-error: '&c错误:无法加载 [value].'
no-rank: "&c你没有等级可以做到这一点."
cannot-remove-items: '&c有些物品无法从你的背包中删除!'
exist-challenges-or-levels: '&c在你的世界里已经存在挑战。 无法继续!'
defaults-file-exist: '&cdefaults.json已经存在。 使用覆盖模式替换它!'
defaults-file-error: '&c创建defaults.json文件时出错 检查控制台!'
no-challenges: '&c当前世界没有实施挑战'
no-challenges-admin: '&c当前世界没有实施挑战!你应该使用 &5/[label] challenges &c添加他们!'
missing-level: '&c挑战级别[level]未在数据库中定义. 可能会出现错误!'
missing-arguments: '&c命令缺少参数.'
commands:
admin:
complete:
parameters: "<player> <challenge_id>"
description: 通过指令完成挑战
defaults:
description: 显示导入/导出插件自带挑战的子指令
parameters: "[command]"
import:
parameters: "[overwrite]"
description: 从 challenges.yml 文件中导入挑战|参数覆盖意味着具有相同 ID 的挑战或等级将被覆盖。
main:
description: 打开管理员菜单
reload:
description: 重载挑战组件
parameters: "[hard]"
show:
description: 在聊天中列出当前世界的所有挑战
defaults-import:
description: 导入系统自带挑战
defaults-generate:
description: 将现有的挑战导出到default.json文件中
parameters: "[overwrite] - 允许覆盖已有文件"
reset:
description: 通过指令重置玩家挑战。若 "challenge_id" 参数设为 all则将重置该玩家的所有挑战。
parameters: "<player> <challenge_id>"
migrate:
description: 将参考当前游戏模式世界的挑战数据迁移到新的0.8.0存储格式。
user:
complete:
description: 通过指令完成挑战
parameters: "<challenge_id> [count]"
main:
description: 打开挑战菜单
errors:
cannot-remove-items: "&c有些物品无法从你的背包中删除!"
challenge-level-not-available: "&c你没有解锁挑战级别来完成这个挑战。"
defaults-file-error: "&c创建defaults.json文件时出错 检查控制台!"
defaults-file-exist: "&cdefaults.json已经存在。 使用覆盖模式替换它!"
exist-challenges-or-levels: "&c在你的世界里已经存在挑战。 无法继续!"
import-no-file: "&c找不到challenge.yml文件导入"
incorrect: "&c无法完成挑战。 要求不正确。"
island-level: "&c你的岛屿等级需要达到[number]才能完成挑战"
load-error: "&c错误:无法加载 [value]."
missing-addon: "&c无法完成挑战。 缺少必需的插件或组件。"
missing-arguments: "&c命令缺少参数."
missing-level: "&c挑战级别[level]未在数据库中定义. 可能会出现错误!"
no-challenges: "&c当前世界没有实施挑战"
no-challenges-admin: "&c当前世界没有实施挑战!你应该使用 &5/[label] challenges &c添加他们!"
no-load: "&c错误无法加载challenge.yml。 [message]"
no-name: "&c缺少挑战名称"
no-rank: "&c你没有等级可以做到这一点."
not-a-integer: "&c给定值“[value]”不是整数!"
not-close-enough: "&c你必须站在拥有[number]个任务需求方块的旁边."
not-deployed: "&c未开启挑战"
not-enough-items: "&c你没有足够的[items]来完成这个挑战!"
not-enough-money: "&c您的帐户必须有[value]金钱才能完成挑战。."
not-on-island: "&c你必须在你的岛上做到这一点"
not-repeatable: "&c这个挑战是不可重复的"
not-valid-integer: "&c给定整数“[value]”无效!|值应介于[min]和[max]之间。"
unique-id: '&cUniqueID "[id]" 无效.'
unknown-challenge: "&c未知挑战"
wrong-environment: "&c你在错误的环境中"
wrong-icon: "&c给定材料“[value]”无效且不能用作图标。"
you-still-need: "&c你还需要 [amount] x [item]"
not-enough-experience: "&c必须有[value]经验才能完成挑战"
no-multiple-permission: "&c你无权一次完成挑战多次"
gui:
buttons:
admin:
accept: 接受
add: 添加
add-challenge: 添加挑战
broadcast: 成功任务后发出广播
cancel: 取消
challenge-lore: 挑战介绍
challenges: 挑战
clear: 清空
complete: 完成某个玩家的挑战
complete-wipe: 抹除插件数据库!
create-challenge: 创建新的挑战
create-level: 创建新的挑战等级
decline: 拒绝
default-export: 导出现有挑战
default-import: 导入默认挑战
default-locked-icon: 等级图标锁
delete-challenge: 删除挑战
delete-level: 删除挑战等级
deployment: 是否开启该挑战
description: 介绍
edit-challenge: 编辑挑战
edit-level: 编辑挑战等级
environment: 环境
free-at-top: 免费挑战优先排列
glow: 完成任务后发光
gui-mode: 挑战GUI
gui-view-mode: 显示所有GameModes
history-store: 挑战历史
icon: 图标
increase: "+"
input: 输入
input-mode: 切换输入模式
level-lore: 等级介绍
locked-icon: 图标锁
multiply: "*"
name: 挑战名称
number: "[number]"
order: 顺序
properties: 属性
reduce: "-"
remove-blocks: 完成任务后是否删除方块
remove-challenge: 删除挑战
remove-completed: 完成任务后删除图标
remove-empty: 删除空栏
remove-entities: 完成任务后是否杀死实体
remove-experience: 完成任务后是否删除经验值
remove-items: 完成任务后是否删除物品
remove-money: 完成任务后是否删除金钱
remove-on-complete: 完成后删除该挑战
remove-selected: 删除选定
repeatable: 是否可重复挑战
repeat-count: 最大时间
repeat-reward-commands: 重复指令奖励
repeat-reward-experience: 重复经验奖励
repeat-reward-items: 重复物品奖励
repeat-reward-money: 重复金钱奖励
repeat-reward-text: 重复奖励信息
required-blocks: 检测的方块
required-entities: 检测的实体
required-experience: 需要的经验值
required-items: 需要的物品
required-level: 需要的岛屿等级
required-money: 需要的金钱
required-permissions: 需要的权限
requirements: 要求
reset: 重置某个玩家的挑战
reset-on-new: 在新的岛屿上重置
reward-commands: 指令奖励
reward-experience: 经验奖励
reward-items: 物品奖励
reward-money: 金钱奖励
rewards: 奖励
reward-text: 奖励信息
save: 保存
search-radius: 搜索半径
set: "="
settings: 编辑设定
show-eggs: 切换视图模式
title-enable: 显示标题
title-showtime: 标题显示时间
toggle-user-list: 用户列表
value:
waiver-amount: 豁免金额
import: 导入ASkyBlock挑战
line-length: 物品Lore行长度
history-lifespan: 历史生命周期
island-store: 逐岛存储
library: 网络库
download: 已下载的挑战库
challenge-wipe: 清空挑战数据库
players-wipe: 清空用户数据库
visibility-mode: 挑战可见性模式
type:
island: "&6岛屿类型"
inventory: "&6物品栏类型"
other: "&6其他类型"
next: 下一页
previous: 上一页
return: 返回上一级
value: 完成
increase: 增加
reduce: 减少
challenge-description:
completed: "&B已完成"
completed-times: 已完成 [donetimes]
completed-times-of: '完成次数: [donetimes] 上限: [maxtimes]'
environment: '所需实体:'
experience-reward: "&6经验奖励: [value]"
level: "&F挑战级别: [level]"
maxed-reached: '完成次数: [donetimes] 上限: [maxtimes]'
money-reward: "&6金钱奖励: $[value]"
not-repeatable: "&c该挑战不可重复!"
objects-close-by: "&c任务需求的方块/生物不能离你太远!(超出侦测范围)"
required-blocks: '所需方块:'
required-entities: '所需实体:'
required-experience: "&6所需经验: [value]"
required-island-level: "&6所需岛屿等级: [value]"
required-items: '所需物品:'
required-money: "&6所需金钱: $[value]"
reward-commands: "&6指令奖励:"
reward-items: "&6物品奖励:"
warning-blocks-remove: "&c完成此挑战后该挑战需要的方块将会被清空"
warning-entities-kill: "&c完成此挑战后该挑战需要的生物将会被清空"
warning-items-take: "&c完成此挑战后该挑战的需要物品将会被清空"
descriptions:
admin:
add-challenge: 将现有挑战添加到当前挑战级别
add-text-line: "&6 添加新的文本!"
broadcast: 允许/禁止,当玩家完成第一次挑战后向全服玩家广播
cancel: 取消任何操作并返回上一级菜单
challenge-lore: 修改挑战介绍的哪些目标是可见的
challenges: 管理挑战级别 (添加/删除).
click-to-edit: "&4点击此处编辑输入."
complete: 为某个玩家完成某个挑战|玩家无法获得完成奖励。
complete-wipe: 清空插件数据库中的所有挑战,包括玩家的挑战数据!
create-challenge: 添加新挑战。|默认情况下,它将在免费挑战列表中。
create-level: 添加新的挑战等级。
default-export: 将现有的挑战导出至 defaults.json 文件中.
default-import: 导入插件自带挑战
default-locked-icon: 更改默认锁定级别图标。|此级别可以覆盖此选项。
delete-challenge: 删除某个挑战
delete-level: 删除某个挑战等级
deployment: 查看某玩家已完成的挑战
description: 编辑介绍
edit-challenge: 编辑某个挑战设定
edit-level: 编辑某个挑战等级设定
edit-text-line: "&6编辑文本!"
environment: 改变挑战运作的环境。
free-at-top: 改变免费挑战的位置如果为true免费挑战会放在前排如果为false免费挑战将放在后排
glow: 允许/禁用,在已完成的挑战中加上附魔效果
gui-mode: 启用/禁用单一挑战GUI。|&2要求服务器重启。
gui-view-mode: 如果玩家输入/challenges菜单应该显示GameModes还是挑战
icon-challenge: 将在此挑战的GUI面板中显示的图标。
icon-level: 将在此级别的GUI面板中显示的图标。
import: 导入ASkyblock挑战。|右键单击它启用/禁用覆盖模式。|将Challenges.yml放在./BentoBox/addons/Challenges文件夹中。
increase: 增加操作。 单击数字将增加所选数字的值。
input: 打开文本字段输入
input-mode: 在聊天和铁砧输入模式之间切换。
island-store: 启用/禁用挑战每个岛的数据存储。如果启用此选项,整个岛屿团队的挑战进度将是相同的。|不会在点击时转换数据。进展将会失败。
level-lore: 修改挑战级别介绍的哪些目标是可见的
locked-icon: 如果级别被锁定将在GUI面板中显示的图标。
mode-in-world: 属于游戏模式中的世界的玩家.
mode-online: 目前在线的玩家
mode-with-island: 属于游戏模式中的岛屿的玩家.
multiply: 乘法运算。 单击数字会将值乘以所选数字。
name-challenge: 修改挑战名称
name-level: 修改挑战等级名称
order: 更改挑战顺序
properties: 修改常规属性
reduce: 减少操作。 单击数字将减少所选数字的值。
remove-blocks: 是否在挑战结束后删除任务需求方块(替换为空气)
remove-challenge: 从当前级别删除挑战
remove-completed: 允许/禁止,在玩家挑战列表中隐藏已完成的挑战
remove-entities: 是否在挑战结束后删除挑战需要的实体
remove-experience: 是否在玩家完成挑战后删除任务需求的经验值
remove-items: 是否在完成挑战后删除玩家背包中的挑战需求物品
remove-money: 是否在玩家完成挑战后删除任务需求的金钱.|&c需要经济前置.
remove-on-complete: 在玩家完成挑战后是否删除该挑战图标于任务面板中
remove-selected: 删除所选目标|您可以使用鼠标右键选择目标
repeatable: 挑战是否可以重复
repeat-count: 重复挑战的次数如果设置为0则为无限制
repeat-reward-experience: 重复挑战完成后的经验奖励.
repeat-reward-items: '重复挑战完成后的物品奖励.|物品:'
repeat-reward-money: 重复挑战完成后的金钱奖励.|&c需要经济前置.
repeat-reward-text: 重复挑战完成后的信息
required-blocks: 修改挑战需要的方块.|方块:|
required-entities: 修改挑战需要的实体.|实体:|
required-experience: 玩家需要有该项目所设置的经验值才可以完成挑战
required-items: '玩家背包中需要有以下物品才能完成挑战|物品:'
required-level: 玩家需要岛屿等级达到该项目所设置的等级才能完成挑战.|&c需要 Level 组件.
required-money: 玩家需要有该项目所设置的金钱才能完成挑战.|&c需要经济前置.
required-permissions: '玩家需要具有以下权限才能完成挑战|权限:'
requirements: 修改挑战需求
reset: 重置已完成的玩家挑战。|右键单击启用/禁用重置所有功能。
reset-on-new: 允许/禁止,当玩家重置/踢出岛屿后都会重置挑战
reward-commands: '设置完成任务后的指令奖励.|指令:'
reward-experience: 设置完成任务后的经验奖励.
reward-items: '设置完成任务后的物品奖励.|物品:'
rewards: 修改挑战奖励
reward-text: 设置完成任务后的奖励信息
reward-text-level: 完成某挑战级别所有挑战后发送给玩家的信息
save: 保存并返回上一级菜单
search-radius: 玩家完成挑战时检测实体/方块的范围(半径)
selected: 已选中
set: 设置操作,击数字会将值更改为所选数字。
settings: 修改组件设定
show-eggs: 在Egg模式或Head模式之间切换实体视图
title-enable: 启用/禁用玩家完成挑战时显示的标题消息。
title-showtime: 修改标题消息对玩家可见的时间。
toggle-user-list: 切换到不同的玩家列表
waiver-amount: 完成该数量的挑战玩家方能解锁下一挑战级别的挑战
reward-money: 设置完成任务后的金钱奖励.|&c需要经济前置Vault插件和Economy插件.
repeat-reward-commands: 定义挑战完成后执行的自定义命令。| ***在开始处添加 [SELF] 表示命令将由玩家执行,例如 /kill
命令等,否则将被服务器执行。|***字符串 [player] 将被系统替换为完成挑战的玩家名称,例如 /kill [player] 将变成 /kill
BONNe1704 等。|命令:
line-length: 修改每条lore的最大长度。不会影响已有物品。
history-store: 启用/禁用挑战历史存储
history-lifespan: 修改保存历史数据的天数|0表示永久
library: 打开 GUI 显示所有可用的公开挑战库
library-author: 由 &e[author] 创作
library-version: "&9创作于 [version] 版本"
library-lang: "&a语言: [lang]"
library-gamemode: "&a用于 [gamemode] 游戏模式"
lore:
level: 等级字符串 | 表示翻译 'challenges.gui.challenge-description.level'.
status: 状态字符串 | 表示翻译 'challenges.gui.challenge-description.completed'.
count: 完成计数字符串 | 表示翻译 'challenges.gui.challenge-description.completed-times', 'challenges.gui.challenge-description.completed-times-of'
和 'challenges.gui.challenge-description.maxed-reached'.
description: 描述字符串 | 在挑战对象的此处定义 - challenge.description.
warnings: '警告字符串 | 表示下列翻译: | ''challenges.gui.challenge-description.warning-items-take''
| ''challenges.gui.challenge-description.objects-close-by'' | ''challenges.gui.challenge-description.warning-entities-kill''
| ''challenges.gui.challenge-description.warning-blocks-remove''.'
environment: 环境字符串 | 于挑战对象此处定义 - challenge.environment.
requirements: '需求字符串 | 表示下列翻译: | ''challenges.gui.challenge-description.required-level''
| ''challenges.gui.challenge-description.required-money'' | ''challenges.gui.challenge-description.required-experience''
| 以及 challenge.requiredItems, challenge.requiredBlocks 或 challenge.requiredEntities.'
reward_text: 奖励文本 | 在 challenge.rewardText 和 challenge.repeatRewardText
中定义
reward_other: '其他奖励字符串 | 表示下列翻译: | ''challenges.gui.challenge-description.experience-reward''
| ''challenges.gui.challenge-description.money-reward'' | ''challenges.gui.challenge-description.not-repeatable''.'
reward_items: 奖励物品 | 在 challenge.rewardItems 和 challenge.repeatRewardItems
中定义的奖励物品
reward_commands: 奖励命令 | 在 challenge.rewardCommands 和 challenge.repeatRewardCommands
中定义的奖励命令
level_status: 状态字符串 | 表示翻译 'challenges.gui.level-description.completed'.
challenge_count: 成就完成计数器字符串. | 表示 'challenges.gui.level-description.completed-challenges-of'
的翻译
unlock_message: 解锁信息文本 | 在挑战等级对象中定义 - challengeLevel.unlockMessage.
waiver_amount: 解锁下一等级字符串的可继承的挑战计数器 | 表示翻译 'challenges.gui.level-description.waver-amount'
level_reward_text: 奖励文本 | 在 challengeLevel.rewardText 中定义
level_reward_other: '其他奖励字符串 | 表示翻译: | ''challenges.gui.level-description.experience-reward''
| ''challenges.gui.level-description.money-reward''.'
level_reward_items: 奖励物品 | 在 challengeLevel.rewardItems 中定义的物品
level_reward_commands: 奖励命令 | 在 challengeLevel.rewardCommands 中定义的完成挑战将会奖励玩家的命令
download: 允许手动升级可用的挑战库 | 右击以启用缓存清理
download-disabled: GitHub 数据下载器已在 BentoBox 中被禁用。没有它,你不能使用库!
challenge-wipe: 完全清空挑战及等级数据库!
players-wipe: 完全清空玩家数据库!
visibility-mode: 切换未发布的挑战是否应当可见
block: "- [block] : [count]"
command: "- [command]"
current-value: "|&6当前值: [value]."
disabled: 禁用
enabled: 有效
entity: "- [entity] : [count]"
item: "- [count] x [item]"
item-enchant: " - [enchant] [level]"
item-meta: " ([meta])"
level-locked: 请完成 [count] 个 [level] 级别的挑战来解锁这个挑战级别!
level-unlocked: 点击查看 [level] 级别的挑战!
nether: "- 地狱"
normal: "- 主世界"
permission: "- [permission]"
the-end: "- 末地"
increase-by: "&a为完成计数器增加 [value]"
reduce-by: "&c为完成计数器减少 [value]"
visibility:
visible: 所有挑战对任何人可见
hidden: 仅发布的挑战可见
toggleable: 切换未发布的挑战的可见性
type:
island: "&a允许获取玩家附近的方块或怪物"
inventory: "&a允许获取玩家物品栏中的物品"
other: "&a允许获取其他插件/扩展中的物品"
item-description:
armor-color: " [color]"
book-meta: " [title] by [author]"
custom-effects: " 自定义效果:"
egg-meta: " [mob]"
item: "- [count] x [item]"
item-enchant: " - [enchant] [level]"
item-lore: " 物品Lore:"
item-meta: " ([meta])"
item-name: " [name]"
potion-effect: " [effect] x [amplifier] for [duration]t"
potion-type: " [name]"
potion-type-extended: " Extended [name]"
potion-type-extended-upgraded: " [name]"
potion-type-upgraded: " Upgraded [name]"
recipe-count: " [count] recipes"
skull-owner: " [owner]"
fish-meta: "[body-color] 以 [pattern-color] [pattern]"
level-description:
completed: "&B已完成"
completed-challenges-of: "&你已经完成 [number] 个该级别的挑战,达到了 [max]个挑战."
experience-reward: "&6经验奖励: [value]"
money-reward: "&6金钱奖励: $[value]"
reward-commands: "&6指令奖励:"
reward-items: "&6物品奖励:"
waver-amount: "&6可以跳过[value] 个挑战来解锁下一个挑战级别."
questions:
prefix: "&2[SERVER]: "
admin:
number: 输入一个数字,然后按两次回车。
unique-id: 输入不重复的对象名,然后按回车。
challenge-name: 输入当前挑战的显示名称,然后按回车。
level-name: 输入当前等级的显示名称,然后按回车。
title:
admin:
choose-challenge-title: "&a选择挑战"
choose-level-title: "&a选择挑战等级"
choose-user-title: "&a选择玩家"
confirm-title: "&a确认"
edit-challenge-title: "&a编辑挑战"
edit-level-title: "&a编辑挑战等级"
edit-text-fields: "&a编辑文本字段"
manage-blocks: "&a管理方块"
manage-entities: "&a管理实体"
manage-items: "&a管理物品"
manage-numbers: "&a数字垫"
select-block: "&a选择方块"
select-challenge: "&a选择挑战"
select-entity: "&a选择实体"
settings-title: "&a编辑设定"
toggle-environment: "&a切换环境"
gui-title: "&a挑战管理"
library-title: "&a可下载的库"
lore-add: "&a添加物品Lore"
lore-remove: "&a移除物品Lore"
lore-edit: "&a编辑物品Lore"
type-select: "&a选择挑战类型"
challenges: "&6挑战"
game-modes: "&6选择游戏模式"
multiple-complete: "&6多少次"
messages:
admin:
already-completed: "&2这个挑战已经完成"
challenge-created: "[challenge]&r created!"
completed: "&2已为[player]完成挑战[name]!"
complete-wipe: "&c希望你有备份因为你已经创建了所有Challenges Addon数据库"
hit-things: 点击物品将它们添加到所需的事物列表中。 完成后右键单击。
you-added: 你在挑战中添加了一个[thing]
reset: "&2你刚重设了 [player] 的 [name] 挑战!"
reset-all: "&2[player] 的所有挑战都被你重设了!"
not-completed: "&2这个挑战还没完成呢!"
migrate-start: "&2开始迁移挑战扩展数据."
migrate-end: "&2挑战扩展数据已迁移到新格式."
migrate-not: "&2数据全部有效."
start-downloading: "&5开始下载并导入挑战库"
challenge-wipe: "&c希望你已做好备份因你刚刚从数据库中删除了所有的挑战和等级"
players-wipe: "&c希望你已做好备份因你刚刚从数据库中删除了所有玩家已完成的挑战"
defaults-file-completed: defaults.json文件填充了来自[world]的挑战!
defaults-file-overwrite: defaults.json存在。 它将被覆盖。
import-challenges: 开始导入挑战
import-levels: 开始导入挑战级别
import-number: 导入 [number] 个挑战
load-add: '添加新的对象: [value]'
load-overwriting: 覆盖 "[value]"
load-skipping: '"[value]" 已存在 - 跳过'
name-has-completed-challenge: "&5[name] 已完成 [value] &r&5挑战!"
name-has-completed-level: "&5[name] 已完成 [value] &r&5挑战级别!"
no-levels: '警告: challenges.yml文件中没有定义挑战级别'
you-completed-challenge: "&2你已经完成了 [value] &r&2挑战!"
you-completed-level: "&2你完成了 [value] &r&2级别!"
you-repeated-challenge: "&2你已经重复完成了 [value] &r&2挑战!"
you-repeated-challenge-multiple: "&2你重复完成了 [value] &r&2挑战 [count] 次!"
titles:
challenge-subtitle: "[friendlyName]"
challenge-title: 完成挑战
level-subtitle: "[friendlyName]"
level-title: 成功挑战级别
protection:
flags:
CHALLENGES_ISLAND_PROTECTION:
description: "&5&o切换谁可以\n&5&o挖槽挑战"
name: "挑战保护"
CHALLENGES_WORLD_PROTECTION:
description: "&5&o为玩家启用/禁用\n&5&o要求他们在他们的岛屿上\n&5&o才能完成挑战."
name: "挑战岛屿限制"
hint: "请在自己的岛屿完成挑战!"
flags:
CHALLENGES_ISLAND_PROTECTION:
name: 挑战保护
description: |-
&5&o切换谁可以
&5&o完成挑战
CHALLENGES_WORLD_PROTECTION:
description: |-
&5&o为玩家启用/禁用
&5&o要求他们在他们的岛屿上
&5&o才能完成挑战.
hint: 请在自己的岛屿完成挑战!
name: 挑战岛屿限制
version: 11
meta:
authors:
- BONNe

View File

@ -1,117 +1,421 @@
/**
*
*/
package world.bentobox.challenges;
import static org.mockito.Matchers.any;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.HashMap;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.UnsafeValues;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.PluginManager;
import org.bukkit.potion.PotionData;
import org.bukkit.potion.PotionType;
import org.junit.BeforeClass;
import org.bukkit.scheduler.BukkitScheduler;
import org.eclipse.jdt.annotation.NonNull;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.Challenge.ChallengeType;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.Addon.State;
import world.bentobox.bentobox.api.addons.AddonDescription;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.configuration.Config;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.AddonsManager;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.FlagsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.PlaceholdersManager;
/**
* @author tastybento
*
*/
@SuppressWarnings("deprecation")
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class, User.class, Config.class })
public class ChallengesAddonTest {
@Mock
private User user;
@Mock
private IslandsManager im;
@Mock
private Island island;
private ChallengesAddon addon;
@Mock
private BentoBox plugin;
@Mock
private FlagsManager fm;
@Mock
private Settings settings;
@Mock
private GameModeAddon gameMode;
@Mock
private AddonsManager am;
@Mock
private BukkitScheduler scheduler;
@Mock
private PlaceholdersManager phm;
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
@Before
public void setUp() throws Exception {
// Set up plugin
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
when(plugin.getLogger()).thenReturn(Logger.getAnonymousLogger());
//when(plugin.isEnabled()).thenReturn(true);
// Command manager
CommandsManager cm = mock(CommandsManager.class);
when(plugin.getCommandsManager()).thenReturn(cm);
// Placeholders manager
when(plugin.getPlaceholdersManager()).thenReturn(phm);
// Player
Player p = mock(Player.class);
// Sometimes use Mockito.withSettings().verboseLogging()
when(user.isOp()).thenReturn(false);
UUID uuid = UUID.randomUUID();
when(user.getUniqueId()).thenReturn(uuid);
when(user.getPlayer()).thenReturn(p);
when(user.getName()).thenReturn("tastybento");
User.setPlugin(plugin);
// Island World Manager
IslandWorldManager iwm = mock(IslandWorldManager.class);
when(plugin.getIWM()).thenReturn(iwm);
// Player has island to begin with
island = mock(Island.class);
when(im.getIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(island);
when(plugin.getIslands()).thenReturn(im);
// Locales
// Return the reference (USE THIS IN THE FUTURE)
when(user.getTranslation(Mockito.anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
// Server
PowerMockito.mockStatic(Bukkit.class);
Server server = mock(Server.class);
World world = mock(World.class);
world = mock(World.class);
Mockito.when(server.getLogger()).thenReturn(Logger.getAnonymousLogger());
Mockito.when(server.getWorld("world")).thenReturn(world);
Mockito.when(server.getVersion()).thenReturn("BSB_Mocking");
PluginManager pluginManager = mock(PluginManager.class);
when(server.getPluginManager()).thenReturn(pluginManager);
ItemFactory itemFactory = mock(ItemFactory.class);
when(server.getItemFactory()).thenReturn(itemFactory);
Bukkit.setServer(server);
PotionMeta potionMeta = mock(PotionMeta.class);
when(itemFactory.getItemMeta(any())).thenReturn(potionMeta);
OfflinePlayer offlinePlayer = mock(OfflinePlayer.class);
when(Bukkit.getOfflinePlayer(any(UUID.class))).thenReturn(offlinePlayer);
when(offlinePlayer.getName()).thenReturn("tastybento");
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
when(Bukkit.getServer()).thenReturn(server);
when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
when(Bukkit.getPluginManager()).thenReturn(mock(PluginManager.class));
// Addon
addon = new ChallengesAddon();
File jFile = new File("addon.jar");
List<String> lines = Arrays.asList("# ChallengesAddon Configuration", "uniqueId: config");
Path path = Paths.get("config.yml");
Files.write(path, lines, Charset.forName("UTF-8"));
try (JarOutputStream tempJarOutputStream = new JarOutputStream(new FileOutputStream(jFile))) {
//Added the new files to the jar.
try (FileInputStream fis = new FileInputStream(path.toFile())) {
byte[] buffer = new byte[1024];
int bytesRead = 0;
JarEntry entry = new JarEntry(path.toString());
tempJarOutputStream.putNextEntry(entry);
while((bytesRead = fis.read(buffer)) != -1) {
tempJarOutputStream.write(buffer, 0, bytesRead);
}
}
}
File dataFolder = new File("addons/Challenges");
addon.setDataFolder(dataFolder);
addon.setFile(jFile);
AddonDescription desc = new AddonDescription.Builder("bentobox", "challenges", "1.3").description("test").authors("BONNe").build();
addon.setDescription(desc);
// Addons manager
when(plugin.getAddonsManager()).thenReturn(am);
// One game mode
when(am.getGameModeAddons()).thenReturn(Collections.singletonList(gameMode));
AddonDescription desc2 = new AddonDescription.Builder("bentobox", "BSkyBlock", "1.3").description("test").authors("tasty").build();
when(gameMode.getDescription()).thenReturn(desc2);
// Player command
CompositeCommand cmd = mock(CompositeCommand.class);
@NonNull
Optional<CompositeCommand> opCmd = Optional.of(cmd);
when(gameMode.getPlayerCommand()).thenReturn(opCmd);
// Admin command
when(gameMode.getAdminCommand()).thenReturn(opCmd);
// Flags manager
when(plugin.getFlagsManager()).thenReturn(fm);
when(fm.getFlags()).thenReturn(Collections.emptyList());
// The database type has to be created one line before the thenReturn() to work!
when(plugin.getSettings()).thenReturn(settings);
DatabaseType value = DatabaseType.JSON;
when(settings.getDatabaseType()).thenReturn(value);
// Bukkit
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getScheduler()).thenReturn(scheduler);
ItemMeta meta = mock(ItemMeta.class);
ItemFactory itemFactory = mock(ItemFactory.class);
when(itemFactory.getItemMeta(any())).thenReturn(meta);
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
UnsafeValues unsafe = mock(UnsafeValues.class);
when(unsafe.getDataVersion()).thenReturn(777);
when(Bukkit.getUnsafe()).thenReturn(unsafe);
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
new File("addon.jar").delete();
new File("config.yml").delete();
deleteAll(new File("addons"));
deleteAll(new File("database"));
}
private void deleteAll(File file) throws IOException {
if (file.exists()) {
Files.walk(file.toPath())
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
}
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#onLoad()}.
*/
@Test
public void test() {
public void testOnLoad() {
addon.onLoad();
// Check that config.yml file has been saved
File check = new File("addons/Challenges","config.yml");
assertTrue(check.exists());
}
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Challenge challenges = new Challenge();
challenges.setChallengeType(ChallengeType.ISLAND);
Map<Material, Integer> map = new HashMap<>();
map.put(Material.DIRT, 5);
map.put(Material.ACACIA_FENCE_GATE, 3);
challenges.setRequiredBlocks(map);
challenges.setIcon(new ItemStack(Material.ACACIA_FENCE_GATE));
List<ItemStack> requiredItems = new ArrayList<>();
ItemStack result = new ItemStack(Material.POTION, 55);
ItemStack result2 = new ItemStack(Material.SPLASH_POTION, 22);
ItemStack result3 = new ItemStack(Material.LINGERING_POTION, 11);
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#onEnable()}.
*/
@Test
public void testOnEnableDisabledPlugin() {
when(plugin.isEnabled()).thenReturn(false);
addon.onEnable();
verify(plugin).logError("[challenges] BentoBox is not available or disabled!");
assertEquals(Addon.State.DISABLED, addon.getState());
}
PotionMeta potionMeta = (PotionMeta) result.getItemMeta();
PotionData potionData = new PotionData(PotionType.FIRE_RESISTANCE, true, false);
potionMeta.setBasePotionData(potionData);
result.setItemMeta(potionMeta);
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#onEnable()}.
*/
@Test
public void testOnEnableDisabledAddon() {
when(plugin.isEnabled()).thenReturn(true);
addon.setState(State.DISABLED);
addon.onEnable();
verify(plugin).logError("[challenges] Challenges Addon is not available or disabled!");
}
PotionMeta potionMeta2 = (PotionMeta) result2.getItemMeta();
PotionData potionData2 = new PotionData(PotionType.SPEED, true, false);
potionMeta2.setBasePotionData(potionData2);
potionMeta2.addEnchant(Enchantment.BINDING_CURSE, 1, true);
result2.setItemMeta(potionMeta2);
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#onEnable()}.
*/
@Test
public void testOnEnableIncompatibleDatabase() {
// The database type has to be created one line before the thenReturn() to work!
DatabaseType value = DatabaseType.YAML;
when(settings.getDatabaseType()).thenReturn(value);
when(plugin.isEnabled()).thenReturn(true);
addon.setState(State.LOADED);
addon.onEnable();
verify(plugin).logError("[challenges] BentoBox database is not compatible with Challenges Addon.");
verify(plugin).logError("[challenges] Please use JSON based database type.");
assertEquals(State.INCOMPATIBLE, addon.getState());
}
requiredItems.add(result);
requiredItems.add(result2);
requiredItems.add(result3);
challenges.setRequiredItems(requiredItems);
String json = gson.toJson(challenges);
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#onEnable()}.
*/
@Test
public void testOnEnableHooked() {
addon.onLoad();
when(plugin.isEnabled()).thenReturn(true);
addon.setState(State.LOADED);
addon.onEnable();
verify(plugin).logWarning("[challenges] Level add-on not found so level challenges will not work!");
verify(plugin).logWarning("[challenges] Economy plugin not found so money options will not work!");
verify(plugin).log("[challenges] Loading challenges...");
verify(plugin, never()).logError("Challenges could not hook into AcidIsland or BSkyBlock so will not do anything!");
Logger.getAnonymousLogger().info(json);
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#onEnable()}.
*/
@Test
public void testOnEnableNotHooked() {
addon.onLoad();
when(am.getGameModeAddons()).thenReturn(Collections.emptyList());
when(plugin.isEnabled()).thenReturn(true);
addon.setState(State.LOADED);
addon.onEnable();
verify(plugin).log("[challenges] Loading challenges...");
verify(plugin).logError("[challenges] Challenges could not hook into AcidIsland or BSkyBlock so will not do anything!");
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#onReload()}.
*/
@Test
public void testOnReloadNotHooked() {
addon.onReload();
verify(plugin, never()).log(anyString());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#onDisable()}.
*/
@Test
public void testOnDisable() {
this.testOnEnableHooked();
addon.onDisable();
// Verify database saved exists
File chDir = new File("database", "Challenge");
assertTrue(chDir.exists());
File lvDir = new File("database", "ChallengeLevel");
assertTrue(lvDir.exists());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#getChallengesManager()}.
*/
@Test
public void testGetChallengesManager() {
assertNull(addon.getChallengesManager());
this.testOnEnableHooked();
assertNotNull(addon.getChallengesManager());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#getPermissionPrefix()}.
*/
@Test
public void testGetPermissionPrefix() {
assertEquals("addon.", addon.getPermissionPrefix());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#getImportManager()}.
*/
@Test
public void testGetImportManager() {
assertNull(addon.getImportManager());
this.testOnEnableHooked();
assertNotNull(addon.getImportManager());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#getWebManager()}.
*/
@Test
public void testGetWebManager() {
assertNull(addon.getWebManager());
this.testOnEnableHooked();
assertNotNull(addon.getWebManager());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#getChallengesSettings()}.
*/
@Test
public void testGetChallengesSettings() {
assertNull(addon.getChallengesSettings());
addon.onLoad();
assertNotNull(addon.getChallengesSettings());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#isEconomyProvided()}.
*/
@Test
public void testIsEconomyProvided() {
assertFalse(addon.isEconomyProvided());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#getEconomyProvider()}.
*/
@Test
public void testGetEconomyProvider() {
assertNull(addon.getEconomyProvider());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#isLevelProvided()}.
*/
@Test
public void testIsLevelProvided() {
assertFalse(addon.isLevelProvided());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesAddon#getLevelAddon()}.
*/
@Test
public void testGetLevelAddon() {
assertNull(addon.getLevelAddon());
}
}

View File

@ -0,0 +1,868 @@
package world.bentobox.challenges;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.UnsafeValues;
import org.bukkit.World;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.PluginManager;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.AddonDescription;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.PlaceholdersManager;
import world.bentobox.bentobox.util.Util;
import world.bentobox.challenges.config.Settings;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.Challenge.ChallengeType;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.events.ChallengeCompletedEvent;
import world.bentobox.challenges.events.ChallengeResetAllEvent;
import world.bentobox.challenges.events.ChallengeResetEvent;
import world.bentobox.challenges.events.LevelCompletedEvent;
import world.bentobox.challenges.utils.LevelStatus;
/**
* @author tastybento
*
*/
@SuppressWarnings("deprecation")
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class, Util.class})
public class ChallengesManagerTest {
// Constants
private static final String GAME_MODE_NAME = "BSkyBlock";
// Mocks
@Mock
private ChallengesAddon addon;
@Mock
private Settings settings;
@Mock
private IslandWorldManager iwm;
@Mock
private Server server;
@Mock
private PluginManager pim;
@Mock
private ItemFactory itemFactory;
@Mock
private User user;
@Mock
private World world;
@Mock
private GameModeAddon gameModeAddon;
@Mock
private PlaceholdersManager plhm;
// Variable fields
private ChallengesManager cm;
private File database;
private String uuid;
private Challenge challenge;
private @NonNull ChallengeLevel level;
private UUID playerID = UUID.randomUUID();
private String cName;
private String levelName;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
// Set up plugin
BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
when(addon.getPlugin()).thenReturn(plugin);
// IWM
when(plugin.getIWM()).thenReturn(iwm);
when(iwm.inWorld(any(World.class))).thenReturn(true);
// Placeholders
when(plugin.getPlaceholdersManager()).thenReturn(plhm);
// Settings for Database
world.bentobox.bentobox.Settings s = mock(world.bentobox.bentobox.Settings.class);
when(plugin.getSettings()).thenReturn(s);
when(s.getDatabaseType()).thenReturn(DatabaseType.JSON);
// Addon Settings
when(addon.getChallengesSettings()).thenReturn(settings);
when(settings.isStoreHistory()).thenReturn(true);
when(settings.getLifeSpan()).thenReturn(10);
// Database
database = new File("database");
tearDown();
// Bukkit
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getServer()).thenReturn(server);
when(Bukkit.getPluginManager()).thenReturn(pim);
when(Bukkit.getWorld(anyString())).thenReturn(world);
ItemMeta meta = mock(ItemMeta.class);
when(itemFactory.getItemMeta(any())).thenReturn(meta);
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
UnsafeValues unsafe = mock(UnsafeValues.class);
when(unsafe.getDataVersion()).thenReturn(777);
when(Bukkit.getUnsafe()).thenReturn(unsafe);
// Challenge
challenge = new Challenge();
uuid = UUID.randomUUID().toString();
challenge.setUniqueId(GAME_MODE_NAME + "_" + uuid);
challenge.setFriendlyName("name");
challenge.setLevel(GAME_MODE_NAME + "_novice");
challenge.setDescription(Collections.singletonList("A description"));
// Challenge Level
level = new ChallengeLevel();
levelName = GAME_MODE_NAME + "_novice";
level.setUniqueId(levelName);
level.setFriendlyName("Novice");
// User
when(user.getUniqueId()).thenReturn(playerID);
// Util
PowerMockito.mockStatic(Util.class);
when(Util.getWorld(any())).thenReturn(world);
// Addon
AddonDescription desc = new AddonDescription.Builder("main", GAME_MODE_NAME, "1.0").build();
when(gameModeAddon.getDescription()).thenReturn(desc);
Optional<GameModeAddon> opAddon = Optional.of(gameModeAddon);
when(iwm.getAddon(any())).thenReturn(opAddon);
// Challenge name
cName = GAME_MODE_NAME + "_" + uuid;
// Class under test
cm = new ChallengesManager(addon);
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
// Clean up JSON database
// Clean up file system
if (database.exists()) {
Files.walk(database.toPath())
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
}
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#load()}.
* @throws InterruptedException
*/
@Test
public void testLoad() throws InterruptedException {
verify(addon).log("Loading challenges...");
verify(addon, never()).logError(anyString());
this.testSaveLevel();
this.testSaveChallenge();
cm.load();
verify(addon, times(2)).log("Loading challenges...");
verify(addon, never()).logError(anyString());
assertTrue(cm.containsChallenge(cName));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#reload()}.
* @throws InterruptedException
*/
@Test
public void testReload() throws InterruptedException {
cm.reload();
verify(addon).log("Reloading challenges...");
this.testSaveLevel();
this.testSaveChallenge();
cm.reload();
verify(addon, times(2)).log("Reloading challenges...");
verify(addon, never()).logError(anyString());
assertTrue(cm.containsChallenge(cName));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/
@Test
public void testLoadChallengeNoOverwriteSilent() {
// load once
assertTrue(cm.loadChallenge(challenge, false, user, true));
// load twice - no overwrite
assertFalse(cm.loadChallenge(challenge, false, user, true));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/
@Test
public void testLoadChallengeNoOverwriteNotSilent() {
// load once
assertTrue(cm.loadChallenge(challenge, false, user, true));
// load twice - no overwrite, not silent
assertFalse(cm.loadChallenge(challenge, false, user, false));
verify(user).sendMessage("challenges.messages.load-skipping", "[value]", "name");
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/
@Test
public void testLoadChallengeOverwriteSilent() {
// load once
assertTrue(cm.loadChallenge(challenge, false, user, true));
// overwrite
assertTrue(cm.loadChallenge(challenge, true, user, true));
verify(user, never()).sendMessage(anyString(), anyString(), anyString());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/
@Test
public void testLoadChallengeOverwriteNotSilent() {
// load once
assertTrue(cm.loadChallenge(challenge, false, user, true));
// overwrite not silent
assertTrue(cm.loadChallenge(challenge, true, user, false));
verify(user).sendMessage("challenges.messages.load-overwriting", "[value]", "name");
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/
@Test
public void testLoadLevelNoOverwriteSilent() {
// load once
assertTrue(cm.loadLevel(level, false, user, true));
// load twice - no overwrite
assertFalse(cm.loadLevel(level, false, user, true));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/
@Test
public void testLoadLevelNoOverwriteNotSilent() {
// load once
assertTrue(cm.loadLevel(level, false, user, true));
// load twice - no overwrite, not silent
assertFalse(cm.loadLevel(level, false, user, false));
verify(user).sendMessage("challenges.messages.load-skipping", "[value]", "Novice");
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/
@Test
public void testLoadLevelOverwriteSilent() {
// load once
assertTrue(cm.loadLevel(level, false, user, true));
// overwrite
assertTrue(cm.loadLevel(level, true, user, true));
verify(user, never()).sendMessage(anyString(), anyString(), anyString());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
*/
@Test
public void testLoadLevelOverwriteNotSilent() {
// load once
assertTrue(cm.loadLevel(level, false, user, true));
// overwrite not silent
assertTrue(cm.loadLevel(level, true, user, false));
verify(user).sendMessage("challenges.messages.load-overwriting", "[value]", "Novice");
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#removeFromCache(java.util.UUID)}.
*/
@Test
public void testRemoveFromCache() {
cm.removeFromCache(playerID);
verify(settings).isStoreAsIslandData();
// TODO there should be a test where isStoreAsIslandData returns true
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#wipeDatabase(boolean)}.
* @throws InterruptedException
*/
@Test
public void testWipeDatabase() throws InterruptedException {
// Create some database
this.testLoad();
// Verify file exists
File chDir = new File(database, "Challenge");
File check = new File(chDir, cName + ".json");
assertTrue(check.exists());
File lvDir = new File(database, "ChallengeLevel");
File checkLv = new File(lvDir, levelName + ".json");
assertTrue(checkLv.exists());
cm.setChallengeComplete(user, world, challenge, 20);
//cm.save();
File plData = new File(database, "ChallengesPlayerData");
File checkPd = new File(plData, playerID.toString() + ".json");
assertTrue(checkPd.exists());
// Wipe it
cm.wipeDatabase(false);
// Verify
assertFalse(check.exists());
assertFalse(checkLv.exists());
assertTrue(checkPd.exists());
cm.wipeDatabase(true);
assertFalse(checkPd.exists());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#wipePlayers()}.
* @throws InterruptedException
*/
@Test
public void testWipePlayers() throws InterruptedException {
this.testLoad();
cm.setChallengeComplete(user, world, challenge, 20);
cm.save();
File plData = new File(database, "ChallengesPlayerData");
File checkLv = new File(plData, playerID.toString() + ".json");
assertTrue(checkLv.exists());
cm.wipePlayers();
assertFalse(checkLv.exists());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#migrateDatabase(world.bentobox.bentobox.api.user.User, org.bukkit.World)}.
*/
@Test
public void testMigrateDatabase() {
cm.migrateDatabase(user, world);
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#save()}.
*/
@Test
public void testSave() {
cm.save();
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#saveChallenge(world.bentobox.challenges.database.object.Challenge)}.
* @throws InterruptedException
*/
@Test
public void testSaveChallenge() throws InterruptedException {
// Async - may not happen quickly
cm.saveChallenge(challenge);
Thread.sleep(500);
File chDir = new File(database, "Challenge");
assertTrue(chDir.exists());
File check = new File(chDir, cName + ".json");
assertTrue(check.exists());
// Remove icon becauseit has mockito meta in it
removeLine(check);
}
private boolean removeLine(File inputFile) {
File tempFile = new File("myTempFile.json");
try (BufferedReader reader = new BufferedReader(new FileReader(inputFile))) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))) {
String lineToRemove = "\"icon";
String currentLine;
while((currentLine = reader.readLine()) != null) {
// trim newline when comparing with lineToRemove
String trimmedLine = currentLine.trim();
if(trimmedLine.startsWith(lineToRemove)) continue;
writer.write(currentLine + System.getProperty("line.separator"));
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return tempFile.renameTo(inputFile);
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#saveLevel(world.bentobox.challenges.database.object.ChallengeLevel)}.
* @throws InterruptedException
*/
@Test
public void testSaveLevel() throws InterruptedException {
cm.saveLevel(level);
Thread.sleep(500);
File chDir = new File(database, "ChallengeLevel");
assertTrue(chDir.exists());
File check = new File(chDir, GAME_MODE_NAME + "_novice.json");
assertTrue(check.exists());
// Remove icon becauseit has mockito meta in it
removeLine(check);
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#isChallengeComplete(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.Challenge)}.
*/
@Test
public void testIsChallengeCompleteUserWorldChallenge() {
assertFalse(cm.isChallengeComplete(user, world, challenge));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#isChallengeComplete(java.util.UUID, org.bukkit.World, world.bentobox.challenges.database.object.Challenge)}.
*/
@Test
public void testIsChallengeCompleteUUIDWorldChallenge() {
assertFalse(cm.isChallengeComplete(playerID, world, challenge));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#isChallengeComplete(java.util.UUID, org.bukkit.World, java.lang.String)}.
*/
@Test
public void testIsChallengeCompleteUUIDWorldString() {
assertFalse(cm.isChallengeComplete(playerID, world, "Novice"));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#setChallengeComplete(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.Challenge, int)}.
*/
@Test
public void testSetChallengeCompleteUserWorldChallengeInt() {
cm.setChallengeComplete(user, world, challenge, 3);
assertTrue(cm.isChallengeComplete(user, world, challenge));
verify(pim).callEvent(any(ChallengeCompletedEvent.class));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#setChallengeComplete(java.util.UUID, org.bukkit.World, world.bentobox.challenges.database.object.Challenge, int)}.
*/
@Test
public void testSetChallengeCompleteUUIDWorldChallengeInt() {
cm.setChallengeComplete(playerID, world, challenge, 3);
assertTrue(cm.isChallengeComplete(playerID, world, challenge));
verify(pim).callEvent(any(ChallengeCompletedEvent.class));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#setChallengeComplete(java.util.UUID, org.bukkit.World, world.bentobox.challenges.database.object.Challenge, java.util.UUID)}.
*/
@Test
public void testSetChallengeCompleteUUIDWorldChallengeUUID() {
UUID adminID = UUID.randomUUID();
cm.setChallengeComplete(playerID, world, challenge, adminID);
assertTrue(cm.isChallengeComplete(playerID, world, challenge));
verify(pim).callEvent(any(ChallengeCompletedEvent.class));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#resetChallenge(java.util.UUID, org.bukkit.World, world.bentobox.challenges.database.object.Challenge, java.util.UUID)}.
*/
@Test
public void testResetChallenge() {
cm.setChallengeComplete(user, world, challenge, 3);
assertTrue(cm.isChallengeComplete(user, world, challenge));
cm.resetChallenge(playerID, world, challenge, playerID);
assertFalse(cm.isChallengeComplete(user, world, challenge));
verify(pim).callEvent(any(ChallengeResetEvent.class));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#resetAllChallenges(world.bentobox.bentobox.api.user.User, org.bukkit.World)}.
*/
@Test
public void testResetAllChallengesUserWorld() {
cm.setChallengeComplete(user, world, challenge, 3);
assertTrue(cm.isChallengeComplete(user, world, challenge));
cm.resetAllChallenges(user, world);
assertFalse(cm.isChallengeComplete(user, world, challenge));
verify(pim).callEvent(any(ChallengeResetAllEvent.class));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#resetAllChallenges(java.util.UUID, org.bukkit.World, java.util.UUID)}.
*/
@Test
public void testResetAllChallengesUUIDWorldUUID() {
cm.setChallengeComplete(user, world, challenge, 3);
assertTrue(cm.isChallengeComplete(user, world, challenge));
cm.resetAllChallenges(playerID, world, playerID);
assertFalse(cm.isChallengeComplete(user, world, challenge));
verify(pim).callEvent(any(ChallengeResetAllEvent.class));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#getChallengeTimes(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.Challenge)}.
*/
@Test
public void testGetChallengeTimesUserWorldChallenge() {
assertEquals(0L, cm.getChallengeTimes(user, world, challenge));
cm.setChallengeComplete(user, world, challenge, 6);
assertEquals(6L, cm.getChallengeTimes(user, world, challenge));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#getChallengeTimes(world.bentobox.bentobox.api.user.User, org.bukkit.World, java.lang.String)}.
*/
@Test
public void testGetChallengeTimesUserWorldString() {
assertEquals(0L, cm.getChallengeTimes(user, world, cName));
cm.setChallengeComplete(user, world, challenge, 6);
assertEquals(6L, cm.getChallengeTimes(user, world, cName));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#isLevelCompleted(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.ChallengeLevel)}.
*/
@Test
public void testIsLevelCompleted() {
assertFalse(cm.isLevelCompleted(user, world, level));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#isLevelUnlocked(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.ChallengeLevel)}.
*/
@Test
public void testIsLevelUnlocked() {
assertFalse(cm.isLevelUnlocked(user, world, level));
this.testLoadLevelNoOverwriteSilent();
assertTrue(cm.isLevelUnlocked(user, world, level));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#setLevelComplete(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.ChallengeLevel)}.
*/
@Test
public void testSetLevelComplete() {
assertFalse(cm.isLevelCompleted(user, world, level));
cm.setLevelComplete(user, world, level);
assertTrue(cm.isLevelCompleted(user, world, level));
verify(pim).callEvent(any(LevelCompletedEvent.class));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#validateLevelCompletion(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.ChallengeLevel)}.
*/
@Test
public void testValidateLevelCompletion() {
assertTrue(cm.validateLevelCompletion(user, world, level));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#getChallengeLevelStatus(java.util.UUID, org.bukkit.World, world.bentobox.challenges.database.object.ChallengeLevel)}.
*/
@Test
public void testGetChallengeLevelStatus() {
this.testLoadLevelNoOverwriteSilent();
LevelStatus cls = cm.getChallengeLevelStatus(playerID, world, level);
assertTrue(cls.getNumberOfChallengesStillToDo() == 0);
assertEquals(level, cls.getLevel());
assertTrue(cls.isComplete());
assertTrue(cls.isUnlocked());
assertEquals("BSkyBlock_novice", cls.getLevel().getUniqueId());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#getAllChallengeLevelStatus(world.bentobox.bentobox.api.user.User, org.bukkit.World)}.
*/
@Test
public void testGetAllChallengeLevelStatus() {
this.testLoadLevelNoOverwriteSilent();
List<LevelStatus> list = cm.getAllChallengeLevelStatus(user, world);
assertTrue(list.size() == 1);
LevelStatus cls = list.get(0);
assertTrue(cls.getNumberOfChallengesStillToDo() == 0);
assertEquals(level, cls.getLevel());
assertTrue(cls.isComplete());
assertTrue(cls.isUnlocked());
assertEquals("BSkyBlock_novice", cls.getLevel().getUniqueId());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#getAllChallengesNames(org.bukkit.World)}.
*/
@Test
public void testGetAllChallengesNames() {
assertTrue(cm.getAllChallengesNames(world).isEmpty());
cm.saveChallenge(challenge);
cm.loadChallenge(challenge, false, user, true);
List<String> list = cm.getAllChallengesNames(world);
assertFalse(list.isEmpty());
assertEquals(cName, list.get(0));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#getAllChallenges(org.bukkit.World)}.
*/
@Test
public void testGetAllChallenges() {
assertTrue(cm.getAllChallenges(world).isEmpty());
cm.saveChallenge(challenge);
cm.loadChallenge(challenge, false, user, true);
List<Challenge> list = cm.getAllChallenges(world);
assertFalse(list.isEmpty());
assertEquals(challenge, list.get(0));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#getFreeChallenges(org.bukkit.World)}.
*/
@Test
public void testGetFreeChallenges() {
// Empty
assertTrue(cm.getFreeChallenges(world).isEmpty());
// One normal
cm.saveChallenge(challenge);
cm.loadChallenge(challenge, false, user, true);
assertTrue(cm.getFreeChallenges(world).isEmpty());
// One free
challenge.setLevel("");
cm.saveChallenge(challenge);
cm.loadChallenge(challenge, false, user, true);
List<Challenge> list = cm.getFreeChallenges(world);
assertFalse(list.isEmpty());
assertEquals(challenge, list.get(0));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#getLevelChallenges(world.bentobox.challenges.database.object.ChallengeLevel)}.
* @throws InterruptedException
*/
@Test
public void testGetLevelChallenges() throws InterruptedException {
assertTrue(cm.getLevelChallenges(level).isEmpty());
// make some challenges
this.testSaveLevel();
this.testSaveChallenge();
level.setChallenges(Collections.singleton(challenge.getUniqueId()));
// Test again
List<Challenge> list = cm.getLevelChallenges(level);
assertFalse(list.isEmpty());
assertEquals(challenge, list.get(0));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#getChallenge(java.lang.String)}.
* @throws InterruptedException
*/
@Test
public void testGetChallenge() throws InterruptedException {
assertNull(cm.getChallenge(cName));
this.testSaveLevel();
this.testSaveChallenge();
Challenge ch = cm.getChallenge(cName);
assertNotNull(ch);
assertEquals(cName, ch.getUniqueId());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#containsChallenge(java.lang.String)}.
*/
@Test
public void testContainsChallenge() {
assertFalse(cm.containsChallenge("no-such-challenge"));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#createChallenge(java.lang.String, world.bentobox.challenges.database.object.Challenge.ChallengeType, world.bentobox.challenges.database.object.requirements.Requirements)}.
*/
@Test
public void testCreateChallenge() {
@Nullable
Challenge ch = cm.createChallenge("newChal", ChallengeType.ISLAND, null);
assertEquals(ChallengeType.ISLAND, ch.getChallengeType());
assertEquals("newChal", ch.getUniqueId());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#deleteChallenge(world.bentobox.challenges.database.object.Challenge)}.
* @throws InterruptedException
*/
@Test
public void testDeleteChallenge() throws InterruptedException {
this.testSaveLevel();
this.testSaveChallenge();
Challenge ch = cm.getChallenge(cName);
assertNotNull(ch);
assertEquals(cName, ch.getUniqueId());
cm.deleteChallenge(challenge);
ch = cm.getChallenge(cName);
assertNull(ch);
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#getLevels(org.bukkit.World)}.
*/
@Test
public void testGetLevels() {
this.testGetLevelString();
List<ChallengeLevel> lvs = cm.getLevels(world);
assertFalse(lvs.isEmpty());
assertEquals(level, lvs.get(0));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#getLevel(world.bentobox.challenges.database.object.Challenge)}.
*/
@Test
public void testGetLevelChallenge() {
this.testGetLevelString();
assertEquals(level, cm.getLevel(challenge));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#getLevel(java.lang.String)}.
*/
@Test
public void testGetLevelString() {
assertNull(cm.getLevel("dss"));
cm.saveLevel(level);
cm.loadLevel(level, false, user, true);
assertEquals(level, cm.getLevel(levelName));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#containsLevel(java.lang.String)}.
*/
@Test
public void testContainsLevel() {
this.testGetLevelString();
assertFalse(cm.containsLevel("sdsd"));
assertTrue(cm.containsLevel(levelName));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#addChallengeToLevel(world.bentobox.challenges.database.object.Challenge, world.bentobox.challenges.database.object.ChallengeLevel)}.
* @throws InterruptedException
*/
@Test
public void testAddChallengeToLevel() throws InterruptedException {
this.testLoad();
cm.deleteChallenge(challenge);
assertFalse(cm.containsChallenge(cName));
cm.addChallengeToLevel(challenge, level);
assertEquals(level, cm.getLevel(challenge));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#removeChallengeFromLevel(world.bentobox.challenges.database.object.Challenge, world.bentobox.challenges.database.object.ChallengeLevel)}.
* @throws InterruptedException
*/
@Test
public void testRemoveChallengeFromLevel() throws InterruptedException {
this.testAddChallengeToLevel();
cm.removeChallengeFromLevel(challenge, level);
assertFalse(cm.containsChallenge(cName));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#createLevel(java.lang.String, org.bukkit.World)}.
*/
@Test
public void testCreateLevel() {
@Nullable
ChallengeLevel cl = cm.createLevel("Expert", world);
assertEquals("Expert", cl.getUniqueId());
assertEquals(world.getName(), cl.getWorld());
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#deleteChallengeLevel(world.bentobox.challenges.database.object.ChallengeLevel)}.
* @throws InterruptedException
*/
@Test
public void testDeleteChallengeLevel() throws InterruptedException {
this.testAddChallengeToLevel();
assertTrue(cm.containsLevel(levelName));
cm.deleteChallengeLevel(level);
assertFalse(cm.containsLevel(levelName));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#hasAnyChallengeData(org.bukkit.World)}.
* @throws InterruptedException
*/
@Test
public void testHasAnyChallengeDataWorld() throws InterruptedException {
assertFalse(cm.hasAnyChallengeData(world));
this.testLoad();
assertTrue(cm.hasAnyChallengeData(world));
}
/**
* Test method for {@link world.bentobox.challenges.ChallengesManager#hasAnyChallengeData(java.lang.String)}.
* @throws InterruptedException
*/
@Test
public void testHasAnyChallengeDataString() throws InterruptedException {
assertFalse(cm.hasAnyChallengeData("BSkyBlock"));
this.testLoad();
assertTrue(cm.hasAnyChallengeData("BSkyBlock"));
}
}

View File

@ -0,0 +1,268 @@
package world.bentobox.challenges.commands;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.meta.ItemMeta;
import org.eclipse.jdt.annotation.NonNull;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.ChallengesManager;
import world.bentobox.challenges.config.Settings;
import world.bentobox.challenges.config.SettingsUtils.VisibilityMode;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class, ChatColor.class})
public class ChallengesCommandTest {
@Mock
private CompositeCommand ic;
private UUID uuid;
@Mock
private User user;
@Mock
private IslandsManager im;
@Mock
private Island island;
@Mock
private ChallengesAddon addon;
private ChallengesCommand cc;
@Mock
private World world;
@Mock
private ChallengesManager chm;
@Mock
private IslandWorldManager iwm;
@Mock
private GameModeAddon gameModeAddon;
@Mock
private Settings settings;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
// Set up plugin
BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
User.setPlugin(plugin);
// Command manager
CommandsManager cm = mock(CommandsManager.class);
when(plugin.getCommandsManager()).thenReturn(cm);
// Addon
when(ic.getAddon()).thenReturn(addon);
when(ic.getPermissionPrefix()).thenReturn("bskyblock.");
when(ic.getLabel()).thenReturn("island");
when(ic.getTopLabel()).thenReturn("island");
when(ic.getWorld()).thenReturn(world);
when(ic.getTopLabel()).thenReturn("bsb");
// IWM friendly name
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
when(iwm.inWorld(any(World.class))).thenReturn(true);
Optional<GameModeAddon> optionalAddon = Optional.of(gameModeAddon);
when(iwm.getAddon(any())).thenReturn(optionalAddon);
when(plugin.getIWM()).thenReturn(iwm);
// Game Mode Addon
@NonNull
Optional<CompositeCommand> optionalAdmin = Optional.of(ic);
when(gameModeAddon.getAdminCommand()).thenReturn(optionalAdmin);
// World
when(world.toString()).thenReturn("world");
// Player
Player p = mock(Player.class);
// Sometimes use Mockito.withSettings().verboseLogging()
when(user.isOp()).thenReturn(false);
uuid = UUID.randomUUID();
when(user.getUniqueId()).thenReturn(uuid);
when(user.getPlayer()).thenReturn(p);
when(user.getName()).thenReturn("tastybento");
when(user.getPermissionValue(anyString(), anyInt())).thenReturn(-1);
when(user.isPlayer()).thenReturn(true);
// Mock item factory (for itemstacks)
PowerMockito.mockStatic(Bukkit.class);
ItemFactory itemFactory = mock(ItemFactory.class);
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
ItemMeta itemMeta = mock(ItemMeta.class);
when(itemFactory.getItemMeta(any())).thenReturn(itemMeta);
// Addon
when(addon.getChallengesManager()).thenReturn(chm);
when(chm.getAllChallengeLevelStatus(any(), any())).thenReturn(Collections.emptyList());
// Challenges exist
when(chm.hasAnyChallengeData(any(World.class))).thenReturn(true);
// ChatColor
PowerMockito.mockStatic(ChatColor.class);
when(ChatColor.translateAlternateColorCodes(any(char.class), anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
// Settings
when(addon.getChallengesSettings()).thenReturn(settings);
when(settings.getVisibilityMode()).thenReturn(VisibilityMode.VISIBLE);
// Island
when(plugin.getIslands()).thenReturn(im);
when(im.getIsland(any(), any(User.class))).thenReturn(island);
// Command under test
cc = new ChallengesCommand(addon, ic);
}
/**
* Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testCanExecuteWrongWorld() {
when(iwm.inWorld(any(World.class))).thenReturn(false);
assertFalse(cc.canExecute(user, "challenges", Collections.emptyList()));
verify(user).sendMessage("general.errors.wrong-world");
}
/**
* Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testCanExecuteNoChallenges() {
when(chm.hasAnyChallengeData(any(World.class))).thenReturn(false);
assertFalse(cc.canExecute(user, "challenges", Collections.emptyList()));
verify(addon).logError("There are no challenges set up in world!");
verify(user).sendMessage("challenges.errors.no-challenges");
}
/**
* Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testCanExecuteNoChallengesOp() {
when(user.isOp()).thenReturn(true);
when(chm.hasAnyChallengeData(any(World.class))).thenReturn(false);
assertFalse(cc.canExecute(user, "challenges", Collections.emptyList()));
verify(addon).logError("There are no challenges set up in world!");
verify(user).sendMessage("challenges.errors.no-challenges-admin", "[command]", "bsb challenges");
verify(user, never()).sendMessage("challenges.errors.no-challenges");
}
/**
* Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testCanExecuteNoChallengesHasPerm() {
when(user.hasPermission(anyString())).thenReturn(true);
when(chm.hasAnyChallengeData(any(World.class))).thenReturn(false);
assertFalse(cc.canExecute(user, "challenges", Collections.emptyList()));
verify(addon).logError("There are no challenges set up in world!");
verify(user).sendMessage("challenges.errors.no-challenges-admin", "[command]", "bsb challenges");
verify(user, never()).sendMessage("challenges.errors.no-challenges");
}
/**
* Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testCanExecuteNoAdminCommand() {
when(gameModeAddon.getAdminCommand()).thenReturn(Optional.empty());
when(user.isOp()).thenReturn(true);
when(chm.hasAnyChallengeData(any(World.class))).thenReturn(false);
assertFalse(cc.canExecute(user, "challenges", Collections.emptyList()));
verify(addon).logError("There are no challenges set up in world!");
verify(user).sendMessage("challenges.errors.no-challenges-admin", "[command]", "bsb challenges");
verify(user, never()).sendMessage("challenges.errors.no-challenges");
}
/**
* Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testCanExecuteNoIsland() {
when(im.getIsland(any(), any(User.class))).thenReturn(null);
assertFalse(cc.canExecute(user, "challenges", Collections.emptyList()));
verify(user).sendMessage("general.errors.no-island");
}
/**
* Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testCanExecuteSuccess() {
assertTrue(cc.canExecute(user, "challenges", Collections.emptyList()));
verify(user, never()).sendMessage(anyString());
}
/**
* Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringConsole() {
User console = mock(User.class);
assertFalse(cc.execute(console, "challenges", Collections.emptyList()));
verify(console).sendMessage(eq("commands.help.header"), eq(TextVariables.LABEL), eq("BSkyBlock"));
}
/**
* Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringUser() {
assertTrue(cc.execute(user, "challenges", Collections.emptyList()));
}
/**
* Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#setup()}.
*/
@Test
public void testSetup() {
assertEquals("bskyblock." + ChallengesCommand.CHALLENGE_COMMAND, cc.getPermission());
assertEquals("challenges.commands.user.main.parameters", cc.getParameters());
assertEquals("challenges.commands.user.main.description", cc.getDescription());
assertTrue(cc.isOnlyPlayer());
// CompleteChallengeCommand
assertEquals(1, cc.getSubCommands(true).size());
}
}

View File

@ -0,0 +1,342 @@
package world.bentobox.challenges.commands;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.meta.ItemMeta;
import org.eclipse.jdt.annotation.NonNull;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.util.Util;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.ChallengesManager;
import world.bentobox.challenges.config.Settings;
import world.bentobox.challenges.config.SettingsUtils.VisibilityMode;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.tasks.TryToComplete;
import world.bentobox.challenges.utils.Utils;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class, ChatColor.class, Utils.class, TryToComplete.class, Util.class})
public class CompleteChallengeCommandTest {
@Mock
private CompositeCommand ic;
private UUID uuid;
@Mock
private User user;
@Mock
private IslandsManager im;
@Mock
private Island island;
@Mock
private ChallengesAddon addon;
private CompleteChallengeCommand cc;
@Mock
private World world;
@Mock
private ChallengesManager chm;
@Mock
private IslandWorldManager iwm;
@Mock
private GameModeAddon gameModeAddon;
@Mock
private Settings settings;
@Mock
private Challenge challenge;
/**
* @throws java.lang.Exception
*/
@SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
// Set up plugin
BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
User.setPlugin(plugin);
// Command manager
CommandsManager cm = mock(CommandsManager.class);
when(plugin.getCommandsManager()).thenReturn(cm);
// Addon
when(ic.getAddon()).thenReturn(addon);
when(ic.getPermissionPrefix()).thenReturn("bskyblock.");
when(ic.getLabel()).thenReturn("island");
when(ic.getTopLabel()).thenReturn("island");
when(ic.getWorld()).thenReturn(world);
when(ic.getTopLabel()).thenReturn("bsb");
// IWM friendly name
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
when(iwm.inWorld(any(World.class))).thenReturn(true);
Optional<GameModeAddon> optionalAddon = Optional.of(gameModeAddon);
when(iwm.getAddon(any())).thenReturn(optionalAddon);
when(plugin.getIWM()).thenReturn(iwm);
// Game Mode Addon
@NonNull
Optional<CompositeCommand> optionalAdmin = Optional.of(ic);
when(gameModeAddon.getAdminCommand()).thenReturn(optionalAdmin);
// World
when(world.toString()).thenReturn("world");
// Player
Player p = mock(Player.class);
// Sometimes use Mockito.withSettings().verboseLogging()
when(user.isOp()).thenReturn(false);
uuid = UUID.randomUUID();
when(user.getUniqueId()).thenReturn(uuid);
when(user.getPlayer()).thenReturn(p);
when(user.getName()).thenReturn("tastybento");
when(user.getPermissionValue(anyString(), anyInt())).thenReturn(-1);
when(user.isPlayer()).thenReturn(true);
// Mock item factory (for itemstacks)
PowerMockito.mockStatic(Bukkit.class);
ItemFactory itemFactory = mock(ItemFactory.class);
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
ItemMeta itemMeta = mock(ItemMeta.class);
when(itemFactory.getItemMeta(any())).thenReturn(itemMeta);
// Addon & Challenge Manager
when(addon.getChallengesManager()).thenReturn(chm);
when(chm.getAllChallengeLevelStatus(any(), any())).thenReturn(Collections.emptyList());
// Challenges exist
when(chm.hasAnyChallengeData(any(World.class))).thenReturn(true);
// Challenges
when(chm.getChallenge(anyString())).thenReturn(challenge);
List<String> nameList = Arrays.asList("world_maker", "world_placer", "bad_challenge_name", "world_breaker");
when(chm.getAllChallengesNames(any())).thenReturn(nameList);
// ChatColor
PowerMockito.mockStatic(ChatColor.class);
when(ChatColor.translateAlternateColorCodes(any(char.class), anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
// Settings
when(addon.getChallengesSettings()).thenReturn(settings);
when(settings.getVisibilityMode()).thenReturn(VisibilityMode.VISIBLE);
// Island
when(plugin.getIslands()).thenReturn(im);
when(im.getIsland(any(), any(User.class))).thenReturn(island);
// Utils
PowerMockito.mockStatic(Utils.class);
when(Utils.getGameMode(any())).thenReturn("world");
// Try to complete
PowerMockito.mockStatic(TryToComplete.class);
// All challenges are successful!
when(TryToComplete.complete(any(), any(), any(), any(), anyString(), anyString(), anyInt())).thenReturn(true);
// Util
PowerMockito.mockStatic(Util.class);
when(Util.tabLimit(any(), any())).thenAnswer((Answer<List<String>>) invocation -> (List<String>)invocation.getArgument(0, List.class));
// Command under test
cc = new CompleteChallengeCommand(addon, ic);
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#CompleteChallengeCommand(world.bentobox.bentobox.api.addons.Addon, world.bentobox.bentobox.api.commands.CompositeCommand)}.
*/
@Test
public void testCompleteChallengeCommand() {
assertEquals("complete", cc.getLabel());
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#setup()}.
*/
@Test
public void testSetup() {
assertEquals("bskyblock.complete", cc.getPermission());
assertEquals("challenges.commands.user.complete.parameters", cc.getParameters());
assertEquals("challenges.commands.user.complete.description", cc.getDescription());
assertTrue(cc.isOnlyPlayer());
// No sub commands
assertEquals(0, cc.getSubCommands(true).size());
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringNoArgs() {
assertFalse(cc.execute(user, "complete", Collections.emptyList()));
verify(user).sendMessage(eq("challenges.errors.no-name"));
verify(user).sendMessage(eq("commands.help.header"), eq(TextVariables.LABEL), eq("BSkyBlock"));
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringUnknownChallenge() {
when(chm.getChallenge(anyString())).thenReturn(null);
assertFalse(cc.execute(user, "complete", Collections.singletonList("mychal")));
verify(user).sendMessage(eq("challenges.errors.unknown-challenge"));
verify(user).sendMessage(eq("commands.help.header"), eq(TextVariables.LABEL), eq("BSkyBlock"));
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringKnownChallengeFail() {
when(TryToComplete.complete(any(), any(), any(), any(), anyString(), anyString(), anyInt())).thenReturn(false);
assertFalse(cc.execute(user, "complete", Collections.singletonList("mychal")));
verify(user, never()).sendMessage(any());
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringKnownChallengeSuccess() {
assertTrue(cc.execute(user, "complete", Collections.singletonList("mychal")));
verify(user, never()).sendMessage(any());
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringKnownChallengeSuccessMultipleTimesNoPerm() {
assertTrue(cc.execute(user, "complete", Arrays.asList("mychal", "5")));
verify(user).sendMessage(eq("challenges.error.no-multiple-permission"));
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testExecuteUserStringListOfStringKnownChallengeSuccessMultipleTimesHasPerm() {
when(user.hasPermission(anyString())).thenReturn(true);
assertTrue(cc.execute(user, "complete", Arrays.asList("mychal", "5")));
verify(user, never()).sendMessage(any());
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testTabCompleteUserStringListOfStringNoArgs() {
cc.tabComplete(user, "complete", Collections.emptyList());
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testTabCompleteUserStringListOfStringOneArg() {
List<String> list = cc.tabComplete(user, "complete", Collections.singletonList("arg")).get();
assertFalse(list.isEmpty());
assertEquals("help", list.get(0));
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testTabCompleteUserStringListOfStringTwoArgs() {
List<String> list = cc.tabComplete(user, "complete", Arrays.asList("arg1", "arg2")).get();
assertFalse(list.isEmpty());
assertEquals("help", list.get(0));
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testTabCompleteUserStringListOfStringThreeArgs() {
List<String> list = cc.tabComplete(user, "complete", Arrays.asList("arg1", "arg2", "arg3")).get();
assertFalse(list.isEmpty());
assertEquals("maker", list.get(0));
assertEquals("placer", list.get(1));
assertEquals("breaker", list.get(2));
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testTabCompleteUserStringListOfStringFourArgs() {
List<String> list = cc.tabComplete(user, "complete", Arrays.asList("arg1", "arg2", "arg3", "arg4")).get();
assertTrue(list.isEmpty());
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testTabCompleteUserStringListOfStringFourArgsNumber() {
List<String> list = cc.tabComplete(user, "complete", Arrays.asList("arg1", "arg2", "arg3", "4")).get();
assertFalse(list.isEmpty());
assertEquals("<number>", list.get(0));
}
/**
* Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
*/
@Test
public void testTabCompleteUserStringListOfStringFiveArgs() {
List<String> list = cc.tabComplete(user, "complete", Arrays.asList("arg1", "arg2", "arg23", "arg4", "arg5")).get();
assertFalse(list.isEmpty());
assertEquals("help", list.get(0));
}
}

View File

@ -0,0 +1,392 @@
package world.bentobox.challenges.panel.user;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.BlueprintsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.ChallengesManager;
import world.bentobox.challenges.config.Settings;
import world.bentobox.challenges.config.SettingsUtils.VisibilityMode;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.Challenge.ChallengeType;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.utils.LevelStatus;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class, ChatColor.class})
public class ChallengesGUITest {
@Mock
private User user;
@Mock
private IslandsManager im;
@Mock
private IslandWorldManager iwm;
@Mock
private BentoBox plugin;
@Mock
private Settings settings;
@Mock
private CompositeCommand ic;
@Mock
private BlueprintsManager bpm;
@Mock
private Inventory inv;
@Mock
private ItemMeta meta;
@Mock
private ChallengesAddon addon;
@Mock
private World world;
private ChallengesGUI cg;
@Mock
private ChallengesManager chm;
private UUID uuid;
@Mock
private Challenge challenge1;
@Mock
private Challenge challenge2;
@Mock
private Challenge challenge3;
@Mock
private Challenge challenge4;
@Mock
private LevelStatus levelStatus;
private List<Challenge> freeChalls = new ArrayList<>();
private List<Challenge> levelChalls = new ArrayList<>();
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
// Set up plugin
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
PowerMockito.mockStatic(Bukkit.class);
// Item Factory (needed for ItemStack)
ItemFactory itemF = mock(ItemFactory.class);
when(itemF.getItemMeta(Mockito.any())).thenReturn(meta);
when(Bukkit.getItemFactory()).thenReturn(itemF);
// Inventory
when(Bukkit.createInventory(eq(null), anyInt(), anyString())).thenReturn(inv);
// Addon
when(addon.getChallengesManager()).thenReturn(chm);
// Levels
when(levelStatus.isUnlocked()).thenReturn(true);
ChallengeLevel level = mock(ChallengeLevel.class);
when(level.getFriendlyName()).thenReturn("Novice");
when(level.getUniqueId()).thenReturn("novice");
when(level.getIcon()).thenReturn(new ItemStack(Material.BIRCH_BOAT));
when(level.getLockedIcon()).thenReturn(new ItemStack(Material.DARK_OAK_BOAT));
when(levelStatus.getLevel()).thenReturn(level);
List<LevelStatus> levels = Collections.singletonList(levelStatus);
when(chm.getAllChallengeLevelStatus(any(), any())).thenReturn(levels);
when(chm.getChallengeLevelStatus(any(), any(), any())).thenReturn(levelStatus);
// Challenges exist
when(chm.hasAnyChallengeData(any(World.class))).thenReturn(true);
// Free challenges - have more than 18 so that the special processing kicks in
when(chm.getFreeChallenges(any())).thenReturn(freeChalls);
when(challenge1.isDeployed()).thenReturn(true);
when(challenge2.isDeployed()).thenReturn(true);
// 1 is repeatable, 2 is not
when(challenge1.isRepeatable()).thenReturn(true);
// Level challenges
when(chm.getLevelChallenges(any())).thenReturn(levelChalls);
// ChatColor
PowerMockito.mockStatic(ChatColor.class);
when(ChatColor.translateAlternateColorCodes(any(char.class), anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
// Settings
when(addon.getChallengesSettings()).thenReturn(settings);
when(settings.getVisibilityMode()).thenReturn(VisibilityMode.VISIBLE);
when(settings.isFreeChallengesFirst()).thenReturn(false);
when(settings.isRemoveCompleteOneTimeChallenges()).thenReturn(false);
// Player
Player p = mock(Player.class);
when(user.isOp()).thenReturn(false);
uuid = UUID.randomUUID();
when(user.getUniqueId()).thenReturn(uuid);
when(user.getPlayer()).thenReturn(p);
when(user.getName()).thenReturn("tastybento");
when(user.getPermissionValue(anyString(), anyInt())).thenReturn(-1);
when(user.isPlayer()).thenReturn(true);
when(user.getTranslation(anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
cg = new ChallengesGUI(addon, world, user, "island", "bskyblock.");
}
private void addLevelChallenges(int number) {
for (int i = 0; i < number; i++) {
Challenge c = mock(Challenge.class);
when(c.isRepeatable()).thenReturn(true);
when(c.getUniqueId()).thenReturn(String.valueOf(i) + "unique");
when(c.getIcon()).thenReturn(new ItemStack(Material.EMERALD));
when(c.getFriendlyName()).thenReturn(String.valueOf(i) + "name");
when(c.getChallengeType()).thenReturn(ChallengeType.INVENTORY);
when(c.getDescription()).thenReturn(Collections.singletonList("Description"));
when(c.getEnvironment()).thenReturn(Collections.singleton(Environment.NORMAL));
when(c.getLevel()).thenReturn("Novice");
when(c.getRewardItems()).thenReturn(Collections.emptyList());
when(c.isDeployed()).thenReturn(true);
levelChalls.add(c);
}
}
private void addFreeChallenges(int number) {
for (int i = 0; i < number; i++) {
Challenge c = mock(Challenge.class);
when(c.getUniqueId()).thenReturn(String.valueOf(i) + "unique");
when(c.getIcon()).thenReturn(new ItemStack(Material.DIAMOND));
when(c.getFriendlyName()).thenReturn(String.valueOf(i) + "name");
when(c.getChallengeType()).thenReturn(ChallengeType.INVENTORY);
when(c.getDescription()).thenReturn(Collections.singletonList("Description"));
when(c.getEnvironment()).thenReturn(Collections.singleton(Environment.NORMAL));
when(c.getLevel()).thenReturn("Novice");
when(c.getRewardItems()).thenReturn(Collections.emptyList());
when(c.isDeployed()).thenReturn(true);
when(c.isRepeatable()).thenReturn(true);
freeChalls.add(c);
}
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
}
/**
* Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
*/
@Test
public void testBuildNoChallenges() {
when(chm.hasAnyChallengeData(any(World.class))).thenReturn(false);
cg.build();
verify(addon).logError("There are no challenges set up!");
verify(user).sendMessage("challenges.errors.no-challenges");
}
/**
* Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
*/
@Test
public void testBuild0Free0LevelChallenge() {
when(settings.isFreeChallengesFirst()).thenReturn(true);
cg.build();
verify(user).getTranslation("challenges.gui.title.challenges");
ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<ItemStack> argument2 = ArgumentCaptor.forClass(ItemStack.class);
verify(inv).setItem(argument.capture(), argument2.capture());
// Level
assertTrue(argument.getAllValues().get(0) == 0);
assertEquals(Material.BIRCH_BOAT, argument2.getAllValues().get(0).getType());
}
/**
* Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
*/
@Test
public void testBuild10Free10LevelChallenge() {
addFreeChallenges(10);
addLevelChallenges(10);
when(settings.isFreeChallengesFirst()).thenReturn(true);
cg.build();
verify(user).getTranslation("challenges.gui.title.challenges");
ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<ItemStack> argument2 = ArgumentCaptor.forClass(ItemStack.class);
verify(inv, times(21)).setItem(argument.capture(), argument2.capture());
List<ItemStack> values = argument2.getAllValues();
// Free challenges
for (int i = 0; i < 10; i++) {
assertEquals("Failed on " + i, Material.DIAMOND, values.get(i).getType());
}
// Level challenges
for (int i = 11; i < 20; i++) {
assertEquals("Failed on " + i, Material.EMERALD, values.get(i).getType());
}
// Level icons
assertTrue(argument.getAllValues().get(20) == 36);
assertEquals(Material.BIRCH_BOAT, argument2.getAllValues().get(20).getType());
}
/**
* Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
*/
@Test
public void testBuild20Free20LevelChallenge() {
addFreeChallenges(20);
addLevelChallenges(20);
when(settings.isFreeChallengesFirst()).thenReturn(true);
cg.build();
verify(user).getTranslation("challenges.gui.title.challenges");
ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<ItemStack> argument2 = ArgumentCaptor.forClass(ItemStack.class);
verify(inv, times(38)).setItem(argument.capture(), argument2.capture());
List<ItemStack> values = argument2.getAllValues();
// Free challenges
for (int i = 0; i < 18; i++) {
assertEquals("Failed on " + i, Material.DIAMOND, values.get(i).getType());
}
// Next page
assertTrue(argument.getAllValues().get(18) == 18);
assertEquals(Material.OAK_SIGN, argument2.getAllValues().get(18).getType());
// Level challenges
for (int i = 19; i < 37; i++) {
assertEquals("Failed on " + i, Material.EMERALD, values.get(i).getType());
}
// Next page
assertTrue(argument.getAllValues().get(37) == 45);
assertEquals(Material.OAK_SIGN, argument2.getAllValues().get(37).getType());
}
/**
* Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
*/
@Test
public void testBuildFreeChallenges10Free20LevelChallenge() {
addFreeChallenges(10);
addLevelChallenges(20);
when(settings.isFreeChallengesFirst()).thenReturn(true);
cg.build();
verify(user).getTranslation("challenges.gui.title.challenges");
ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<ItemStack> argument2 = ArgumentCaptor.forClass(ItemStack.class);
verify(inv, times(30)).setItem(argument.capture(), argument2.capture());
List<ItemStack> values = argument2.getAllValues();
// Free challenges
for (int i = 0; i < 10; i++) {
assertEquals("Failed on " + i, Material.DIAMOND, values.get(i).getType());
}
// Level challenges
for (int i = 10; i < 27; i++) {
assertEquals("Failed on " + i, Material.EMERALD, values.get(i).getType());
}
// Next page
assertTrue(argument.getAllValues().get(28) == 36);
assertEquals(Material.OAK_SIGN, argument2.getAllValues().get(28).getType());
// Level
assertTrue(argument.getAllValues().get(29) == 45);
assertEquals(Material.BIRCH_BOAT, argument2.getAllValues().get(29).getType());
}
/**
* Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
*/
@Test
public void testBuildFreeChallenges20Free10LevelChallenge() {
addFreeChallenges(20);
addLevelChallenges(10);
when(settings.isFreeChallengesFirst()).thenReturn(true);
cg.build();
verify(user).getTranslation("challenges.gui.title.challenges");
ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<ItemStack> argument2 = ArgumentCaptor.forClass(ItemStack.class);
verify(inv, times(30)).setItem(argument.capture(), argument2.capture());
List<ItemStack> values = argument2.getAllValues();
// Free challenges
for (int i = 0; i < 18; i++) {
assertEquals("Failed on " + i, Material.DIAMOND, values.get(i).getType());
}
// Next page
assertTrue(argument.getAllValues().get(18) == 18);
assertEquals(Material.OAK_SIGN, argument2.getAllValues().get(18).getType());
// Level challenges
for (int i = 19; i < 29; i++) {
assertEquals("Failed on " + i, Material.EMERALD, values.get(i).getType());
}
// Level
assertTrue(argument.getAllValues().get(29) == 45);
assertEquals(Material.BIRCH_BOAT, argument2.getAllValues().get(29).getType());
}
/**
* Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
*/
@Test
public void testBuildFreeChallengesLast20Free10LevelChallenge() {
addFreeChallenges(20);
addLevelChallenges(10);
when(settings.isFreeChallengesFirst()).thenReturn(false);
cg.build();
verify(user).getTranslation("challenges.gui.title.challenges");
ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<ItemStack> argument2 = ArgumentCaptor.forClass(ItemStack.class);
verify(inv, times(30)).setItem(argument.capture(), argument2.capture());
List<ItemStack> values = argument2.getAllValues();
// Level challenges
for (int i = 0; i < 10; i++) {
assertEquals("Failed on " + i, Material.EMERALD, values.get(i).getType());
}
// Next page
assertTrue(argument.getAllValues().get(10) == 18);
assertEquals(Material.BIRCH_BOAT, argument2.getAllValues().get(10).getType());
// Free challenges
for (int i = 11; i < 29; i++) {
assertEquals("Failed on " + i, Material.DIAMOND, values.get(i).getType());
}
// Level
assertTrue(argument.getAllValues().get(29) == 45);
assertEquals(Material.OAK_SIGN, argument2.getAllValues().get(29).getType());
}
}

View File

@ -1,231 +1,649 @@
package world.bentobox.challenges.tasks;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.util.BoundingBox;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.AddonDescription;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.configuration.WorldSettings;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.AddonsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.LocalesManager;
import world.bentobox.bentobox.managers.PlaceholdersManager;
import world.bentobox.bentobox.util.Util;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.ChallengesManager;
import world.bentobox.challenges.config.Settings;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.Challenge.ChallengeType;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.database.object.requirements.InventoryRequirements;
import world.bentobox.challenges.database.object.requirements.IslandRequirements;
import world.bentobox.challenges.tasks.TryToComplete.ChallengeResult;
import world.bentobox.challenges.utils.Utils;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Bukkit.class})
@PrepareForTest({Bukkit.class, BentoBox.class, Util.class, Utils.class})
public class TryToCompleteTest {
private User user;
ItemStack[] stacks = { new ItemStack(Material.PAPER, 32),
new ItemStack(Material.ACACIA_BOAT),
null,
null,
new ItemStack(Material.CACTUS, 32),
new ItemStack(Material.CACTUS, 32),
new ItemStack(Material.CACTUS, 32),
new ItemStack(Material.BRICK_STAIRS, 64),
new ItemStack(Material.BRICK_STAIRS, 64),
new ItemStack(Material.BRICK_STAIRS, 5),
new ItemStack(Material.GOLD_BLOCK, 32)
};
List<ItemStack> required;
private ChallengesAddon addon;
private PlayerInventory inv;
// Constants
private static final String GAME_MODE_NAME = "BSkyBlock";
private static final String[] NAMES = {"adam", "ben", "cara", "dave", "ed", "frank", "freddy", "george", "harry", "ian", "joe"};
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
Server server = mock(Server.class);
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getServer()).thenReturn(server);
when(Bukkit.getBukkitVersion()).thenReturn("1.13.2");
private TryToComplete ttc;
private Challenge challenge;
private @NonNull ChallengeLevel level;
@Mock
private ChallengesAddon addon;
@Mock
private User user;
@Mock
private World world;
private String topLabel = "island";
private String permissionPrefix = "perm.";
user = mock(User.class);
inv = mock(PlayerInventory.class);
when(inv.getContents()).thenReturn(stacks);
when(user.getInventory()).thenReturn(inv);
addon = mock(ChallengesAddon.class);
required = new ArrayList<>();
private String levelName;
@Mock
private ChallengesManager cm;
@Mock
private BentoBox plugin;
@Mock
private GameModeAddon gameMode;
@Mock
private AddonsManager am;
@Mock
private IslandsManager im;
@Mock
private Island island;
@Mock
private Player player;
@Mock
private Settings settings;
@Mock
private WorldSettings mySettings;
private Map<String, Boolean> map;
@Mock
private @Nullable PlayerInventory inv;
private ItemStack[] contents = {};
@Mock
private BoundingBox bb;
ItemFactory itemFactory = mock(ItemFactory.class);
when(server.getItemFactory()).thenReturn(itemFactory);
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
// Set up plugin
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
when(addon.getPlugin()).thenReturn(plugin);
// World
when(user.getWorld()).thenReturn(world);
when(world.getName()).thenReturn("world");
when(world.getEnvironment()).thenReturn(Environment.NORMAL);
// Test will not work with items that has meta data.
when(itemFactory.getItemMeta(any())).thenReturn(null);
when(itemFactory.equals(null, null)).thenReturn(true);
// Addons manager
when(plugin.getAddonsManager()).thenReturn(am);
// One game mode
when(am.getGameModeAddons()).thenReturn(Collections.singletonList(gameMode));
AddonDescription desc2 = new AddonDescription.Builder("bentobox", GAME_MODE_NAME, "1.3").description("test").authors("tasty").build();
when(gameMode.getDescription()).thenReturn(desc2);
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
}
// Challenge Level
level = new ChallengeLevel();
levelName = GAME_MODE_NAME + "_novice";
level.setUniqueId(levelName);
level.setFriendlyName("Novice");
// Set up challenge
String uuid = UUID.randomUUID().toString();
challenge = new Challenge();
challenge.setUniqueId(GAME_MODE_NAME + "_" + uuid);
challenge.setFriendlyName("name");
challenge.setLevel(GAME_MODE_NAME + "_novice");
challenge.setDescription(Collections.singletonList("A description"));
challenge.setChallengeType(ChallengeType.INVENTORY);
challenge.setDeployed(true);
challenge.setIcon(new ItemStack(Material.EMERALD));
challenge.setEnvironment(Collections.singleton(World.Environment.NORMAL));
challenge.setLevel(levelName);
challenge.setRepeatable(true);
challenge.setMaxTimes(10);
InventoryRequirements req = new InventoryRequirements();
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@Test
public void testRemoveItemsSuccess() {
Material requiredMaterial = Material.PAPER;
int requiredQuantity = 21;
challenge.setRequirements(req);
// Util
PowerMockito.mockStatic(Util.class);
when(Util.getWorld(any())).thenReturn(world);
when(Util.prettifyText(anyString())).thenCallRealMethod();
this.required.add(new ItemStack(requiredMaterial, requiredQuantity));
TryToComplete x = new TryToComplete(this.addon);
x.user(this.user);
Map<ItemStack, Integer> removed = x.removeItems(this.required, 1);
// Island World Manager
IslandWorldManager iwm = mock(IslandWorldManager.class);
when(plugin.getIWM()).thenReturn(iwm);
Optional<GameModeAddon> optionalGameMode = Optional.of(gameMode);
when(iwm.getAddon(any())).thenReturn(optionalGameMode);
when(iwm.getIslandDistance(any())).thenReturn(400);
assertEquals((int) removed.getOrDefault(new ItemStack(requiredMaterial, 1), 0), requiredQuantity);
}
// Island Manager
when(addon.getIslands()).thenReturn(im);
Optional<Island> opIsland = Optional.of(island);
when(im.getIslandAt(any())).thenReturn(opIsland);
when(im.getIsland(any(), any(User.class))).thenReturn(island);
// Player is on island
when(im.locationIsOnIsland(any(), any())).thenReturn(true);
// Island flags - everything is allowed by default
when(island.isAllowed(any(), any())).thenReturn(true);
// Island
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@Test
public void testRemoveItemsMax() {
Material requiredMaterial = Material.PAPER;
int requiredQuantity = 50;
@Nullable
Location loc = mock(Location.class);
when(loc.toString()).thenReturn("center");
when(island.getCenter()).thenReturn(loc);
this.required.add(new ItemStack(requiredMaterial, requiredQuantity));
TryToComplete x = new TryToComplete(this.addon);
x.user(this.user);
Map<ItemStack, Integer> removed = x.removeItems(this.required, 1);
// Challenges Manager
when(addon.getChallengesManager()).thenReturn(cm);
// All levels unlocked by default
when(cm.isLevelUnlocked(any(), any(), any())).thenReturn(true);
// Player has done this challenge 3 times (default max is 10)
when(cm.getChallengeTimes(any(), any(), any(Challenge.class))).thenReturn(3L);
assertNotEquals((int) removed.getOrDefault(new ItemStack(requiredMaterial, 1), 0), requiredQuantity);
}
// User has all perms by default
when(user.hasPermission(anyString())).thenReturn(true);
when(user.getPlayer()).thenReturn(player);
when(user.getTranslation(Mockito.anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
when(user.getName()).thenReturn("tastybento");
@Nullable
Location userLoc = mock(Location.class);
when(userLoc.toString()).thenReturn("location");
when(user.getLocation()).thenReturn(userLoc);
when(user.getInventory()).thenReturn(inv);
when(inv.getContents()).thenReturn(contents);
when(player.getBoundingBox()).thenReturn(bb);
when(bb.clone()).thenReturn(bb);
when(bb.toString()).thenReturn("BoundingBox");
// Locales
User.setPlugin(plugin);
LocalesManager lm = mock(LocalesManager.class);
when(plugin.getLocalesManager()).thenReturn(lm);
when(lm.get(any(), any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
PlaceholdersManager phm = mock(PlaceholdersManager.class);
when(plugin.getPlaceholdersManager()).thenReturn(phm);
when(phm.replacePlaceholders(any(), any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@Test
public void testRemoveItemsZero() {
Material requiredMaterial = Material.PAPER;
int requiredQuantity = 0;
// Survival by default
when(player.getGameMode()).thenReturn(GameMode.SURVIVAL);
this.required.add(new ItemStack(requiredMaterial, requiredQuantity));
TryToComplete x = new TryToComplete(this.addon);
x.user(this.user);
Map<ItemStack, Integer> removed = x.removeItems(this.required, 1);
// Addon
when(addon.getChallengesSettings()).thenReturn(settings);
when(settings.isBroadcastMessages()).thenReturn(true);
assertTrue(removed.isEmpty());
}
// Bukkit - online players
Map<UUID, String> online = new HashMap<>();
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@Test
public void testRemoveItemsSuccessMultiple() {
required.add(new ItemStack(Material.PAPER, 11));
required.add(new ItemStack(Material.PAPER, 5));
required.add(new ItemStack(Material.PAPER, 5));
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<ItemStack, Integer> removed = x.removeItems(required, 1);
Set<Player> onlinePlayers = new HashSet<>();
for (int j = 0; j < NAMES.length; j++) {
Player p1 = mock(Player.class);
UUID uuid2 = UUID.randomUUID();
when(p1.getUniqueId()).thenReturn(uuid2);
when(p1.getName()).thenReturn(NAMES[j]);
online.put(uuid2, NAMES[j]);
onlinePlayers.add(p1);
}
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getOnlinePlayers()).then((Answer<Set<Player>>) invocation -> onlinePlayers);
assertEquals((int) removed.getOrDefault(new ItemStack(Material.PAPER, 1), 0), 21);
}
// World settings
map = new HashMap<>();
when(mySettings.getWorldFlags()).thenReturn(map);
when(iwm.getWorldSettings(any())).thenReturn(mySettings);
ChallengesAddon.CHALLENGES_WORLD_PROTECTION.setSetting(world, true);
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@Test
public void testRemoveItemsSuccessMultipleOther() {
required.add(new ItemStack(Material.CACTUS, 5));
required.add(new ItemStack(Material.PAPER, 11));
required.add(new ItemStack(Material.PAPER, 5));
required.add(new ItemStack(Material.PAPER, 5));
required.add(new ItemStack(Material.CACTUS, 5));
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<ItemStack, Integer> removed = x.removeItems(required, 1);
// ItemFactory
ItemFactory itemFactory = mock(ItemFactory.class);
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
assertEquals((int) removed.getOrDefault(new ItemStack(Material.PAPER, 1), 0), 21);
assertEquals((int) removed.getOrDefault(new ItemStack(Material.CACTUS, 1), 0), 10);
}
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@Test
public void testRemoveItemsMultipleOtherFail() {
required.add(new ItemStack(Material.ACACIA_FENCE, 5));
required.add(new ItemStack(Material.ARROW, 11));
required.add(new ItemStack(Material.STONE, 5));
required.add(new ItemStack(Material.BAKED_POTATO, 5));
required.add(new ItemStack(Material.GHAST_SPAWN_EGG, 5));
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<ItemStack, Integer> removed = x.removeItems(required, 1);
assertTrue(removed.isEmpty());
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@Test
public void testRemoveItemsFail() {
ItemStack input = new ItemStack(Material.GOLD_BLOCK, 55);
required.add(input);
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<ItemStack, Integer> removed = x.removeItems(required, 1);
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#TryToComplete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testTryToCompleteChallengesAddonUserChallengeWorldStringString() {
ttc = new TryToComplete(addon,
user,
challenge,
world,
topLabel,
permissionPrefix);
verify(addon).getChallengesManager();
// It will remove 32, but not any more
assertEquals((int) removed.getOrDefault(new ItemStack(Material.GOLD_BLOCK, 1), 0), 32);
}
// An error will be thrown
Mockito.verify(addon, Mockito.times(1)).logError(Mockito.anyString());
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringNotDeployed() {
challenge.setDeployed(false);
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.errors.not-deployed");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringWrongWorld() {
challenge.setUniqueId("test");
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("general.errors.wrong-world");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringNotOnIsland() {
ChallengesAddon.CHALLENGES_WORLD_PROTECTION.setSetting(world, true);
when(im.locationIsOnIsland(any(Player.class), any(Location.class))).thenReturn(false);
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.errors.not-on-island");
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@Test
public void testRequireTwoStacks() {
required.add(new ItemStack(Material.BRICK_STAIRS, 64));
required.add(new ItemStack(Material.BRICK_STAIRS, 64));
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringNotOnIslandButOk() {
ChallengesAddon.CHALLENGES_WORLD_PROTECTION.setSetting(world, false);
when(im.locationIsOnIsland(any(Player.class), any(Location.class))).thenReturn(false);
assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.messages.you-completed-challenge", "[value]", "name");
}
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<ItemStack, Integer> removed = x.removeItems(required, 1);
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringLevelNotUnlocked() {
when(cm.isLevelUnlocked(any(), any(), any())).thenReturn(false);
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.errors.challenge-level-not-available");
}
// It should remove both stacks
assertEquals((int) removed.getOrDefault(new ItemStack(Material.BRICK_STAIRS, 1), 0), 128);
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringNotRepeatable() {
challenge.setRepeatable(false);
when(cm.isChallengeComplete(any(User.class), any(), any())).thenReturn(true);
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.errors.not-repeatable");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringNotRepeatableFirstTime() {
challenge.setRepeatable(false);
challenge.setMaxTimes(0);
when(cm.getChallengeTimes(any(), any(), any(Challenge.class))).thenReturn(0L);
assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.messages.you-completed-challenge", "[value]", "name");
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@Test
public void testFactorStacks() {
required.add(new ItemStack(Material.BRICK_STAIRS, 32));
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringNoRank() {
when(island.isAllowed(any(), any())).thenReturn(false);
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.errors.no-rank");
}
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<ItemStack, Integer> removed = x.removeItems(required, 4);
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String, int)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringIntZero() {
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix, 0));
verify(user).sendMessage("challenges.errors.not-valid-integer");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String, int)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringIntNegative() {
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix, -10));
verify(user).sendMessage("challenges.errors.not-valid-integer");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String, int)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringIntPositiveWrongEnvinonment() {
challenge.setEnvironment(Collections.singleton(Environment.NETHER));
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix, 100));
verify(user).sendMessage("challenges.errors.wrong-environment");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String, int)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringIntPositiveNoPerm() {
InventoryRequirements req = new InventoryRequirements();
req.setRequiredPermissions(Collections.singleton("perm-you-dont-have"));
when(user.hasPermission(anyString())).thenReturn(false);
challenge.setRequirements(req);
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix, 100));
verify(user).sendMessage("general.errors.no-permission");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringSuccess() {
assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.messages.you-completed-challenge", "[value]", "name");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringSuccessSingleReq() {
InventoryRequirements req = new InventoryRequirements();
req.setRequiredItems(Collections.singletonList(new ItemStack(Material.EMERALD_BLOCK)));
challenge.setRequirements(req);
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.errors.not-enough-items", "[items]", "Emerald Block");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringSuccessMultipleReq() {
InventoryRequirements req = new InventoryRequirements();
ItemStack itemStackMock = mock(ItemStack.class);
when(itemStackMock.getAmount()).thenReturn(3);
when(itemStackMock.getType()).thenReturn(Material.EMERALD_BLOCK);
when(itemStackMock.clone()).thenReturn(itemStackMock);
ItemStack itemStackMock2 = mock(ItemStack.class);
when(itemStackMock2.getType()).thenReturn(Material.ENCHANTED_BOOK);
when(itemStackMock2.getAmount()).thenReturn(10);
when(itemStackMock2.clone()).thenReturn(itemStackMock2);
ItemStack itemStackMock3 = mock(ItemStack.class);
when(itemStackMock3.getType()).thenReturn(Material.EMERALD_BLOCK);
when(itemStackMock3.getAmount()).thenReturn(15);
when(itemStackMock3.clone()).thenReturn(itemStackMock3);
// itemStackMock and 3 are same type
when(itemStackMock3.isSimilar(eq(itemStackMock))).thenReturn(true);
when(itemStackMock.isSimilar(eq(itemStackMock3))).thenReturn(true);
req.setRequiredItems(Arrays.asList(itemStackMock , itemStackMock2));
challenge.setRequirements(req);
ItemStack[] newContents = {itemStackMock3};
when(inv.getContents()).thenReturn(newContents);
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
// Sufficient emerald blocks
verify(user, never()).sendMessage("challenges.errors.not-enough-items", "[items]", "Emerald Block");
// Not enough books
verify(user).sendMessage("challenges.errors.not-enough-items", "[items]", "Enchanted Book");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringSuccessCreative() {
when(player.getGameMode()).thenReturn(GameMode.CREATIVE);
assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.messages.you-completed-challenge", "[value]", "name");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandBBTooLarge() {
challenge.setChallengeType(ChallengeType.ISLAND);
IslandRequirements req = new IslandRequirements();
req.setSearchRadius(1);
challenge.setRequirements(req);
// Trigger big bounding box error
when(bb.getWidthX()).thenReturn(50000D);
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(addon).logError("BoundingBox is larger than SearchRadius. | BoundingBox: BoundingBox | Search Distance: 1 | Location: location | Center: center | Range: 0");
verify(bb).expand(1);
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandSuccessNoEntities() {
challenge.setChallengeType(ChallengeType.ISLAND);
IslandRequirements req = new IslandRequirements();
req.setSearchRadius(1);
challenge.setRequirements(req);
assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.messages.you-completed-challenge", "[value]", "name");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandFailEntities() {
challenge.setChallengeType(ChallengeType.ISLAND);
IslandRequirements req = new IslandRequirements();
Map<EntityType, Integer> requiredEntities = Collections.singletonMap(EntityType.GHAST, 3);
req.setRequiredEntities(requiredEntities);
req.setSearchRadius(1);
challenge.setRequirements(req);
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "3", "[item]", "Ghast");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandFailMultipleEntities() {
challenge.setChallengeType(ChallengeType.ISLAND);
IslandRequirements req = new IslandRequirements();
Map<EntityType, Integer> requiredEntities = new HashMap<>();
requiredEntities.put(EntityType.GHAST, 3);
requiredEntities.put(EntityType.CHICKEN, 5);
requiredEntities.put(EntityType.PUFFERFISH, 1);
req.setRequiredEntities(requiredEntities);
req.setSearchRadius(1);
challenge.setRequirements(req);
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "3", "[item]", "Ghast");
verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "1", "[item]", "Pufferfish");
verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "5", "[item]", "Chicken");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandFailPartialMultipleEntities() {
challenge.setChallengeType(ChallengeType.ISLAND);
IslandRequirements req = new IslandRequirements();
Map<EntityType, Integer> requiredEntities = new HashMap<>();
requiredEntities.put(EntityType.GHAST, 3);
requiredEntities.put(EntityType.CHICKEN, 5);
requiredEntities.put(EntityType.PUFFERFISH, 1);
req.setRequiredEntities(requiredEntities);
req.setSearchRadius(1);
challenge.setRequirements(req);
Entity ent = mock(Entity.class);
when(ent.getType()).thenReturn(EntityType.PUFFERFISH);
Location loc = mock(Location.class);
when(ent.getLocation()).thenReturn(loc);
List<Entity> list = Collections.singletonList(ent);
when(world.getNearbyEntities(any(BoundingBox.class))).thenReturn(list);
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "3", "[item]", "Ghast");
verify(user, never()).sendMessage("challenges.errors.you-still-need", "[amount]", "1", "[item]", "Pufferfish");
verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "5", "[item]", "Chicken");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandSuccess() {
challenge.setChallengeType(ChallengeType.ISLAND);
IslandRequirements req = new IslandRequirements();
Map<EntityType, Integer> requiredEntities = new HashMap<>();
requiredEntities.put(EntityType.PUFFERFISH, 1);
req.setRequiredEntities(requiredEntities);
req.setSearchRadius(1);
challenge.setRequirements(req);
Entity ent = mock(Entity.class);
when(ent.getType()).thenReturn(EntityType.PUFFERFISH);
Location loc = mock(Location.class);
when(ent.getLocation()).thenReturn(loc);
List<Entity> list = Collections.singletonList(ent);
when(world.getNearbyEntities(any(BoundingBox.class))).thenReturn(list);
assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.messages.you-completed-challenge", "[value]", "name");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandPlayerInOtherEnvironment() {
challenge.setEnvironment(Collections.singleton(Environment.NETHER));
World netherWorld = mock(World.class);
when(user.getWorld()).thenReturn(netherWorld);
when(netherWorld.getName()).thenReturn("world_nether");
when(netherWorld.getEnvironment()).thenReturn(Environment.NETHER);
challenge.setChallengeType(ChallengeType.ISLAND);
IslandRequirements req = new IslandRequirements();
Map<EntityType, Integer> requiredEntities = new HashMap<>();
requiredEntities.put(EntityType.PUFFERFISH, 1);
req.setRequiredEntities(requiredEntities);
req.setSearchRadius(1);
challenge.setRequirements(req);
Entity ent = mock(Entity.class);
when(ent.getType()).thenReturn(EntityType.PUFFERFISH);
Location loc = mock(Location.class);
when(ent.getLocation()).thenReturn(loc);
List<Entity> list = Collections.singletonList(ent);
when(world.getNearbyEntities(any(BoundingBox.class))).thenReturn(list);
when(netherWorld.getNearbyEntities(any(BoundingBox.class))).thenReturn(Collections.emptyList());
assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "1", "[item]", "Pufferfish");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String, int)}.
*/
@Test
public void testCompleteChallengesAddonUserChallengeWorldStringStringIntMultipleTimesPositiveSuccess() {
// Try to complete 10 times. Already done 3 times, and max is 10, so it should be only done 7 times
assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix, 10));
verify(user).sendMessage("challenges.messages.you-repeated-challenge-multiple", "[value]", "name", "[count]", "7");
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#build(int)}.
*/
@Test
public void testBuild() {
this.testTryToCompleteChallengesAddonUserChallengeWorldStringString();
ChallengeResult result = this.ttc.build(10);
assertTrue(result.isMeetsRequirements());
}
/**
* Test method for {@link world.bentobox.challenges.tasks.TryToComplete#removeItems(java.util.List, int)}.
*/
@Test
public void testRemoveItemsNothing() {
this.testTryToCompleteChallengesAddonUserChallengeWorldStringString();
assertTrue(ttc.removeItems(Collections.emptyList(), 1).isEmpty());
}
// It should remove both stacks
assertEquals((int) removed.getOrDefault(new ItemStack(Material.BRICK_STAIRS, 1), 0), 128);
}
}

View File

@ -0,0 +1,242 @@
package world.bentobox.challenges.tasks;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.ChallengesAddon;
/**
* @author tastybento
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Bukkit.class})
public class TryToCompleteTestOld {
private User user;
ItemStack[] stacks = { new ItemStack(Material.PAPER, 32),
new ItemStack(Material.ACACIA_BOAT),
null,
null,
new ItemStack(Material.CACTUS, 32),
new ItemStack(Material.CACTUS, 32),
new ItemStack(Material.CACTUS, 32),
new ItemStack(Material.BRICK_STAIRS, 64),
new ItemStack(Material.BRICK_STAIRS, 64),
new ItemStack(Material.BRICK_STAIRS, 5),
new ItemStack(Material.GOLD_BLOCK, 32)
};
List<ItemStack> required;
private ChallengesAddon addon;
private PlayerInventory inv;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
Server server = mock(Server.class);
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getServer()).thenReturn(server);
when(Bukkit.getBukkitVersion()).thenReturn("1.13.2");
user = mock(User.class);
inv = mock(PlayerInventory.class);
when(inv.getContents()).thenReturn(stacks);
when(user.getInventory()).thenReturn(inv);
addon = mock(ChallengesAddon.class);
required = new ArrayList<>();
ItemFactory itemFactory = mock(ItemFactory.class);
when(server.getItemFactory()).thenReturn(itemFactory);
// Test will not work with items that has meta data.
when(itemFactory.getItemMeta(any())).thenReturn(null);
when(itemFactory.equals(null, null)).thenReturn(true);
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@SuppressWarnings("deprecation")
@Test
public void testRemoveItemsSuccess() {
Material requiredMaterial = Material.PAPER;
int requiredQuantity = 21;
this.required.add(new ItemStack(requiredMaterial, requiredQuantity));
TryToComplete x = new TryToComplete(this.addon);
x.user(this.user);
Map<ItemStack, Integer> removed = x.removeItems(this.required, 1);
assertEquals((int) removed.getOrDefault(new ItemStack(requiredMaterial, 1), 0), requiredQuantity);
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@SuppressWarnings("deprecation")
@Test
public void testRemoveItemsMax() {
Material requiredMaterial = Material.PAPER;
int requiredQuantity = 50;
this.required.add(new ItemStack(requiredMaterial, requiredQuantity));
TryToComplete x = new TryToComplete(this.addon);
x.user(this.user);
Map<ItemStack, Integer> removed = x.removeItems(this.required, 1);
assertNotEquals((int) removed.getOrDefault(new ItemStack(requiredMaterial, 1), 0), requiredQuantity);
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@SuppressWarnings("deprecation")
@Test
public void testRemoveItemsZero() {
Material requiredMaterial = Material.PAPER;
int requiredQuantity = 0;
this.required.add(new ItemStack(requiredMaterial, requiredQuantity));
TryToComplete x = new TryToComplete(this.addon);
x.user(this.user);
Map<ItemStack, Integer> removed = x.removeItems(this.required, 1);
assertTrue(removed.isEmpty());
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@SuppressWarnings("deprecation")
@Test
public void testRemoveItemsSuccessMultiple() {
required.add(new ItemStack(Material.PAPER, 11));
required.add(new ItemStack(Material.PAPER, 5));
required.add(new ItemStack(Material.PAPER, 5));
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<ItemStack, Integer> removed = x.removeItems(required, 1);
assertEquals((int) removed.getOrDefault(new ItemStack(Material.PAPER, 1), 0), 21);
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@SuppressWarnings("deprecation")
@Test
public void testRemoveItemsSuccessMultipleOther() {
required.add(new ItemStack(Material.CACTUS, 5));
required.add(new ItemStack(Material.PAPER, 11));
required.add(new ItemStack(Material.PAPER, 5));
required.add(new ItemStack(Material.PAPER, 5));
required.add(new ItemStack(Material.CACTUS, 5));
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<ItemStack, Integer> removed = x.removeItems(required, 1);
assertEquals((int) removed.getOrDefault(new ItemStack(Material.PAPER, 1), 0), 21);
assertEquals((int) removed.getOrDefault(new ItemStack(Material.CACTUS, 1), 0), 10);
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@SuppressWarnings("deprecation")
@Test
public void testRemoveItemsMultipleOtherFail() {
required.add(new ItemStack(Material.ACACIA_FENCE, 5));
required.add(new ItemStack(Material.ARROW, 11));
required.add(new ItemStack(Material.STONE, 5));
required.add(new ItemStack(Material.BAKED_POTATO, 5));
required.add(new ItemStack(Material.GHAST_SPAWN_EGG, 5));
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<ItemStack, Integer> removed = x.removeItems(required, 1);
assertTrue(removed.isEmpty());
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@SuppressWarnings("deprecation")
@Test
public void testRemoveItemsFail() {
ItemStack input = new ItemStack(Material.GOLD_BLOCK, 55);
required.add(input);
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<ItemStack, Integer> removed = x.removeItems(required, 1);
// It will remove 32, but not any more
assertEquals((int) removed.getOrDefault(new ItemStack(Material.GOLD_BLOCK, 1), 0), 32);
// An error will be thrown
Mockito.verify(addon, Mockito.times(1)).logError(Mockito.anyString());
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@SuppressWarnings("deprecation")
@Test
public void testRequireTwoStacks() {
required.add(new ItemStack(Material.BRICK_STAIRS, 64));
required.add(new ItemStack(Material.BRICK_STAIRS, 64));
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<ItemStack, Integer> removed = x.removeItems(required, 1);
// It should remove both stacks
assertEquals((int) removed.getOrDefault(new ItemStack(Material.BRICK_STAIRS, 1), 0), 128);
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@SuppressWarnings("deprecation")
@Test
public void testFactorStacks() {
required.add(new ItemStack(Material.BRICK_STAIRS, 32));
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<ItemStack, Integer> removed = x.removeItems(required, 4);
// It should remove both stacks
assertEquals((int) removed.getOrDefault(new ItemStack(Material.BRICK_STAIRS, 1), 0), 128);
}
}

View File

@ -0,0 +1,199 @@
package world.bentobox.challenges.utils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.ItemStack;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.AddonDescription;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.challenges.config.SettingsUtils.VisibilityMode;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class})
public class UtilsTest {
@Mock
private IslandWorldManager iwm;
@Mock
private GameModeAddon gameModeAddon;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
// Set up plugin
BentoBox plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Mock item factory (for itemstacks)
PowerMockito.mockStatic(Bukkit.class);
ItemFactory itemFactory = mock(ItemFactory.class);
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
// IWM getAddon
AddonDescription desc = new AddonDescription.Builder("main", "name", "1.0").build();
when(gameModeAddon.getDescription()).thenReturn(desc);
Optional<GameModeAddon> optionalAddon = Optional.of(gameModeAddon);
when(iwm.getAddon(any())).thenReturn(optionalAddon);
when(plugin.getIWM()).thenReturn(iwm);
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
}
/**
* Test method for {@link world.bentobox.challenges.utils.Utils#groupEqualItems(java.util.List)}.
*/
@Test
public void testGroupEqualItemsEmpty() {
assertTrue(Utils.groupEqualItems(Collections.emptyList()).isEmpty());
}
/**
* Test method for {@link world.bentobox.challenges.utils.Utils#groupEqualItems(java.util.List)}.
*/
@Test
public void testGroupEqualItems() {
List<ItemStack> requiredItems = new ArrayList<>();
// First item
ItemStack is = mock(ItemStack.class);
when(is.getAmount()).thenReturn(1);
when(is.getType()).thenReturn(Material.ACACIA_FENCE);
when(is.getMaxStackSize()).thenReturn(64);
when(is.isSimilar(any())).thenReturn(true);
when(is.clone()).thenReturn(is);
requiredItems.add(is);
for (int i = 0; i < 9; i++) {
ItemStack is2 = mock(ItemStack.class);
when(is2.getAmount()).thenReturn(1);
when(is2.getType()).thenReturn(Material.ACACIA_FENCE);
when(is2.getMaxStackSize()).thenReturn(64);
when(is2.isSimilar(any())).thenReturn(true);
when(is2.clone()).thenReturn(is);
requiredItems.add(is2);
}
List<ItemStack> list = Utils.groupEqualItems(requiredItems);
// Result should be two stacks stack of 64 doors and 36 doors
assertEquals(1, list.size());
verify(is, times(9)).setAmount(2);
}
/**
* Test method for {@link world.bentobox.challenges.utils.Utils#groupEqualItems(java.util.List)}.
*/
@Test
public void testGroupEqualItemsUnique() {
List<ItemStack> requiredItems = new ArrayList<>();
// First item
ItemStack is = mock(ItemStack.class);
when(is.getAmount()).thenReturn(1);
when(is.getType()).thenReturn(Material.ACACIA_FENCE);
when(is.getMaxStackSize()).thenReturn(64);
when(is.isSimilar(any())).thenReturn(false);
when(is.clone()).thenReturn(is);
requiredItems.add(is);
for (int i = 0; i < 9; i++) {
ItemStack is2 = mock(ItemStack.class);
when(is2.getAmount()).thenReturn(1);
when(is2.getType()).thenReturn(Material.values()[i+20]);
when(is2.getMaxStackSize()).thenReturn(64);
when(is2.isSimilar(any())).thenReturn(false);
when(is2.clone()).thenReturn(is);
requiredItems.add(is2);
}
List<ItemStack> list = Utils.groupEqualItems(requiredItems);
// Result should be two stacks stack of 64 doors and 36 doors
assertEquals(10, list.size());
verify(is, never()).setAmount(2);
}
/**
* Test method for {@link world.bentobox.challenges.utils.Utils#canIgnoreMeta(org.bukkit.Material)}.
*/
@Test
public void testCanIgnoreMeta() {
assertTrue(Utils.canIgnoreMeta(Material.FIREWORK_ROCKET));
assertTrue(Utils.canIgnoreMeta(Material.ENCHANTED_BOOK));
assertTrue(Utils.canIgnoreMeta(Material.WRITTEN_BOOK));
assertTrue(Utils.canIgnoreMeta(Material.FILLED_MAP));
assertFalse(Utils.canIgnoreMeta(Material.CHISELED_RED_SANDSTONE));
}
/**
* Test method for {@link world.bentobox.challenges.utils.Utils#getGameMode(org.bukkit.World)}.
*/
@Test
public void testGetGameModeNoGameMode() {
when(iwm.getAddon(any())).thenReturn(Optional.empty());
assertNull(Utils.getGameMode(mock(World.class)));
}
/**
* Test method for {@link world.bentobox.challenges.utils.Utils#getGameMode(org.bukkit.World)}.
*/
@Test
public void testGetGameMode() {
assertEquals("name", Utils.getGameMode(mock(World.class)));
}
/**
* Test method for {@link world.bentobox.challenges.utils.Utils#getNextValue(T[], java.lang.Object)}.
*/
@Test
public void testGetNextValue() {
assertEquals(VisibilityMode.HIDDEN, Utils.getNextValue(VisibilityMode.values(), VisibilityMode.VISIBLE));
assertEquals(VisibilityMode.TOGGLEABLE, Utils.getNextValue(VisibilityMode.values(), VisibilityMode.HIDDEN));
assertEquals(VisibilityMode.VISIBLE, Utils.getNextValue(VisibilityMode.values(), VisibilityMode.TOGGLEABLE));
}
/**
* Test method for {@link world.bentobox.challenges.utils.Utils#getPreviousValue(T[], java.lang.Object)}.
*/
@Test
public void testGetPreviousValue() {
assertEquals(VisibilityMode.TOGGLEABLE, Utils.getPreviousValue(VisibilityMode.values(), VisibilityMode.VISIBLE));
assertEquals(VisibilityMode.VISIBLE, Utils.getPreviousValue(VisibilityMode.values(), VisibilityMode.HIDDEN));
assertEquals(VisibilityMode.HIDDEN, Utils.getPreviousValue(VisibilityMode.values(), VisibilityMode.TOGGLEABLE));
}
}