Prepare 0.7.0 Release

This commit is contained in:
BONNe1704 2019-05-09 15:54:47 +03:00
commit 76b7580de3
43 changed files with 6325 additions and 2716 deletions

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.6.1**, and you can download it from [Release tab](https://github.com/BentoBoxWorld/Challenges/releases)
Latest official **Beta Release is 0.7.0**, and you can download it from [Release tab](https://github.com/BentoBoxWorld/Challenges/releases)
Or you can try **nightly builds** where you can check and test new features that will be implemented in next release from [Jenkins Server](https://ci.codemc.org/job/BentoBoxWorld/job/Challenges/lastStableBuild/).
@ -18,57 +18,48 @@ If you like this addon but something is missing or is not working as you want, y
1. Place the addon jar in the addons folder of the BentoBox plugin
2. Restart the server
3. The addon will create a data folder and inside the folder will be a config.yml and an example challenges.yml
4. Edit the config.yml and challenges.yml files how you want. Note that unlike ASkyBlock, the challenges.yml is for *importing only* and faster start.
4. Edit the config.yml how you want.
5. Restart the server
6. To import challenges into GameMode, you must run admin command and attach `challenges import` at the end. Or you can use challenges admin GUI to do the same.
#### Challenges
By default, challenges addon comes without any challenge or level. On first runtime only Admin GUI will be accessible.
Admins can create their own challenges or use challenges from ASkyBlock, by importing them via Admin GUI. This requires challenges.yml file in `./plugins/BentoBox/addons/Challenges/` folder.
There exist also some default challenges, which importing also are available via Admin GUI.
## Compatibility
- [x] BentoBox - 1.3.0 version
- [x] BSkyBlock - 1.3.0 version
- [x] AcidIsland - 1.3.0 version
- [x] SkyGrid - 1.3.0-SNAPSHOT version
- [ ] CaveBlock
- [x] BentoBox - 1.4.0 version
- [x] BSkyBlock - 1.4.0 version
- [x] AcidIsland - 1.4.0 version
- [x] SkyGrid - 1.4.0 version
- [x] CaveBlock - 1.4.0 version
## Config.yml
As most of BenotBox addons, config can be edited only when server is stopped. Otherwise all changes will be overwritten by server.
The config.yml has the following sections:
* Reset Challenges - if this is true, player's challenges will reset when they reset an island or if they are kicked or leave a team. Prevents exploiting the challenges by doing them repeatedly. Default is true
* Broadcast 1st time challenge completion messages to all players. Change to false if the spam becomes too much. Default is true.
* Remove non-repeatable challenges from the challenge GUI when complete. Default is false.
* Add enchanted glow to completed challenges. Default is true
* Free challenges location - You can decide, either free challenges will be at the top, or at the bottom.
* Description line length - allows to specify maximal line length in GUI icon descriptions.
* Challenge Description structure - allows to modify structure of challenge description.
* Level Description structure - allows to modify structure of Level description.
* Disabled GameModes - specify Game Modes where challenges will not work.
* **Commands** - ability to enable */challenges* command. This option change is possible only via configuration and requires server restart.
To enable, you should change `single-gui` to `true`.
* **History** - ability to enable completion history storing in player data object.
To enable, you should change `store-history-data` to `true`.
It is possible to change life-span of history data in days. (0 means that data will not be removed)
* **GUI Settings** - ability to change some options that are visible only in challenges GUI.
* Remove non-repeatable challenges from the challenge GUI when complete. Default is false.
* Add enchanted glow to completed challenges. Default is true.
* Locked level icon is displayed for locked levels.
* Free challenges location - You can decide, either free challenges will be at the top, or at the bottom.
* Description line length - allows to specify maximal line length in GUI icon descriptions.
* Challenge Description structure - allows to modify structure of challenge description.
* Level Description structure - allows to modify structure of Level description.
* **Store mode** - ability to store challenges completion per island or per player.
To enable storing challenges data per island change `store-island-data` to `true`. ATTENTION: progress will be lost on this option change.
* **Reset Challenges** - if this is true, player's challenges will reset when they reset an island or if they are kicked or leave a team. Prevents exploiting the challenges by doing them repeatedly. Default is true
* **Broadcast** - ability to broadcast 1st time challenge completion messages to all players. Change to false if the spam becomes too much. Default is true.
* **Title** - ability to enable showing Title screen on first challenge completion or level completion.
* **Disabled GameModes** - specify Game Modes where challenges will not work.
## Challenges.yml
## Information
This file is just to facilitate importing of old ASkyBlock or AcidIsland challenges and is not used during the normal operation of the game. it is meant to just enable you to jump start your challenge collection.
This file format is very similar to the ASkyBlock file but not exactly the same because it is designed for 1.13.x servers and higher. If you try to import ASkyBlock challenges, they may or may not completely import, so check for errors in the console.
Once you have imported challenges, the *real* challenge files are actually in two folders in the BentoBox database folder. One folder is for the challenges and the other is for the challenge levels. They are all defined in .yml files in these locations:
```
plugins/BentoBox/database/Challenges
plugins/BentoBox/database/ChallengeLevels
```
If you edit a file, then you should reload the challenge database by using the admin reload command, e.g. **/bsb challenges reload** or **/acid challenges reload**.
If you want to force an overwrite of challenges via an import, add the **overwrite** option to the end of the import command.
Note that you must import challenges into both BSkyBlock and AcidIsland separately.
## Admin commands
There are a few admin commands and more being written. The main challenge admin command is **/bsb challenges** or **/acid challenges**. Use
* /bsbadmin challenges help : Show help for all the commands
* /bsbadmin challenges import [overwrite]: import challenges from challenges.yml
* /bsbadmin challenges reload : reload challenges from the database
More information can be found in [Wiki Pages](https://github.com/BentoBoxWorld/Challenges/wiki).

18
pom.xml
View File

@ -36,18 +36,19 @@
<powermock.version>1.7.4</powermock.version>
<!-- More visible way how to change dependency versions -->
<spigot.version>1.13.2-R0.1-SNAPSHOT</spigot.version>
<bentobox.version>1.3.0</bentobox.version>
<level.version>1.3.0</level.version>
<bentobox.version>1.4.0</bentobox.version>
<level.version>1.4.0</level.version>
<vault.version>68f14ec</vault.version>
<!-- Revision variable removes warning about dynamic version -->
<revision>${build.version}</revision>
<revision>${build.version}-SNAPSHOT</revision>
<!-- This allows to change between versions and snapshots. -->
<build.version>0.6.1</build.version>
<build.version>0.7.0</build.version>
<build.number>-LOCAL</build.number>
</properties>
<profiles>
<profile>
<id>develop</id>
<id>ci</id>
<activation>
<property>
<name>env.BUILD_NUMBER</name>
@ -55,7 +56,7 @@
</activation>
<properties>
<!-- Override only if necessary -->
<revision>${build.version}-SNAPSHOT-${env.BUILD_NUMBER}</revision>
<build.number>-#${env.BUILD_NUMBER}</build.number>
<!-- GIT_BRANCH -->
</properties>
</profile>
@ -70,7 +71,8 @@
<properties>
<!-- Override only if necessary -->
<revision>${build.version}</revision>
<!-- GIT_BRANCH -->
<!-- Empties build number variable.-->
<build.number></build.number>
</properties>
</profile>
</profiles>
@ -93,7 +95,7 @@
</repository>
<repository>
<id>codemc-repo</id>
<url>https://repo.codemc.org/repository/maven-public/</url>
<url>https://repo.codemc.org/repository/maven-releases/</url>
</repository>
<!--Vault Repo is down.-->
<!--<repository>-->

View File

@ -225,10 +225,12 @@ public class ChallengesAddon extends Addon {
@Override
public void onReload()
{
if (this.hooked) {
this.challengesManager.save();
super.onReload();
if (this.hooked)
{
this.loadSettings();
this.challengesManager.reload();
this.getLogger().info("Challenges addon reloaded.");
}
}

View File

@ -1,9 +1,14 @@
package world.bentobox.challenges;
import java.io.File;
import java.io.IOException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import java.io.*;
import java.nio.file.Files;
import java.util.*;
import java.util.stream.Collectors;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
@ -11,13 +16,14 @@ import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import world.bentobox.bentobox.api.configuration.Config;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.database.json.adapters.*;
import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.bentobox.util.ItemParser;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.database.object.ChallengeLevels;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.Challenges;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.util.Util;
import world.bentobox.challenges.utils.GuiUtils;
@ -40,10 +46,6 @@ public class ChallengesImportManager
*/
public ChallengesImportManager(ChallengesAddon challengesAddon) {
this.addon = challengesAddon;
File challengeFile = new File(addon.getDataFolder(), "challenges.yml");
if (!challengeFile.exists()) {
addon.saveResource("challenges.yml",false);
}
}
/**
@ -208,170 +210,420 @@ public class ChallengesImportManager
// ---------------------------------------------------------------------
// Section: Backward compatibility
// Section: Default Challenge Loader
// ---------------------------------------------------------------------
/**
* This method imports challenges form 0.3 and below version.
* @param user - user
* @param world - world to import into
* @param overwrite - true if previous ones should be overwritten
* @return true if successful
* This method loads default challenges into memory.
* @param user User who calls default challenge loading
* @param world Target world.
* @return <code>true</code> if everything was successful, otherwise <code>false</code>.
*/
public boolean importPreviousChallenges(User user, World world, boolean overwrite)
public boolean loadDefaultChallenges(User user, World world)
{
ChallengesManager manager = this.addon.getChallengesManager();
List<Challenges> challenges =
new Config<>(this.addon, Challenges.class).loadConfigObjects();
if (!challenges.isEmpty())
// If exist any challenge or level that is bound to current world, then do not load default challenges.
if (manager.hasAnyChallengeData(world.getName()))
{
List<ChallengeLevels> levels =
new Config<>(this.addon, ChallengeLevels.class).loadConfigObjects();
for (ChallengeLevels level : levels)
if (user.isPlayer())
{
ChallengeLevel newlevel = this.createLevel(level, world);
if (newlevel != null)
{
manager.loadLevel(newlevel, overwrite, user, false);
}
user.sendMessage("challenges.errors.exist-challenges-or-levels");
}
else
{
this.addon.logWarning("challenges.errors.exist-challenges-or-levels");
}
for (Challenges challenge : challenges)
{
Challenge newChallenge = this.createChallenge(challenge, world);
if (newChallenge == null)
{
continue;
}
manager.loadChallenge(newChallenge, overwrite, user, false);
if (challenge.getLevel().isEmpty() || challenge.getLevel().equals("FREE"))
{
newChallenge.setLevel(ChallengesManager.FREE);
}
else
{
String levelName = Util.getWorld(world).getName() + "_" + challenge.getLevel();
if (this.addon.getChallengesManager().containsLevel(levelName))
{
manager.addChallengeToLevel(newChallenge,
this.addon.getChallengesManager().getLevel(levelName));
}
}
}
return false;
}
// Safe json configuration to Challenges folder.
this.addon.saveResource("default.json", true);
try
{
// This prefix will be used to all challenges. That is a unique way how to separate challenged for
// each game mode.
String uniqueIDPrefix = Util.getWorld(world).getName() + "_";
DefaultDataHolder defaultChallenges = new DefaultJSONHandler(this.addon).loadObject();
// All new challenges should get correct ID. So we need to map it to loaded challenges.
defaultChallenges.getChallengeList().parallelStream().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().parallelStream().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;
}
this.addon.getChallengesManager().save();
// Remove default.yml file from resources to avoid interacting with it.
new File(this.addon.getDataFolder(), "default.json").delete();
return true;
}
/**
* This method creates new ChallengeLevel based on old level settings.
* @param level Old level object.
* @param world World where new challenge will operate.
* @return New level or null, if old level does not operate in this world.
*/
private ChallengeLevel createLevel(ChallengeLevels level, World world)
{
if (!level.getWorlds().isEmpty() &&
!level.getWorlds().contains(Util.getWorld(world).getName()))
{
return null;
}
ChallengeLevel newLevel = new ChallengeLevel();
newLevel.setUniqueId(Util.getWorld(world).getName() + "_" + level.getUniqueId());
newLevel.setFriendlyName(level.getFriendlyName());
newLevel.setOrder(level.getOrder());
newLevel.setWorld(Util.getWorld(world).getName());
newLevel.setUnlockMessage(level.getUnlockMessage());
newLevel.setWaiverAmount(level.getWaiveramount());
newLevel.setRewardText(level.getRewardDescription());
newLevel.setRewardMoney(level.getMoneyReward());
newLevel.setRewardExperience(level.getExpReward());
newLevel.setRewardItems(level.getRewardItems());
newLevel.setRewardCommands(level.getRewardCommands());
return newLevel;
}
// ---------------------------------------------------------------------
// Section: Default generation
// ---------------------------------------------------------------------
/**
* This method creates new Challenge based on old challenges settings.
* @param challenge Old challenges object.
* @param world World where new challenge will operate.
* @return New Challenge or null, if old challenge does not operate in this world.
* 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 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>
*/
private Challenge createChallenge(Challenges challenge, World world)
public boolean generateDefaultChallengeFile(User user, World world, boolean overwrite)
{
if (!challenge.getWorld().equals(Util.getWorld(world).getName()))
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");
}
defaultFile.delete();
}
else
{
if (user.isPlayer())
{
user.sendMessage("challenges.errors.defaults-file-exist");
}
else
{
this.addon.logWarning("challenges.errors.defaults-file-exist");
}
return false;
}
}
try
{
// Does not operate in given world.
return null;
if (defaultFile.createNewFile())
{
String replacementString = Util.getWorld(world).getName() + "_";
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, ""));
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()));
return clone;
}).
collect(Collectors.toList());
DefaultDataHolder defaultChallenges = new DefaultDataHolder();
defaultChallenges.setChallengeList(challengeList);
defaultChallenges.setLevelList(levelList);
defaultChallenges.setVersion(this.addon.getDescription().getVersion());
BufferedWriter writer = new BufferedWriter(new FileWriter(defaultFile, false));
writer.write(Objects.requireNonNull(
new DefaultJSONHandler(this.addon).toJsonString(defaultChallenges)));
writer.close();
}
}
catch (IOException e)
{
if (user.isPlayer())
{
user.sendMessage("challenges.errors.defaults-file-error");
}
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");
}
}
return true;
}
// ---------------------------------------------------------------------
// Section: Private classes for default challegnes
// ---------------------------------------------------------------------
/**
* This Class allows to load default challenges and their levels as objects much easier.
*/
private final class DefaultJSONHandler
{
/**
* This constructor inits JSON builder that will be used to parese challenges.
* @param addon Challenges Adddon
*/
DefaultJSONHandler(ChallengesAddon addon)
{
GsonBuilder builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().enableComplexMapKeySerialization();
// Register adapters
builder.registerTypeAdapter(Location.class, new LocationAdapter()) ;
builder.registerTypeAdapter(World.class, new WorldAdapter());
builder.registerTypeAdapter(Flag.class, new FlagAdapter(addon.getPlugin()));
builder.registerTypeAdapter(PotionEffectType.class, new PotionEffectTypeAdapter());
builder.registerTypeAdapter(ItemStack.class, new ItemStackTypeAdapter());
// Keep null in the database
builder.serializeNulls();
// Allow characters like < or > without escaping them
builder.disableHtmlEscaping();
this.addon = addon;
this.gson = builder.setPrettyPrinting().create();
}
Challenge newChallenge = new Challenge();
newChallenge.setUniqueId(challenge.getUniqueId());
newChallenge.setFriendlyName(challenge.getFriendlyName());
newChallenge.setRemoveWhenCompleted(challenge.isRemoveWhenCompleted());
newChallenge.setDeployed(challenge.isDeployed());
newChallenge.setIcon(challenge.getIcon());
newChallenge.setEnvironment(new HashSet<>(challenge.getEnvironment()));
switch (challenge.getChallengeType())
/**
* This method returns json object that is parsed to string. Json object is made from given instance.
* @param instance Instance that must be parsed to json string.
* @return String that contains JSON information from instance object.
*/
String toJsonString(DefaultDataHolder instance)
{
case INVENTORY:
newChallenge.setChallengeType(Challenge.ChallengeType.INVENTORY);
break;
case ISLAND:
newChallenge.setChallengeType(Challenge.ChallengeType.ISLAND);
break;
default:
newChallenge.setChallengeType(Challenge.ChallengeType.OTHER);
break;
// Null check
if (instance == null)
{
this.addon.logError("JSON database request to store a null. ");
return null;
}
return this.gson.toJson(instance);
}
newChallenge.setOrder(challenge.getSlot());
newChallenge.setDescription(challenge.getDescription());
newChallenge.setRequiredEntities(challenge.getRequiredEntities());
newChallenge.setRequiredItems(challenge.getRequiredItems());
newChallenge.setRequiredBlocks(challenge.getRequiredBlocks());
newChallenge.setRequiredMoney(challenge.getReqMoney());
newChallenge.setRequiredExperience(challenge.getReqExp());
newChallenge.setRequiredIslandLevel(challenge.getReqIslandlevel());
newChallenge.setRequiredPermissions(challenge.getReqPerms());
/**
* 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");
newChallenge.setTakeMoney(challenge.isTakeMoney());
newChallenge.setTakeItems(challenge.isTakeItems());
newChallenge.setSearchRadius(challenge.getSearchRadius());
StringBuilder builder = new StringBuilder();
newChallenge.setRewardText(challenge.getRewardText());
newChallenge.setRewardItems(challenge.getRewardItems());
newChallenge.setRewardMoney(challenge.getRewardMoney());
newChallenge.setRewardExperience(challenge.getRewardExp());
newChallenge.setRewardCommands(challenge.getRewardCommands());
try
{
Files.readAllLines(defaultFile.toPath()).forEach(builder::append);
}
catch (IOException e)
{
e.printStackTrace();
}
newChallenge.setRepeatable(challenge.isRepeatable());
newChallenge.setMaxTimes(challenge.getMaxTimes());
newChallenge.setRepeatRewardText(challenge.getRepeatRewardText());
newChallenge.setRepeatItemReward(challenge.getRepeatItemReward());
newChallenge.setRepeatMoneyReward(challenge.getRepeatMoneyReward());
newChallenge.setRepeatExperienceReward(challenge.getRepeatExpReward());
newChallenge.setRepeatRewardCommands(challenge.getRepeatRewardCommands());
return this.gson.fromJson(builder.toString(), DefaultDataHolder.class);
}
return newChallenge;
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* Holds JSON builder object.
*/
private Gson gson;
/**
* Holds ChallengesAddon object.
*/
private ChallengesAddon addon;
}
/**
* This is simple object that will allow to store all current challenges and levels
* in single file.
*/
private 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.
*/
public List<Challenge> getChallengeList()
{
return challengeList;
}
/**
* This method sets given list as default challenge list.
* @param challengeList new default challenge list.
*/
public void setChallengeList(List<Challenge> challengeList)
{
this.challengeList = challengeList;
}
/**
* This method returns list of default challenge levels.
* @return List that contains default challenge levels.
*/
public List<ChallengeLevel> getLevelList()
{
return challengeLevelList;
}
/**
* This method sets given list as default challenge level list.
* @param levelList new default challenge level list.
*/
public 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 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";
}
/**
* @param uniqueId - unique ID the uniqueId to set
*/
@Override
public void setUniqueId(String uniqueId)
{
// method not used.
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* Holds a list with default challenges.
*/
@Expose
private List<Challenge> challengeList;
/**
* 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;
}
}

View File

@ -127,13 +127,45 @@ public class ChallengesManager
{
this.challengeCacheData.clear();
this.levelCacheData.clear();
if (!this.playerCacheData.isEmpty())
{
// store player data before cleaning.
this.savePlayersData();
}
this.playerCacheData.clear();
this.addon.getLogger().info("Loading challenges...");
this.challengeDatabase.loadObjects().forEach(this::loadChallenge);
this.levelDatabase.loadObjects().forEach(this::loadLevel);
this.playersDatabase.loadObjects().forEach(this::loadPlayerData);
// It is not necessary to load all players in memory.
// this.playersDatabase.loadObjects().forEach(this::loadPlayerData);
}
/**
* Reload database. This method keeps cache memory.
*/
public void reload()
{
if (!this.playerCacheData.isEmpty())
{
// store player data before cleaning.
this.savePlayersData();
}
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);
// It is not necessary to load all players in memory.
// this.playersDatabase.loadObjects().forEach(this::loadPlayerData);
}
@ -287,6 +319,28 @@ public class ChallengesManager
}
/**
* This method removes given player from cache data.
* @param playerID player ID which cache data must be removed.
*/
public void removeFromCache(UUID playerID)
{
if (!this.settings.isStoreAsIslandData())
{
if (this.playerCacheData.containsKey(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.
// Unfortunately, I do not know all worlds. Checking everything would be bad. Probably, I could
// add extra map that links players with their cached island data?
}
// ---------------------------------------------------------------------
// Section: Other storing related methods
// ---------------------------------------------------------------------
@ -339,17 +393,17 @@ public class ChallengesManager
// The player is not in the cache
// Check if the player exists in the database
if (this.playersDatabase.objectExists(uniqueID.toString()))
if (this.playersDatabase.objectExists(uniqueID))
{
// Load player from database
ChallengesPlayerData data = this.playersDatabase.loadObject(uniqueID.toString());
ChallengesPlayerData data = this.playersDatabase.loadObject(uniqueID);
// Store in cache
this.playerCacheData.put(uniqueID, data);
}
else
{
// Create the player data
ChallengesPlayerData pd = new ChallengesPlayerData(uniqueID.toString());
ChallengesPlayerData pd = new ChallengesPlayerData(uniqueID);
this.playersDatabase.saveObject(pd);
// Add to cache
this.playerCacheData.put(uniqueID, pd);
@ -386,7 +440,7 @@ public class ChallengesManager
* This method saves given challenge object to database.
* @param challenge object that must be saved
*/
private void saveChallenge(Challenge challenge)
public void saveChallenge(Challenge challenge)
{
this.challengeDatabase.saveObject(challenge);
}
@ -405,7 +459,7 @@ public class ChallengesManager
* This method saves given level into database.
* @param level object that must be saved
*/
private void saveLevel(ChallengeLevel level)
public void saveLevel(ChallengeLevel level)
{
this.levelDatabase.saveObject(level);
}
@ -550,9 +604,23 @@ public class ChallengesManager
* @param challengeID - challengeID
*/
private void setChallengeComplete(@NonNull String storageDataID, @NonNull String challengeID)
{
this.setChallengeComplete(storageDataID, challengeID, 1);
}
/**
* Sets the challenge with given ID as complete and increments the number of times it has been
* completed
*
* @param storageDataID - playerData ID
* @param challengeID - challengeID
* @param count - how many times challenge is completed
*/
private void setChallengeComplete(@NonNull String storageDataID, @NonNull String challengeID, int count)
{
this.addPlayerData(storageDataID);
this.playerCacheData.get(storageDataID).setChallengeDone(challengeID);
this.playerCacheData.get(storageDataID).addChallengeDone(challengeID, count);
// Save
this.savePlayerData(storageDataID);
}
@ -788,9 +856,9 @@ public class ChallengesManager
* @param world - World where completion must be called.
* @param challenge - That must be completed.
*/
public void setChallengeComplete(User user, World world, Challenge challenge)
public void setChallengeComplete(User user, World world, Challenge challenge, int completionCount)
{
this.setChallengeComplete(user.getUniqueId(), world, challenge);
this.setChallengeComplete(user.getUniqueId(), world, challenge, completionCount);
}
@ -800,13 +868,14 @@ public class ChallengesManager
* @param world - World where completion must be called.
* @param challenge - That must be completed.
*/
public void setChallengeComplete(UUID userID, World world, Challenge challenge)
public void setChallengeComplete(UUID userID, World world, Challenge challenge, int completionCount)
{
String storageID = this.getDataUniqueID(userID, Util.getWorld(world));
this.setChallengeComplete(storageID, challenge.getUniqueId());
this.addLogEntry(storageID, new LogEntry.Builder("COMPLETE").
data("user-id", userID.toString()).
data("challenge-id", challenge.getUniqueId()).
data("completion-count", Integer.toString(completionCount)).
build());
// Fire event that user completes challenge
@ -814,7 +883,7 @@ public class ChallengesManager
new ChallengeCompletedEvent(challenge.getUniqueId(),
userID,
false,
1));
completionCount));
}
@ -1036,13 +1105,19 @@ public class ChallengesManager
* @param world - the world to check
* @return List of challenge names
*/
public List<String> getAllChallengesNames(World world)
public List<String> getAllChallengesNames(@NonNull World world)
{
String worldName = Util.getWorld(world).getName();
World gameWorld = Util.getWorld(world);
if (gameWorld == null)
{
return Collections.emptyList();
}
// TODO: Probably need to check also database.
return this.challengeCacheData.values().stream().
sorted(Comparator.comparing(Challenge::getOrder)).
filter(challenge -> challenge.getUniqueId().startsWith(worldName)).
filter(challenge -> challenge.getUniqueId().startsWith(gameWorld.getName())).
map(Challenge::getUniqueId).
collect(Collectors.toList());
}
@ -1054,12 +1129,18 @@ public class ChallengesManager
* @param world - the world to check
* @return List of challenges
*/
public List<Challenge> getAllChallenges(World world)
public List<Challenge> getAllChallenges(@NonNull World world)
{
String worldName = Util.getWorld(world).getName();
World gameWorld = Util.getWorld(world);
if (gameWorld == null)
{
return Collections.emptyList();
}
// TODO: Probably need to check also database.
return this.challengeCacheData.values().stream().
filter(challenge -> challenge.getUniqueId().startsWith(worldName)).
filter(challenge -> challenge.getUniqueId().startsWith(gameWorld.getName())).
sorted(Comparator.comparing(Challenge::getOrder)).
collect(Collectors.toList());
}
@ -1198,9 +1279,16 @@ public class ChallengesManager
* @param world for which levels must be searched.
* @return List with challenges in given world.
*/
public List<ChallengeLevel> getLevels(World world)
public List<ChallengeLevel> getLevels(@NonNull World world)
{
return this.getLevels(Util.getWorld(world).getName());
world = Util.getWorld(world);
if (world == null)
{
return Collections.emptyList();
}
return this.getLevels(world.getName());
}
@ -1374,42 +1462,53 @@ public class ChallengesManager
if (this.levelCacheData.containsKey(challengeLevel.getUniqueId()))
{
this.levelCacheData.remove(challengeLevel.getUniqueId());
// Remove challenge level from challenges object.
if (!challengeLevel.getChallenges().isEmpty())
{
challengeLevel.getChallenges().forEach(challengeID -> {
Challenge challenge = this.getChallenge(challengeID);
if (challenge != null)
{
challenge.setLevel(ChallengesManager.FREE);
}
});
}
this.levelDatabase.deleteObject(challengeLevel);
}
}
// ---------------------------------------------------------------------
// Section: Fix world duplication issue.
// ---------------------------------------------------------------------
/**
* This method returns if in given world has any stored challenge or level.
* @param world World that needs to be checked
* @return <code>true</code> if world has any challenge or level, otherwise <code>false</code>
*/
public boolean hasAnyChallengeData(@NonNull World world)
{
world = Util.getWorld(world);
if (world == null)
{
return false;
}
return this.hasAnyChallengeData(world.getName());
}
/**
* This allows to fix player data issue when world name is duplicated.
* @deprecated Will be removed in 0.7.0 release.
* This method returns if in given world has any stored challenge or level.
* @param worldName World name that needs to be checked
* @return <code>true</code> if world has any challenge or level, otherwise <code>false</code>
*/
@Deprecated
public void fixCorruptedPlayerData()
public boolean hasAnyChallengeData(@NonNull String worldName)
{
this.playersDatabase.loadObjects().forEach(playerData -> {
Map<String, Integer> completed = playerData.getChallengeStatus();
Map<String, Long> timeStamps = playerData.getChallengesTimestamp();
new ArrayList<>(completed.keySet()).forEach(challenge -> {
String correctName = challenge.replaceFirst("(\\w+)(?=(\\1))", "");
if (!correctName.isEmpty() && !correctName.equals(challenge))
{
completed.put(correctName, completed.get(challenge));
timeStamps.put(correctName, timeStamps.get(challenge));
completed.remove(challenge);
timeStamps.remove(challenge);
this.addon.log("ChallengeString was modified " + challenge + " was changed to " + correctName);
}
});
this.playerCacheData.put(playerData.getUniqueId(), playerData);
this.savePlayerData(playerData.getUniqueId());
});
return this.challengeDatabase.loadObjects().stream().anyMatch(
challenge -> challenge.getUniqueId().startsWith(worldName)) ||
this.levelDatabase.loadObjects().stream().anyMatch(
level -> level.getUniqueId().startsWith(worldName));
}
}

View File

@ -143,6 +143,17 @@ public class Settings implements DataObject
@ConfigEntry(path = "broadcast-messages")
private boolean broadcastMessages = true;
@ConfigComment("")
@ConfigComment("Shows a title screen for player after completion a challenge or level.")
@ConfigComment("Message can be edited via language settings.")
@ConfigEntry(path = "title.show-title")
private boolean showCompletionTitle = true;
@ConfigComment("")
@ConfigComment("Integer that represents how long title will be visible for player.")
@ConfigEntry(path = "title.title-showtime")
private int titleShowtime = 70;
@ConfigComment("")
@ConfigComment("This list stores GameModes in which Challenges addon should not work.")
@ConfigComment("To disable addon it is necessary to write its name in new line that starts with -. Example:")
@ -161,7 +172,7 @@ public class Settings implements DataObject
* Configuration version
*/
@ConfigComment("")
private String configVersion = "v2";
private String configVersion = "v3";
// ---------------------------------------------------------------------
@ -350,6 +361,48 @@ public class Settings implements DataObject
}
/**
* This method returns the showCompletionTitle object.
* @return the showCompletionTitle object.
*/
public boolean isShowCompletionTitle()
{
return this.showCompletionTitle;
}
/**
* This method returns the titleShowtime object.
* @return the titleShowtime object.
*/
public int getTitleShowtime()
{
return this.titleShowtime;
}
/**
* This method sets the titleShowtime object value.
* @param titleShowtime the titleShowtime object new value.
*
*/
public void setTitleShowtime(int titleShowtime)
{
this.titleShowtime = titleShowtime;
}
/**
* This method sets the showCompletionTitle object value.
* @param showCompletionTitle the showCompletionTitle object new value.
*
*/
public void setShowCompletionTitle(boolean showCompletionTitle)
{
this.showCompletionTitle = showCompletionTitle;
}
/**
* This method sets the lockedLevelIcon value.
* @param lockedLevelIcon the lockedLevelIcon new value.

View File

@ -50,7 +50,9 @@ public class ChallengesCommand extends CompositeCommand
public void setup()
{
this.setPermission(CHALLENGE_COMMAND);
this.setParametersHelp("challenges.commands.user.parameters");
this.setDescription("challenges.commands.user.description");
this.setParametersHelp("challenges.commands.user.main.parameters");
this.setDescription("challenges.commands.user.main.description");
new CompleteChallengeCommand(this.getAddon(), this);
}
}

View File

@ -40,8 +40,8 @@ public class ChallengesUserCommand extends CompositeCommand
{
this.setOnlyPlayer(true);
this.setPermission("challenges");
this.setParametersHelp("challenges.commands.user.parameters");
this.setDescription("challenges.commands.user.description");
this.setParametersHelp("challenges.commands.user.main.parameters");
this.setDescription("challenges.commands.user.main.description");
}

View File

@ -0,0 +1,147 @@
package world.bentobox.challenges.commands;
import java.util.*;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.util.Util;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.tasks.TryToComplete;
/**
* This command allows to complete challenges without a gui.
*/
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;
if (this.addon.getChallengesManager().hasAnyChallengeData(this.getWorld()))
{
// Strip world name from all challenges
this.challenges = this.addon.getChallengesManager().getAllChallengesNames(this.getWorld()).stream().
map(challenge -> challenge.replaceFirst(Util.getWorld(this.getWorld()).getName() + "_", "")).
collect(Collectors.toList());
}
}
/**
* {@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 = Util.getWorld(this.getWorld()).getName() + "_" + args.get(0);
Challenge challenge = this.addon.getChallengesManager().getChallenge(challengeName);
if (challenge != null)
{
return TryToComplete.complete(this.addon,
user,
challenge,
this.getWorld(),
this.getTopLabel(),
this.getPermissionPrefix());
}
else
{
user.sendMessage("challenges.errors.unknown-challenge");
this.showHelp(this, user);
return false;
}
}
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);
final List<String> returnList = new ArrayList<>();
final int size = args.size();
switch (size)
{
case 3:
// Create suggestions with all challenges that is available for users.
this.challenges.forEach(challenge -> {
returnList.addAll(Util.tabLimit(Collections.singletonList(challenge), lastString));
});
break;
case 4:
// Suggest a number of completions.
if (lastString.isEmpty() || lastString.matches("[0-9]*"))
{
returnList.addAll(Util.tabLimit(Collections.singletonList("<number>"), lastString));
}
break;
default:
{
returnList.addAll(Util.tabLimit(Collections.singletonList("help"), lastString));
break;
}
}
return Optional.of(returnList);
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* Variable that holds challenge addon. Single casting.
*/
private ChallengesAddon addon;
/**
* This list contains all challenge IDs without a world name.
*/
private List<String> challenges;
}

View File

@ -8,35 +8,44 @@ import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.panel.admin.AdminGUI;
public class Challenges extends CompositeCommand {
public class Challenges extends CompositeCommand
{
/**
* Admin command for challenges
*
* @param parent
*/
public Challenges(ChallengesAddon addon, CompositeCommand parent) {
public Challenges(ChallengesAddon addon, CompositeCommand parent)
{
super(addon, parent, "challenges");
}
@Override
public void setup() {
public void setup()
{
this.setPermission("admin.challenges");
this.setParametersHelp("challenges.commands.admin.main.parameters");
this.setDescription("challenges.commands.admin.main.description");
// Register sub commands
new ImportCommand(getAddon(), this);
// new CompleteChallenge(getAddon(), this);
new ReloadChallenges(getAddon(), this);
new ResetChallenge(getAddon(), this);
//new ShowChallenges(getAddon(), this);
//new CreateChallenge(getAddon(), this);
// Register sub commands
// This method reloads challenges addon
new ReloadChallenges(getAddon(), this);
// Import ASkyBlock Challenges
new ImportCommand(getAddon(), this);
// Defaults processing command
new DefaultsCommand(this.getAddon(), this);
}
@Override
public boolean execute(User user, String label, List<String> args) {
public boolean execute(User user, String label, List<String> args)
{
// Open up the admin challenges GUI
if (user.isPlayer()) {
if (user.isPlayer())
{
new AdminGUI((ChallengesAddon) this.getAddon(),
this.getWorld(),
user,
@ -47,5 +56,4 @@ public class Challenges extends CompositeCommand {
}
return false;
}
}

View File

@ -1,77 +0,0 @@
package world.bentobox.challenges.commands.admin;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
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.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.util.Util;
@Deprecated
public class CompleteChallenge extends CompositeCommand {
private ChallengesManager manager;
/**
* Admin command to complete user challenges
* @param parent
*/
public CompleteChallenge(Addon addon, CompositeCommand parent) {
super(addon, parent, "complete");
}
@Override
public void setup() {
this.setPermission("admin.challenges");
this.setParametersHelp("challenges.commands.admin.complete.parameters");
this.setDescription("challenges.commands.admin.complete.description");
manager = ((ChallengesAddon)getAddon()).getChallengesManager();
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.size() != 2) {
// Show help
showHelp(this, user);
return false;
}
// Get target player
UUID targetUUID = getPlayers().getUUID(args.get(0));
if (targetUUID == null) {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false;
}
if (!getPlugin().getIslands().hasIsland(getWorld(), targetUUID)) {
user.sendMessage("general.errors.player-has-no-island");
return false;
}
// Check for valid challenge name
if (!manager.containsChallenge(args.get(1))) {
user.sendMessage("challenges.admin.complete.unknown-challenge");
return false;
}
// Complete challenge
manager.setChallengeComplete(targetUUID, this.getWorld(), this.manager.getChallenge(args.get(1)), user.getUniqueId());
user.sendMessage("general.success");
return true;
}
@Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
if (args.size() == 3) {
// Online players
return Optional.of(Util.tabLimit(new ArrayList<>(Util.getOnlinePlayerList(user)), lastArg));
} else if (args.size() == 4) {
// Challenges in this world
return Optional.of(Util.tabLimit(manager.getAllChallengesNames(getWorld()), lastArg));
}
return Optional.empty();
}
}

View File

@ -0,0 +1,165 @@
package world.bentobox.challenges.commands.admin;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.util.Util;
import world.bentobox.challenges.ChallengesAddon;
/**
* This method generates default challenges file.
*/
public class DefaultsCommand extends CompositeCommand
{
/**
* Constructor that inits generate defaults command.
*
* @param addon Addon that inits this command
* @param cmd Parent command
*/
public DefaultsCommand(Addon addon, CompositeCommand cmd)
{
super(addon, cmd, "defaults");
this.addon = (ChallengesAddon) addon;
}
/**
* {@inheritDoc}
*/
@Override
public void setup()
{
this.setPermission("admin.challenges");
this.setParametersHelp("challenges.commands.admin.defaults.parameters");
this.setDescription("challenges.commands.admin.defaults.description");
// Register sub commands
// This method reloads challenges addon
new ImportCommand(this);
// Import ASkyBlock Challenges
new GenerateCommand(this);
}
/**
* {@inheritDoc}
*/
@Override
public boolean execute(User user, String label, List<String> args)
{
return this.showHelp(this, user);
}
// ---------------------------------------------------------------------
// Section: Private Classes
// ---------------------------------------------------------------------
/**
* This class allows to process import command.
*/
private class ImportCommand extends CompositeCommand
{
/**
* Default constructor for import method.
* @param parent composite command
*/
private ImportCommand(CompositeCommand parent)
{
super(DefaultsCommand.this.addon, parent, "import");
}
/**
* {@inheritDoc}
*/
@Override
public void setup()
{
this.setPermission("admin.challenges");
this.setParametersHelp("challenges.commands.admin.defaults-import.parameters");
this.setDescription("challenges.commands.admin.defaults-import.description");
}
/**
* {@inheritDoc}
*/
@Override
public boolean execute(User user, String label, List<String> args)
{
return DefaultsCommand.this.addon.getImportManager().loadDefaultChallenges(user, this.getWorld());
}
}
/**
* This class allows to process generate command.
*/
private class GenerateCommand extends CompositeCommand
{
/**
* Default constructor for generate method.
* @param parent composite command
*/
private GenerateCommand(CompositeCommand parent)
{
super(DefaultsCommand.this.addon, parent, "generate");
}
/**
* {@inheritDoc}
*/
@Override
public void setup()
{
this.setPermission("admin.challenges");
this.setParametersHelp("challenges.commands.admin.defaults-generate.parameters");
this.setDescription("challenges.commands.admin.defaults-generate.description");
}
/**
* {@inheritDoc}
*/
@Override
public boolean execute(User user, String label, List<String> args)
{
return DefaultsCommand.this.addon.getImportManager().generateDefaultChallengeFile(
user,
this.getWorld(),
!args.isEmpty() && args.get(0).equalsIgnoreCase("overwrite"));
}
/**
* {@inheritDoc}
*/
@Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args)
{
String lastArg = !args.isEmpty() ? args.get(args.size() - 1) : "";
return Optional.of(Util.tabLimit(Collections.singletonList("overwrite"), lastArg));
}
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* Holds challenges addon as variable.
*/
private ChallengesAddon addon;
}

View File

@ -8,36 +8,65 @@ import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
public class ReloadChallenges extends CompositeCommand {
private ChallengesManager manager;
/**
* This class allows to reload challenges addon.
*/
public class ReloadChallenges extends CompositeCommand
{
/**
* Admin command to complete user challenges
* Admin command to reloads challenges addon.
* @param parent
*/
public ReloadChallenges(Addon addon, CompositeCommand parent) {
public ReloadChallenges(Addon addon, CompositeCommand parent)
{
super(addon, parent, "reload");
this.manager = ((ChallengesAddon) getAddon()).getChallengesManager();
}
/**
* {@inheritDoc}
*/
@Override
public void setup() {
public void setup()
{
this.setPermission("admin.challenges");
this.setParametersHelp("challenges.commands.admin.reload.parameters");
this.setDescription("challenges.commands.admin.reload.description");
manager = ((ChallengesAddon)getAddon()).getChallengesManager();
}
/**
* {@inheritDoc}
*/
@Override
public boolean execute(User user, String label, List<String> args) {
if (!args.isEmpty()) {
// Show help
showHelp(this, user);
public boolean execute(User user, String label, List<String> args)
{
if (args.isEmpty())
{
this.manager.load();
user.sendMessage("general.success");
return true;
}
else if (args.get(0).equalsIgnoreCase("hard"))
{
this.manager.reload();
user.sendMessage("general.success");
return true;
}
else
{
this.showHelp(this, user);
return false;
}
manager.load();
user.sendMessage("general.success");
return true;
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
private ChallengesManager manager;
}

View File

@ -1,81 +0,0 @@
package world.bentobox.challenges.commands.admin;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
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.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.util.Util;
/**
* @deprecated Challenges can be reset via GUI.
*/
@Deprecated
public class ResetChallenge extends CompositeCommand {
private ChallengesManager manager;
/**
* Admin command to complete user challenges
* @param parent
*/
public ResetChallenge(Addon addon, CompositeCommand parent) {
super(addon, parent, "reset");
}
@Override
public void setup() {
this.setPermission("admin.challenges");
this.setParametersHelp("challenges.commands.admin.reset.parameters");
this.setDescription("challenges.commands.admin.reset.description");
manager = ((ChallengesAddon)getAddon()).getChallengesManager();
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.size() != 2) {
// Show help
showHelp(this, user);
return false;
}
// Get target player
UUID targetUUID = getPlayers().getUUID(args.get(0));
if (targetUUID == null) {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false;
}
if (!getPlugin().getIslands().hasIsland(getWorld(), targetUUID)) {
user.sendMessage("general.errors.player-has-no-island");
return false;
}
// Check for valid challenge name
if (!manager.containsChallenge(args.get(1))) {
user.sendMessage("challenges.errors.unknown-challenge");
return false;
}
// Complete challenge
manager.resetChallenge(targetUUID, this.getWorld(), manager.getChallenge(args.get(1)), user.getUniqueId());
user.sendMessage("general.success");
return true;
}
@Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
if (args.size() == 3) {
// Online players
return Optional.of(Util.tabLimit(new ArrayList<>(Util.getOnlinePlayerList(user)), lastArg));
} else if (args.size() == 4) {
// Challenges in this world
return Optional.of(Util.tabLimit(manager.getAllChallengesNames(getWorld()), lastArg));
}
return Optional.empty();
}
}

View File

@ -1,12 +1,8 @@
package world.bentobox.challenges.database.object;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
import org.bukkit.Material;
import org.bukkit.World;
@ -1025,4 +1021,62 @@ public class Challenge implements DataObject
return uniqueId.equals(other.uniqueId);
}
}
/**
* Clone method that returns clone of current challenge.
* @return Challenge that is cloned from current object.
*/
@Override
public Challenge clone()
{
Challenge clone;
try
{
clone = (Challenge) super.clone();
}
catch (CloneNotSupportedException e)
{
clone = new Challenge();
clone.setUniqueId(this.uniqueId);
clone.setFriendlyName(this.friendlyName);
clone.setDeployed(this.deployed);
clone.setDescription(new ArrayList<>(this.description));
clone.setIcon(this.icon.clone());
clone.setOrder(this.order);
clone.setChallengeType(ChallengeType.valueOf(this.challengeType.name()));
clone.setEnvironment(new HashSet<>(this.environment));
clone.setLevel(this.level);
clone.setRemoveWhenCompleted(this.removeWhenCompleted);
clone.setRequiredPermissions(new HashSet<>(this.requiredPermissions));
clone.setRequiredBlocks(new HashMap<>(this.requiredBlocks));
clone.setRemoveBlocks(this.removeBlocks);
clone.setRequiredEntities(new HashMap<>(this.requiredEntities));
clone.setRemoveEntities(this.removeEntities);
clone.setRequiredItems(this.requiredItems.stream().map(ItemStack::clone).collect(Collectors.toCollection(() -> new ArrayList<>(this.requiredItems.size()))));
clone.setTakeItems(this.takeItems);
clone.setRequiredExperience(this.requiredExperience);
clone.setTakeExperience(this.takeExperience);
clone.setRequiredMoney(this.requiredMoney);
clone.setTakeMoney(this.takeMoney);
clone.setRequiredIslandLevel(this.requiredIslandLevel);
clone.setSearchRadius(this.searchRadius);
clone.setRewardText(this.rewardText);
clone.setRewardItems(this.rewardItems.stream().map(ItemStack::clone).collect(Collectors.toCollection(() -> new ArrayList<>(this.rewardItems.size()))));
clone.setRewardExperience(this.rewardExperience);
clone.setRewardMoney(this.rewardMoney);
clone.setRewardCommands(new ArrayList<>(this.rewardCommands));
clone.setRepeatable(this.repeatable);
clone.setRepeatRewardText(this.repeatRewardText);
clone.setMaxTimes(this.maxTimes);
clone.setRepeatExperienceReward(this.repeatExperienceReward);
clone.setRepeatItemReward(this.repeatItemReward.stream().map(ItemStack::clone).collect(Collectors.toCollection(() -> new ArrayList<>(this.repeatItemReward.size()))));
clone.setRepeatMoneyReward(this.repeatMoneyReward);
clone.setRepeatRewardCommands(new ArrayList<>(this.repeatRewardCommands));
}
return clone;
}
}

View File

@ -8,6 +8,7 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.configuration.ConfigComment;
import world.bentobox.bentobox.database.objects.DataObject;
@ -496,4 +497,40 @@ public class ChallengeLevel implements DataObject, Comparable<ChallengeLevel>
return uniqueId.equals(other.uniqueId);
}
}
/**
* Clone method that returns clone of current challengeLevel.
* @return ChallengeLevel that is cloned from current object.
*/
@Override
public ChallengeLevel clone()
{
ChallengeLevel clone;
try
{
clone = (ChallengeLevel) super.clone();
}
catch (CloneNotSupportedException e)
{
clone = new ChallengeLevel();
clone.setUniqueId(this.uniqueId);
clone.setFriendlyName(this.friendlyName);
clone.setIcon(this.icon.clone());
clone.setLockedIcon(this.lockedIcon != null ? this.lockedIcon.clone() : null);
clone.setWorld(this.world);
clone.setOrder(this.order);
clone.setWaiverAmount(this.waiverAmount);
clone.setUnlockMessage(this.unlockMessage);
clone.setRewardText(this.rewardText);
clone.setRewardItems(this.rewardItems.stream().map(ItemStack::clone).collect(Collectors.toCollection(() -> new ArrayList<>(this.rewardItems.size()))));
clone.setRewardExperience(this.rewardExperience);
clone.setRewardMoney(this.rewardMoney);
clone.setRewardCommands(new ArrayList<>(this.rewardCommands));
clone.setChallenges(new HashSet<>(this.challenges));
}
return clone;
}
}

View File

@ -1,226 +0,0 @@
package world.bentobox.challenges.database.object;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.inventory.ItemStack;
import world.bentobox.challenges.ChallengesManager;
import world.bentobox.bentobox.api.configuration.ConfigComment;
import world.bentobox.bentobox.database.objects.DataObject;
/**
* Represent a challenge level
* @author tastybento
*
*/
@Deprecated
public class ChallengeLevels implements DataObject, Comparable<ChallengeLevels> {
public ChallengeLevels() {}
@ConfigComment("A friendly name for the level. If blank, level name is used.")
private String friendlyName = "";
@ConfigComment("Worlds that this level applies in. String list.")
private List<String> worlds = new ArrayList<>();
@ConfigComment("Commands to run when this level is completed")
private List<String> rewardCommands = new ArrayList<>();
@ConfigComment("Level name")
private String uniqueId = ChallengesManager.FREE;
@ConfigComment("The number of undone challenges that can be left on this level before unlocking next level")
private int waiveramount = 1;
@ConfigComment("The ordering of the levels, lowest to highest")
private int order = 0;
@ConfigComment("The message shown when unlocking this level")
private String unlockMessage = "";
@ConfigComment("Unlock reward description")
private String rewardDescription = "";
@ConfigComment("List of reward itemstacks")
private List<ItemStack> rewardItems;
@ConfigComment("Unlock experience reward")
private int expReward;
@ConfigComment("Unlock money reward")
private int moneyReward;
public String getFriendlyName() {
return friendlyName;
}
public List<String> getRewardCommands() {
return rewardCommands = new ArrayList<>();
}
@Override
public String getUniqueId() {
return uniqueId;
}
/**
* Get the number of undone tasks that can be left on a level before unlocking next level
* @return
*/
public int getWaiveramount() {
return waiveramount;
}
public void setFriendlyName(String friendlyName) {
this.friendlyName = friendlyName;
}
public void setRewardCommands(List<String> rewardCommands) {
this.rewardCommands = rewardCommands;
}
@Override
public void setUniqueId(String uniqueId) {
this.uniqueId = uniqueId;
}
public void setWaiveramount(int waiveramount) {
this.waiveramount = waiveramount;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
@Override
public int compareTo(ChallengeLevels o) {
return Integer.compare(this.order, o.order);
}
/**
* @return the rewardDescription
*/
public String getRewardDescription() {
return rewardDescription;
}
/**
* @param rewardDescription the rewardDescription to set
*/
public void setRewardDescription(String rewardDescription) {
this.rewardDescription = rewardDescription;
}
/**
* @return the rewardItems
*/
public List<ItemStack> getRewardItems() {
return rewardItems;
}
/**
* @param rewardItems the rewardItems to set
*/
public void setRewardItems(List<ItemStack> rewardItems) {
this.rewardItems = rewardItems;
}
/**
* @return the expReward
*/
public int getExpReward() {
return expReward;
}
/**
* @param expReward the expReward to set
*/
public void setExpReward(int expReward) {
this.expReward = expReward;
}
/**
* @return the moneyReward
*/
public int getMoneyReward() {
return moneyReward;
}
/**
* @param moneyReward the moneyReward to set
*/
public void setMoneyReward(int moneyReward) {
this.moneyReward = moneyReward;
}
/**
* @return the unlockMessage
*/
public String getUnlockMessage() {
return unlockMessage;
}
/**
* @param unlockMessage the unlockMessage to set
*/
public void setUnlockMessage(String unlockMessage) {
this.unlockMessage = unlockMessage;
}
/**
* @return the worlds
*/
public List<String> getWorlds() {
return worlds;
}
/**
* @param worlds the worlds to set
*/
public void setWorlds(List<String> worlds) {
this.worlds = worlds;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof ChallengeLevels)) {
return false;
}
ChallengeLevels other = (ChallengeLevels) obj;
if (uniqueId == null) {
if (other.uniqueId != null) {
return false;
}
} else if (!uniqueId.equals(other.uniqueId)) {
return false;
}
return true;
}
}

View File

@ -1,634 +0,0 @@
package world.bentobox.challenges.database.object;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import world.bentobox.challenges.ChallengesManager;
import world.bentobox.bentobox.api.configuration.ConfigComment;
import world.bentobox.bentobox.database.objects.DataObject;
/**
* Data object for challenges
* @author tastybento
*
*/
@Deprecated
public class Challenges implements DataObject {
public Challenges() {}
public enum ChallengeType {
/**
* This challenge only shows and icon in the GUI and doesn't do anything.
*/
ICON,
/**
* The player must have the items on them.
*/
INVENTORY,
/**
* The island level has to be equal or over this amount. Only works if there's an island level plugin installed.
*/
LEVEL,
/**
* Items or required entities have to be within x blocks of the player.
*/
ISLAND
}
// The order of the fields is the order shown in the YML files
@ConfigComment("Whether this challenge is deployed or not")
private boolean deployed;
// Description
@ConfigComment("Name of the icon and challenge. May include color codes. Single line.")
private String friendlyName = "";
@ConfigComment("Description of the challenge. Will become the lore on the icon. Can include & color codes. String List.")
private List<String> description = new ArrayList<>();
@ConfigComment("The icon in the GUI for this challenge. ItemStack.")
private ItemStack icon = new ItemStack(Material.PAPER);
@ConfigComment("Icon slot where this challenge should be placed. 0 to 49. A negative value means any slot")
private int slot = -1;
// Definition
@ConfigComment("Challenge level. Default is Free")
private String level = ChallengesManager.FREE;
@ConfigComment("Challenge type can be ICON, INVENTORY, LEVEL or ISLAND.")
private ChallengeType challengeType = ChallengeType.INVENTORY;
@ConfigComment("World where this challenge operates. List only overworld. Nether and end are automatically covered.")
private String world = "";
@ConfigComment("List of environments where this challenge will occur: NETHER, NORMAL, THE_END. Leave blank for all.")
private List<World.Environment> environment = new ArrayList<>();
@ConfigComment("The required permissions to see this challenge. String list.")
private Set<String> reqPerms = new HashSet<>();
@ConfigComment("The number of blocks around the player to search for items on an island")
private int searchRadius = 10;
@ConfigComment("If true, the challenge will disappear from the GUI when completed")
private boolean removeWhenCompleted;
@ConfigComment("Take the required items from the player")
private boolean takeItems = true;
@ConfigComment("Take the money from the player")
private boolean takeMoney = false;
// Requirements
@ConfigComment("This is a map of the blocks required in a ISLAND challenge. Material, Integer")
private Map<Material, Integer> requiredBlocks = new EnumMap<>(Material.class);
@ConfigComment("The items that must be in the inventory to complete the challenge. ItemStack List.")
private List<ItemStack> requiredItems = new ArrayList<>();
@ConfigComment("Any entities that must be in the area for ISLAND type challenges. Map EntityType, Number")
private Map<EntityType, Integer> requiredEntities = new EnumMap<>(EntityType.class);
@ConfigComment("Required experience")
private int reqExp;
@ConfigComment("Required island level for this challenge. Only works if Level Addon is being used.")
private long reqIslandlevel;
@ConfigComment("Required money")
private int reqMoney;
// Rewards
@ConfigComment("List of items the player will receive first time. ItemStack List.")
private List<ItemStack> rewardItems = new ArrayList<>();
@ConfigComment("If this is blank, the reward text will be auto-generated, otherwise this will be used.")
private String rewardText = "";
@ConfigComment("Experience point reward")
private int rewardExp;
@ConfigComment("Money reward")
private int rewardMoney;
@ConfigComment("Commands to run when the player completes the challenge for the first time. String List")
private List<String> rewardCommands = new ArrayList<>();
// Repeatable
@ConfigComment("True if the challenge is repeatable")
private boolean repeatable;
@ConfigComment("Maximum number of times the challenge can be repeated")
private int maxTimes = 1;
@ConfigComment("Repeat exp award")
private int repeatExpReward;
@ConfigComment("Reward items for repeating the challenge. List of ItemStacks.")
private List<ItemStack> repeatItemReward = new ArrayList<>();
@ConfigComment("Repeat money award")
private int repeatMoneyReward;
@ConfigComment("Commands to run when challenge is repeated. String List.")
private List<String> repeatRewardCommands = new ArrayList<>();
@ConfigComment("Description of the repeat rewards. If blank, it will be autogenerated.")
private String repeatRewardText = "";
@ConfigComment("Unique name of the challenge")
private String uniqueId = "";
/*
* END OF SETTINGS
*/
/**
* @return the challengeType
*/
public ChallengeType getChallengeType() {
return challengeType;
}
/**
* @param challengeType the challengeType to set
*/
public void setChallengeType(ChallengeType challengeType) {
this.challengeType = challengeType;
}
/**
* @return the deployed
*/
public boolean isDeployed() {
return deployed;
}
/**
* @param deployed the deployed to set
*/
public void setDeployed(boolean deployed) {
this.deployed = deployed;
}
/**
* @return the description
*/
public List<String> getDescription() {
return description;
}
/**
* @param description the description to set
*/
public void setDescription(List<String> description) {
this.description = description;
}
/**
* @return the expReward
*/
public int getRewardExp() {
return rewardExp;
}
/**
* @param expReward the expReward to set
*/
public void setRewardExp(int expReward) {
this.rewardExp = expReward;
}
/**
* @return the friendlyName
*/
public String getFriendlyName() {
return friendlyName;
}
/**
* @param friendlyName the friendlyName to set
*/
public void setFriendlyName(String friendlyName) {
this.friendlyName = friendlyName;
}
/**
* @return the icon
*/
public ItemStack getIcon() {
return icon != null ? icon.clone() : new ItemStack(Material.MAP);
}
/**
* @param icon the icon to set
*/
public void setIcon(ItemStack icon) {
this.icon = icon;
}
/**
* @return the level
*/
public String getLevel() {
return level;
}
/**
* @param level the level to set
*/
public void setLevel(String level) {
if (level.isEmpty()) {
level = ChallengesManager.FREE;
}
this.level = level;
}
/**
* @return the maxTimes
*/
public int getMaxTimes() {
return maxTimes;
}
/**
* @param maxTimes the maxTimes to set
*/
public void setMaxTimes(int maxTimes) {
this.maxTimes = maxTimes;
}
/**
* @return the moneyReward
*/
public int getRewardMoney() {
return rewardMoney;
}
/**
* @param moneyReward the moneyReward to set
*/
public void setRewardMoney(int moneyReward) {
this.rewardMoney = moneyReward;
}
/**
* @return the removeWhenCompleted
*/
public boolean isRemoveWhenCompleted() {
return removeWhenCompleted;
}
/**
* @param removeWhenCompleted the removeWhenCompleted to set
*/
public void setRemoveWhenCompleted(boolean removeWhenCompleted) {
this.removeWhenCompleted = removeWhenCompleted;
}
/**
* @return the repeatable
*/
public boolean isRepeatable() {
return repeatable;
}
/**
* @param repeatable the repeatable to set
*/
public void setRepeatable(boolean repeatable) {
this.repeatable = repeatable;
}
/**
* @return the repeatExpReward
*/
public int getRepeatExpReward() {
return repeatExpReward;
}
/**
* @param repeatExpReward the repeatExpReward to set
*/
public void setRepeatExpReward(int repeatExpReward) {
this.repeatExpReward = repeatExpReward;
}
/**
* @return the repeatItemReward
*/
public List<ItemStack> getRepeatItemReward() {
return repeatItemReward;
}
/**
* @param repeatItemReward the repeatItemReward to set
*/
public void setRepeatItemReward(List<ItemStack> repeatItemReward) {
this.repeatItemReward = repeatItemReward;
}
/**
* @return the repeatMoneyReward
*/
public int getRepeatMoneyReward() {
return repeatMoneyReward;
}
/**
* @param repeatMoneyReward the repeatMoneyReward to set
*/
public void setRepeatMoneyReward(int repeatMoneyReward) {
this.repeatMoneyReward = repeatMoneyReward;
}
/**
* @return the repeatRewardCommands
*/
public List<String> getRepeatRewardCommands() {
return repeatRewardCommands;
}
/**
* @param repeatRewardCommands the repeatRewardCommands to set
*/
public void setRepeatRewardCommands(List<String> repeatRewardCommands) {
this.repeatRewardCommands = repeatRewardCommands;
}
/**
* @return the repeatRewardText
*/
public String getRepeatRewardText() {
return repeatRewardText;
}
/**
* @param repeatRewardText the repeatRewardText to set
*/
public void setRepeatRewardText(String repeatRewardText) {
this.repeatRewardText = repeatRewardText;
}
/**
* @return the reqExp
*/
public int getReqExp() {
return reqExp;
}
/**
* @param reqExp the reqExp to set
*/
public void setReqExp(int reqExp) {
this.reqExp = reqExp;
}
/**
* @return the reqIslandlevel
*/
public long getReqIslandlevel() {
return reqIslandlevel;
}
/**
* @param reqIslandlevel the reqIslandlevel to set
*/
public void setReqIslandlevel(long reqIslandlevel) {
this.reqIslandlevel = reqIslandlevel;
}
/**
* @return the reqMoney
*/
public int getReqMoney() {
return reqMoney;
}
/**
* @param reqMoney the reqMoney to set
*/
public void setReqMoney(int reqMoney) {
this.reqMoney = reqMoney;
}
/**
* @return the reqPerms
*/
public Set<String> getReqPerms() {
return reqPerms;
}
/**
* @param reqPerms the reqPerms to set
*/
public void setReqPerms(Set<String> reqPerms) {
this.reqPerms = reqPerms;
}
/**
* @return the requiredItems
*/
public List<ItemStack> getRequiredItems() {
return requiredItems;
}
/**
* @param requiredItems the requiredItems to set
*/
public void setRequiredItems(List<ItemStack> requiredItems) {
this.requiredItems = requiredItems;
}
/**
* @return requiredEntities
*/
public Map<EntityType, Integer> getRequiredEntities() {
return requiredEntities;
}
/**
* @param requiredEntities the requiredEntities to set
*/
public void setRequiredEntities(Map<EntityType, Integer> requiredEntities) {
this.requiredEntities = requiredEntities;
}
/**
* @return the requiredBlocks
*/
public Map<Material, Integer> getRequiredBlocks() {
return requiredBlocks;
}
/**
* @param map the requiredBlocks to set
*/
public void setRequiredBlocks(Map<Material, Integer> map) {
this.requiredBlocks = map;
}
/**
* @return the rewardCommands
*/
public List<String> getRewardCommands() {
return rewardCommands;
}
/**
* @param rewardCommands the rewardCommands to set
*/
public void setRewardCommands(List<String> rewardCommands) {
this.rewardCommands = rewardCommands;
}
/**
* @return the itemReward
*/
public List<ItemStack> getRewardItems() {
return rewardItems;
}
/**
* @param itemReward the itemReward to set
*/
public void setRewardItems(List<ItemStack> itemReward) {
this.rewardItems = itemReward;
}
/**
* @return the rewardText
*/
public String getRewardText() {
return rewardText;
}
/**
* @param rewardText the rewardText to set
*/
public void setRewardText(String rewardText) {
this.rewardText = rewardText;
}
/**
* @return the searchRadius
*/
public int getSearchRadius() {
return searchRadius;
}
/**
* @param searchRadius the searchRadius to set
*/
public void setSearchRadius(int searchRadius) {
this.searchRadius = searchRadius;
}
/**
* @return the slot
*/
public int getSlot() {
return slot;
}
/**
* @param slot the slot to set
*/
public void setSlot(int slot) {
this.slot = slot;
}
/**
* @return the takeItems
*/
public boolean isTakeItems() {
return takeItems;
}
/**
* @param takeItems the takeItems to set
*/
public void setTakeItems(boolean takeItems) {
this.takeItems = takeItems;
}
/**
* @return the takeMoney
*/
public boolean isTakeMoney() {
return takeMoney;
}
/**
* @param takeMoney the takeMoney to set
*/
public void setTakeMoney(boolean takeMoney) {
this.takeMoney = takeMoney;
}
/**
* @return the environment
*/
public List<World.Environment> getEnvironment() {
return environment;
}
/**
* @param environment the environment to set
*/
public void setEnvironment(List<World.Environment> environment) {
this.environment = environment;
}
/**
* @return the worlds
*/
public String getWorld() {
return world;
}
/**
* @param worlds the worlds to set
*/
public void setWorld(String world) {
this.world = world;
}
/**
* @return the uniqueId
*/
@Override
public String getUniqueId() {
return uniqueId;
}
/**
* @param uniqueId the uniqueId to set
*/
@Override
public void setUniqueId(String uniqueId) {
this.uniqueId = uniqueId;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Challenges)) {
return false;
}
Challenges other = (Challenges) obj;
if (uniqueId == null) {
if (other.uniqueId != null) {
return false;
}
} else if (!uniqueId.equals(other.uniqueId)) {
return false;
}
return true;
}
}

View File

@ -217,8 +217,21 @@ public class ChallengesPlayerData implements DataObject
*/
public void setChallengeDone(@NonNull String challengeName)
{
int times = challengeStatus.getOrDefault(challengeName, 0) + 1;
challengeStatus.put(challengeName, times);
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());
}

View File

@ -4,6 +4,8 @@ package world.bentobox.challenges.listeners;
import org.bukkit.event.EventHandler;
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;
@ -20,16 +22,45 @@ public class SaveListener implements Listener
}
/**
* This event listener handles world save event.
* @param e World Save event.
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onWorldSave(WorldSaveEvent e)
{
if (!this.addon.getChallengesManager().getAllChallenges(e.getWorld()).isEmpty())
// Save only for worlds where exist any challenge addon data.
if (this.addon.getChallengesManager().hasAnyChallengeData(e.getWorld()))
{
this.addon.getChallengesManager().save();
}
}
/**
* This event listener handles player kick event.
* If player is kicked, then remove it from player cache data.
* @param e PlayerKickEvent
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerKickEvent(PlayerKickEvent e)
{
this.addon.getChallengesManager().removeFromCache(e.getPlayer().getUniqueId());
}
/**
* This event listener handles player quit event.
* If player quits server, then remove it from player cache data.
* @param e PlayerQuitEvent
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerQuitEvent(PlayerQuitEvent e)
{
this.addon.getChallengesManager().removeFromCache(e.getPlayer().getUniqueId());
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------

View File

@ -20,6 +20,7 @@ import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.ChallengesManager;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.utils.GuiUtils;
import world.bentobox.challenges.utils.LevelStatus;
@ -101,6 +102,10 @@ public abstract class CommonGUI
protected static final String IMPORT = "import";
protected static final String DEFAULT = "defaults";
protected static final String GENERATE = "generate";
protected static final String SETTINGS = "settings";
protected static final String DELETE = "delete";
@ -239,7 +244,13 @@ public abstract class CommonGUI
return null;
}
return new PanelItem(icon, name, description, false, clickHandler, false);
return new PanelItemBuilder().
icon(icon).
name(name).
description(description).
glow(false).
clickHandler(clickHandler).
build();
}
@ -287,8 +298,19 @@ public abstract class CommonGUI
{
case 'l':
{
result.add(this.user.getTranslation("challenges.gui.challenge-description.level",
"[level]", manager.getLevel(challenge).getFriendlyName()));
ChallengeLevel level = manager.getLevel(challenge);
if (level == null)
{
result.add(this.user.getTranslation("challenges.errors.missing-level",
"[level]", challenge.getLevel()));
}
else
{
result.add(this.user.getTranslation("challenges.gui.challenge-description.level",
"[level]", level.getFriendlyName()));
}
break;
}
case 's':

View File

@ -8,6 +8,7 @@ import org.bukkit.inventory.ItemStack;
import net.wesjd.anvilgui.AnvilGUI;
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.bentobox.util.Util;
import world.bentobox.challenges.ChallengesAddon;
@ -55,9 +56,9 @@ public class AdminGUI extends CommonGUI
DELETE_CHALLENGE,
DELETE_LEVEL,
IMPORT_CHALLENGES,
BACKWARD_CHALLENGES,
BACKWARD_PLAYER_DATA,
EDIT_SETTINGS
EDIT_SETTINGS,
DEFAULT_IMPORT_CHALLENGES,
DEFAULT_EXPORT_CHALLENGES
}
@ -112,8 +113,9 @@ public class AdminGUI extends CommonGUI
// Import Challenges
panelBuilder.item(15, this.createButton(Button.IMPORT_CHALLENGES));
panelBuilder.item(24, this.createButton(Button.BACKWARD_CHALLENGES));
panelBuilder.item(33, this.createButton(Button.BACKWARD_PLAYER_DATA));
panelBuilder.item(24, this.createButton(Button.DEFAULT_IMPORT_CHALLENGES));
// Not added as I do not think admins should use it. It still will be able via command.
// panelBuilder.item(33, this.createButton(Button.DEFAULT_EXPORT_CHALLENGES));
// Edit Addon Settings
panelBuilder.item(16, this.createButton(Button.EDIT_SETTINGS));
@ -374,16 +376,16 @@ public class AdminGUI extends CommonGUI
break;
}
case BACKWARD_CHALLENGES:
case DEFAULT_IMPORT_CHALLENGES:
{
permissionSuffix = IMPORT;
permissionSuffix = DEFAULT;
name = this.user.getTranslation("challenges.gui.buttons.admin.backward");
description = this.user.getTranslation("challenges.gui.descriptions.admin.backward");
name = this.user.getTranslation("challenges.gui.buttons.admin.default-import");
description = this.user.getTranslation("challenges.gui.descriptions.admin.default-import");
icon = new ItemStack(Material.HOPPER);
clickHandler = (panel, user, clickType, slot) -> {
this.addon.getImportManager().
importPreviousChallenges(this.user, this.world, false);
// Run import command.
this.user.performCommand(this.topLabel + " " + CHALLENGES + " " + DEFAULT + " " + IMPORT);
return true;
};
@ -391,27 +393,28 @@ public class AdminGUI extends CommonGUI
break;
}
case BACKWARD_PLAYER_DATA:
case DEFAULT_EXPORT_CHALLENGES:
{
permissionSuffix = IMPORT;
permissionSuffix = DEFAULT;
name = this.user.getTranslation("challenges.gui.buttons.admin.backward-player");
description = this.user.getTranslation("challenges.gui.descriptions.admin.backward-player");
name = this.user.getTranslation("challenges.gui.buttons.admin.default-export");
description = this.user.getTranslation("challenges.gui.descriptions.admin.default-export");
icon = new ItemStack(Material.HOPPER);
clickHandler = (panel, user, clickType, slot) -> {
new ConfirmationGUI(this.user, status -> {
if (status)
{
this.addon.getChallengesManager().fixCorruptedPlayerData();
}
if (clickType.isRightClick())
{
this.overwriteMode = !this.overwriteMode;
this.build();
});
}
else
{
// Run import command.
this.user.performCommand(this.topLabel + " " + CHALLENGES + " " + DEFAULT + " " + GENERATE +
(this.overwriteMode ? " overwrite" : ""));
}
return true;
};
glow = false;
glow = this.overwriteMode;
break;
}
@ -453,6 +456,12 @@ public class AdminGUI extends CommonGUI
};
}
return new PanelItem(icon, name, GuiUtils.stringSplit(description, this.addon.getChallengesSettings().getLoreLineLength()), glow, clickHandler, false);
return new PanelItemBuilder().
icon(icon).
name(name).
description(GuiUtils.stringSplit(description, this.addon.getChallengesSettings().getLoreLineLength())).
glow(glow).
clickHandler(clickHandler).
build();
}
}

View File

@ -7,10 +7,12 @@ import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import java.util.*;
import java.util.stream.Collectors;
import net.wesjd.anvilgui.AnvilGUI;
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;
@ -115,6 +117,10 @@ public class EditChallengeGUI extends CommonGUI
panelBuilder.item(44, this.returnButton);
// Every time when this GUI is build, save challenge
// This will ensure that all main things will be always stored
this.addon.getChallengesManager().saveChallenge(this.challenge);
panelBuilder.build();
}
@ -281,7 +287,13 @@ public class EditChallengeGUI extends CommonGUI
return null;
}
return new PanelItem(icon, name, GuiUtils.stringSplit(description, this.addon.getChallengesSettings().getLoreLineLength()), glow, clickHandler, false);
return new PanelItemBuilder().
icon(icon).
name(name).
description(GuiUtils.stringSplit(description, this.addon.getChallengesSettings().getLoreLineLength())).
glow(glow).
clickHandler(clickHandler).
build();
}
@ -647,8 +659,14 @@ public class EditChallengeGUI extends CommonGUI
"[value]", Integer.toString(this.challenge.getSearchRadius())));
icon = new ItemStack(Material.COBBLESTONE_WALL);
// Search radius should not be larger then island radius.
int maxSearchDistance =
this.addon.getPlugin().getIWM().getAddon(this.world).map(gameModeAddon ->
gameModeAddon.getWorldSettings().getIslandDistance()).orElse(100);
clickHandler = (panel, user, clickType, slot) -> {
new NumberGUI(this.user, this.challenge.getSearchRadius(), 0, lineLength, (status, value) -> {
new NumberGUI(this.user, this.challenge.getSearchRadius(), 0, maxSearchDistance, lineLength, (status, value) -> {
if (status)
{
this.challenge.setSearchRadius(value);
@ -806,27 +824,19 @@ public class EditChallengeGUI extends CommonGUI
description.add(this.user.getTranslation("challenges.gui.descriptions.current-value",
"[value]", Long.toString(this.challenge.getRequiredIslandLevel())));
if (this.addon.isLevelProvided())
{
icon = new ItemStack(Material.BEACON);
clickHandler = (panel, user, clickType, slot) -> {
new NumberGUI(this.user, (int) this.challenge.getRequiredIslandLevel(), lineLength, (status, value) -> {
if (status)
{
this.challenge.setRequiredIslandLevel(value);
}
icon = new ItemStack(this.addon.isLevelProvided() ? Material.BEACON : Material.BARRIER);
clickHandler = (panel, user, clickType, slot) -> {
new NumberGUI(this.user, (int) this.challenge.getRequiredIslandLevel(), lineLength, (status, value) -> {
if (status)
{
this.challenge.setRequiredIslandLevel(value);
}
this.build();
});
this.build();
});
return true;
};
}
else
{
icon = new ItemStack(Material.BARRIER);
clickHandler = null;
}
return true;
};
glow = false;
break;
@ -839,26 +849,18 @@ public class EditChallengeGUI extends CommonGUI
description.add(this.user.getTranslation("challenges.gui.descriptions.current-value",
"[value]", Long.toString(this.challenge.getRequiredIslandLevel())));
if (this.addon.isEconomyProvided())
{
icon = new ItemStack(Material.GOLD_INGOT);
clickHandler = (panel, user, clickType, slot) -> {
new NumberGUI(this.user, this.challenge.getRequiredMoney(), 0, lineLength, (status, value) -> {
if (status)
{
this.challenge.setRequiredMoney(value);
}
icon = new ItemStack(this.addon.isEconomyProvided() ? Material.GOLD_INGOT : Material.BARRIER);
clickHandler = (panel, user, clickType, slot) -> {
new NumberGUI(this.user, this.challenge.getRequiredMoney(), 0, lineLength, (status, value) -> {
if (status)
{
this.challenge.setRequiredMoney(value);
}
this.build();
});
return true;
};
}
else
{
icon = new ItemStack(Material.BARRIER);
clickHandler = null;
}
this.build();
});
return true;
};
glow = false;
break;
@ -874,21 +876,13 @@ public class EditChallengeGUI extends CommonGUI
this.user.getTranslation("challenges.gui.descriptions.enabled") :
this.user.getTranslation("challenges.gui.descriptions.disabled")));
if (this.addon.isEconomyProvided())
{
icon = new ItemStack(Material.LEVER);
clickHandler = (panel, user, clickType, slot) -> {
this.challenge.setTakeMoney(!this.challenge.isTakeMoney());
icon = new ItemStack(this.addon.isEconomyProvided() ? Material.LEVER : Material.BARRIER);
clickHandler = (panel, user, clickType, slot) -> {
this.challenge.setTakeMoney(!this.challenge.isTakeMoney());
this.build();
return true;
};
}
else
{
icon = new ItemStack(Material.BARRIER);
clickHandler = null;
}
this.build();
return true;
};
glow = this.challenge.isTakeMoney();
break;
@ -904,14 +898,14 @@ public class EditChallengeGUI extends CommonGUI
icon = new ItemStack(Material.WRITTEN_BOOK);
clickHandler = (panel, user, clickType, slot) -> {
new AnvilGUI(this.addon.getPlugin(),
this.user.getPlayer(),
this.challenge.getRewardText(),
(player, reply) -> {
this.challenge.setRewardText(reply);
this.build();
return reply;
});
new StringListGUI(this.user, this.challenge.getRewardText(), lineLength, (status, value) -> {
if (status)
{
this.challenge.setRewardText(value.stream().map(s -> s + "|").collect(Collectors.joining()));
}
this.build();
});
return true;
};
@ -991,27 +985,20 @@ public class EditChallengeGUI extends CommonGUI
description.add(this.user.getTranslation("challenges.gui.descriptions.current-value",
"[value]", Integer.toString(this.challenge.getRewardMoney())));
if (this.addon.isEconomyProvided())
{
icon = new ItemStack(Material.GOLD_INGOT);
clickHandler = (panel, user, clickType, slot) -> {
new NumberGUI(this.user, this.challenge.getRewardMoney(), 0, lineLength, (status, value) -> {
if (status)
{
this.challenge.setRewardMoney(value);
}
icon = new ItemStack(this.addon.isEconomyProvided() ? Material.GOLD_INGOT : Material.BARRIER);
clickHandler = (panel, user, clickType, slot) -> {
new NumberGUI(this.user, this.challenge.getRewardMoney(), 0, lineLength, (status, value) -> {
if (status)
{
this.challenge.setRewardMoney(value);
}
this.build();
});
this.build();
});
return true;
};
return true;
};
}
else
{
icon = new ItemStack(Material.BARRIER);
clickHandler = null;
}
glow = false;
break;
@ -1101,14 +1088,14 @@ public class EditChallengeGUI extends CommonGUI
icon = new ItemStack(Material.WRITTEN_BOOK);
clickHandler = (panel, user, clickType, slot) -> {
new AnvilGUI(this.addon.getPlugin(),
this.user.getPlayer(),
this.challenge.getRepeatRewardText(),
(player, reply) -> {
this.challenge.setRepeatRewardText(reply);
this.build();
return reply;
});
new StringListGUI(this.user, this.challenge.getRepeatRewardText(), lineLength, (status, value) -> {
if (status)
{
this.challenge.setRepeatRewardText(value.stream().map(s -> s + "|").collect(Collectors.joining()));
}
this.build();
});
return true;
};
@ -1189,31 +1176,23 @@ public class EditChallengeGUI extends CommonGUI
description.add(this.user.getTranslation("challenges.gui.descriptions.current-value",
"[value]", Integer.toString(this.challenge.getRepeatMoneyReward())));
if (this.addon.isEconomyProvided())
{
icon = new ItemStack(Material.GOLD_NUGGET);
clickHandler = (panel, user, clickType, slot) -> {
new NumberGUI(this.user,
this.challenge.getRepeatMoneyReward(),
0,
lineLength,
(status, value) -> {
if (status)
{
this.challenge.setRepeatMoneyReward(value);
}
icon = new ItemStack(this.addon.isEconomyProvided() ? Material.GOLD_NUGGET : Material.BARRIER);
clickHandler = (panel, user, clickType, slot) -> {
new NumberGUI(this.user,
this.challenge.getRepeatMoneyReward(),
0,
lineLength,
(status, value) -> {
if (status)
{
this.challenge.setRepeatMoneyReward(value);
}
this.build();
});
this.build();
});
return true;
};
}
else
{
icon = new ItemStack(Material.BARRIER);
clickHandler = null;
}
return true;
};
glow = false;
break;
@ -1250,7 +1229,13 @@ public class EditChallengeGUI extends CommonGUI
return null;
}
return new PanelItem(icon, name, GuiUtils.stringSplit(description, lineLength), glow, clickHandler, false);
return new PanelItemBuilder().
icon(icon).
name(name).
description(GuiUtils.stringSplit(description, lineLength)).
glow(glow).
clickHandler(clickHandler).
build();
}

View File

@ -1,6 +1,7 @@
package world.bentobox.challenges.panel.admin;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.enchantments.Enchantment;
@ -103,6 +104,10 @@ public class EditLevelGUI extends CommonGUI
panelBuilder.item(44, this.returnButton);
// Save challenge level every time this gui is build.
// It will ensure that changes are stored in database.
this.addon.getChallengesManager().saveLevel(this.challengeLevel);
panelBuilder.build();
}
@ -253,7 +258,13 @@ public class EditLevelGUI extends CommonGUI
return null;
}
return new PanelItem(icon, name, GuiUtils.stringSplit(description, this.addon.getChallengesSettings().getLoreLineLength()), glow, clickHandler, false);
return new PanelItemBuilder().
icon(icon).
name(name).
description(GuiUtils.stringSplit(description, this.addon.getChallengesSettings().getLoreLineLength())).
glow(glow).
clickHandler(clickHandler).
build();
}
@ -265,7 +276,7 @@ public class EditLevelGUI extends CommonGUI
private PanelItem createChallengeIcon(Challenge challenge)
{
return new PanelItemBuilder().
name(challenge.getFriendlyName()).
name(ChatColor.translateAlternateColorCodes('&', challenge.getFriendlyName())).
description(GuiUtils.stringSplit(
challenge.getDescription(),
this.addon.getChallengesSettings().getLoreLineLength())).
@ -416,14 +427,15 @@ public class EditLevelGUI extends CommonGUI
"[value]", "|" + this.challengeLevel.getUnlockMessage()));
icon = new ItemStack(Material.WRITABLE_BOOK);
clickHandler = (panel, user, clickType, slot) -> {
new AnvilGUI(this.addon.getPlugin(),
this.user.getPlayer(),
this.challengeLevel.getUnlockMessage(),
(player, reply) -> {
this.challengeLevel.setUnlockMessage(reply);
this.build();
return reply;
});
new StringListGUI(this.user, this.challengeLevel.getUnlockMessage(), lineLength, (status, value) -> {
if (status)
{
this.challengeLevel.setUnlockMessage(value.stream().map(s -> s + "|").collect(Collectors.joining()));
}
this.build();
});
return true;
};
glow = false;
@ -486,14 +498,15 @@ public class EditLevelGUI extends CommonGUI
"[value]", "|" + this.challengeLevel.getRewardText()));
icon = new ItemStack(Material.WRITTEN_BOOK);
clickHandler = (panel, user, clickType, slot) -> {
new AnvilGUI(this.addon.getPlugin(),
this.user.getPlayer(),
this.challengeLevel.getRewardText(),
(player, reply) -> {
this.challengeLevel.setRewardText(reply);
this.build();
return reply;
});
new StringListGUI(this.user, this.challengeLevel.getRewardText(), lineLength, (status, value) -> {
if (status)
{
this.challengeLevel.setRewardText(value.stream().map(s -> s + "|").collect(Collectors.joining()));
}
this.build();
});
return true;
};
glow = false;
@ -572,27 +585,19 @@ public class EditLevelGUI extends CommonGUI
description.add(this.user.getTranslation("challenges.gui.descriptions.current-value",
"[value]", Integer.toString(this.challengeLevel.getRewardMoney())));
if (this.addon.isEconomyProvided())
{
icon = new ItemStack(Material.GOLD_INGOT);
clickHandler = (panel, user, clickType, slot) -> {
new NumberGUI(this.user, this.challengeLevel.getRewardMoney(), 0, lineLength, (status, value) -> {
if (status)
{
this.challengeLevel.setRewardMoney(value);
}
icon = new ItemStack(this.addon.isEconomyProvided() ? Material.GOLD_INGOT : Material.BARRIER);
clickHandler = (panel, user, clickType, slot) -> {
new NumberGUI(this.user, this.challengeLevel.getRewardMoney(), 0, lineLength, (status, value) -> {
if (status)
{
this.challengeLevel.setRewardMoney(value);
}
this.build();
});
this.build();
});
return true;
};
}
else
{
icon = new ItemStack(Material.BARRIER);
clickHandler = null;
}
return true;
};
glow = false;
break;
@ -697,7 +702,15 @@ public class EditLevelGUI extends CommonGUI
return null;
}
return new PanelItem(icon, name, GuiUtils.stringSplit(description, lineLength), glow, clickHandler, false);
return new PanelItemBuilder().
icon(icon).
name(name).
description(GuiUtils.stringSplit(description, lineLength)).
glow(glow).
clickHandler(clickHandler).
build();
}

View File

@ -72,7 +72,13 @@ public class EditSettingsGUI extends CommonGUI
GuiUtils.fillBorder(panelBuilder);
panelBuilder.item(19, this.getSettingsButton(Button.RESET_CHALLENGES));
panelBuilder.item(10, this.getSettingsButton(Button.ENABLE_TITLE));
if (this.settings.isShowCompletionTitle())
{
panelBuilder.item(19, this.getSettingsButton(Button.TITLE_SHOWTIME));
}
panelBuilder.item(28, this.getSettingsButton(Button.BROADCAST));
panelBuilder.item(20, this.getSettingsButton(Button.GLOW_COMPLETED));
@ -100,7 +106,8 @@ public class EditSettingsGUI extends CommonGUI
panelBuilder.item(33, this.getSettingsButton(Button.PURGE_HISTORY));
}
panelBuilder.item(25, this.getSettingsButton(Button.STORE_MODE));
panelBuilder.item(25, this.getSettingsButton(Button.RESET_CHALLENGES));
panelBuilder.item(34, this.getSettingsButton(Button.STORE_MODE));
// Return Button
panelBuilder.item(44, this.returnButton);
@ -449,11 +456,65 @@ public class EditSettingsGUI extends CommonGUI
glow = false;
break;
}
case ENABLE_TITLE:
{
description = new ArrayList<>(2);
description.add(this.user.getTranslation("challenges.gui.descriptions.admin.title-enable"));
description.add(this.user.getTranslation("challenges.gui.descriptions.current-value",
"[value]",
this.settings.isShowCompletionTitle() ?
this.user.getTranslation("challenges.gui.descriptions.enabled") :
this.user.getTranslation("challenges.gui.descriptions.disabled")));
name = this.user.getTranslation("challenges.gui.buttons.admin.title-enable");
icon = new ItemStack(Material.SIGN);
clickHandler = (panel, user1, clickType, i) -> {
this.settings.setShowCompletionTitle(!this.settings.isShowCompletionTitle());
// Need to rebuild all as new buttons will show up.
this.build();
return true;
};
glow = this.settings.isShowCompletionTitle();
break;
}
case TITLE_SHOWTIME:
{
description = new ArrayList<>(2);
description.add(this.user.getTranslation("challenges.gui.descriptions.admin.title-showtime"));
description.add(this.user.getTranslation("challenges.gui.descriptions.current-value",
"[value]", Integer.toString(this.settings.getTitleShowtime())));
name = this.user.getTranslation("challenges.gui.buttons.admin.title-showtime");
icon = new ItemStack(Material.CLOCK);
clickHandler = (panel, user1, clickType, i) -> {
new NumberGUI(this.user,
this.settings.getTitleShowtime(),
0,
this.settings.getLoreLineLength(),
(status, value) -> {
if (status)
{
this.settings.setTitleShowtime(value);
}
panel.getInventory().setItem(i, this.getSettingsButton(button).getItem());
});
return true;
};
glow = false;
break;
}
default:
return new PanelItemBuilder().build();
}
return new PanelItem(icon, name, GuiUtils.stringSplit(description, this.settings.getLoreLineLength()), glow, clickHandler, false);
return new PanelItemBuilder().
icon(icon).
name(name).
description(GuiUtils.stringSplit(description, this.settings.getLoreLineLength())).
glow(glow).
clickHandler(clickHandler).
build();
}
@ -480,7 +541,9 @@ public class EditSettingsGUI extends CommonGUI
PURGE_HISTORY,
STORE_MODE,
GLOW_COMPLETED,
LOCKED_LEVEL_ICON
LOCKED_LEVEL_ICON,
ENABLE_TITLE,
TITLE_SHOWTIME
}

View File

@ -1,6 +1,7 @@
package world.bentobox.challenges.panel.admin;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.World;
import java.util.List;
@ -133,7 +134,7 @@ public class ListChallengesGUI extends CommonGUI
private PanelItem createChallengeIcon(Challenge challenge)
{
PanelItemBuilder itemBuilder = new PanelItemBuilder().
name(challenge.getFriendlyName()).
name(ChatColor.translateAlternateColorCodes('&', challenge.getFriendlyName())).
description(GuiUtils.stringSplit(this.generateChallengeDescription(challenge, this.user.getPlayer()),
this.addon.getChallengesSettings().getLoreLineLength())).
icon(challenge.getIcon()).

View File

@ -1,6 +1,7 @@
package world.bentobox.challenges.panel.admin;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.World;
import java.util.List;
@ -133,7 +134,7 @@ public class ListLevelsGUI extends CommonGUI
private PanelItem createLevelIcon(ChallengeLevel challengeLevel)
{
PanelItemBuilder itemBuilder = new PanelItemBuilder().
name(challengeLevel.getFriendlyName()).
name(ChatColor.translateAlternateColorCodes('&', challengeLevel.getFriendlyName())).
description(GuiUtils.stringSplit(
this.generateLevelDescription(challengeLevel, this.user.getPlayer()),
this.addon.getChallengesSettings().getLoreLineLength())).

View File

@ -1,11 +1,13 @@
package world.bentobox.challenges.panel.user;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import net.wesjd.anvilgui.AnvilGUI;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
@ -73,10 +75,10 @@ public class ChallengesGUI extends CommonGUI
public void build()
{
// Do not open gui if there is no challenges.
if (this.challengesManager.getAllChallenges(this.world).isEmpty())
if (!this.challengesManager.hasAnyChallengeData(this.world))
{
this.addon.getLogger().severe("There are no challenges set up!");
this.user.sendMessage("general.errors.general");
this.user.sendMessage("challenges.errors.no-challenges");
return;
}
@ -349,18 +351,53 @@ public class ChallengesGUI extends CommonGUI
{
return new PanelItemBuilder().
icon(challenge.getIcon()).
name(challenge.getFriendlyName().isEmpty() ? challenge.getUniqueId() : challenge.getFriendlyName()).
name(challenge.getFriendlyName().isEmpty() ?
challenge.getUniqueId() :
ChatColor.translateAlternateColorCodes('&', challenge.getFriendlyName())).
description(GuiUtils.stringSplit(this.generateChallengeDescription(challenge, this.user.getPlayer()),
this.addon.getChallengesSettings().getLoreLineLength())).
clickHandler((panel, user1, clickType, slot) -> {
if (TryToComplete.complete(this.addon,
this.user,
challenge,
this.world,
this.topLabel,
this.permissionPrefix))
// Add ability to input how many repeats player should do.
// Do not open if challenge is not repeatable.
if (clickType.isRightClick() && challenge.isRepeatable())
{
panel.getInventory().setItem(slot, this.getChallengeButton(challenge).getItem());
new AnvilGUI(this.addon.getPlugin(),
this.user.getPlayer(),
"1",
(player, reply) -> {
try
{
if (TryToComplete.complete(this.addon,
this.user,
challenge,
this.world,
this.topLabel,
this.permissionPrefix,
Integer.parseInt(reply)))
{
panel.getInventory().setItem(slot, this.getChallengeButton(challenge).getItem());
}
}
catch (Exception e)
{
this.user.sendMessage("challenges.errors.not-a-integer", "[value]", reply);
}
return reply;
});
}
else
{
if (TryToComplete.complete(this.addon,
this.user,
challenge,
this.world,
this.topLabel,
this.permissionPrefix))
{
panel.getInventory().setItem(slot, this.getChallengeButton(challenge).getItem());
}
}
return true;
@ -438,7 +475,13 @@ public class ChallengesGUI extends CommonGUI
glow = false;
}
return new PanelItem(icon, name, description, glow, clickHandler, false);
return new PanelItemBuilder().
icon(icon).
name(ChatColor.translateAlternateColorCodes('&', name)).
description(description).
glow(glow).
clickHandler(clickHandler).
build();
}

View File

@ -13,6 +13,7 @@ import java.util.function.BiConsumer;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.PanelListener;
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.utils.GuiUtils;
@ -125,7 +126,13 @@ public class ItemSwitchGUI
return null;
}
return new PanelItem(icon, name, GuiUtils.stringSplit(description, this.lineLength), false, clickHandler, false);
return new PanelItemBuilder().
icon(icon).
name(name).
description(GuiUtils.stringSplit(description, this.lineLength)).
glow(false).
clickHandler(clickHandler).
build();
}
@ -143,7 +150,13 @@ public class ItemSwitchGUI
{
CustomPanelItem(ItemStack item)
{
super(item.clone(), "", Collections.emptyList(), false, null, false);
super(new PanelItemBuilder().
icon(item.clone()).
name("").
description(Collections.emptyList()).
glow(false).
clickHandler(null));
this.getItem().setItemMeta(item.getItemMeta());
}

View File

@ -239,7 +239,13 @@ public class NumberGUI
return null;
}
return new PanelItem(icon, name, GuiUtils.stringSplit(description, this.lineLength), glow, clickHandler, false);
return new PanelItemBuilder().
icon(icon).
name(name).
description(GuiUtils.stringSplit(description, this.lineLength)).
glow(glow).
clickHandler(clickHandler).
build();
}

View File

@ -1,6 +1,7 @@
package world.bentobox.challenges.panel.util;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.event.inventory.ClickType;
import java.util.*;
@ -144,7 +145,7 @@ public class SelectChallengeGUI
return new PanelItemBuilder().
name(challenge.getFriendlyName()).
name(ChatColor.translateAlternateColorCodes('&', challenge.getFriendlyName())).
description(GuiUtils.stringSplit(description, this.lineLength)).
icon(challenge.getIcon()).
clickHandler((panel, user1, clickType, slot) -> {

View File

@ -2,13 +2,19 @@ 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;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.wesjd.anvilgui.AnvilGUI;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.panels.PanelItem;
@ -24,6 +30,12 @@ import world.bentobox.challenges.utils.GuiUtils;
*/
public class StringListGUI
{
public StringListGUI(User user, String value, int lineLength, BiConsumer<Boolean, List<String>> consumer)
{
this(user, Collections.singleton(value), lineLength, consumer);
}
public StringListGUI(User user, Collection<String> value, int lineLength, BiConsumer<Boolean, List<String>> consumer)
{
this(user, new ArrayList<>(value), lineLength, consumer);
@ -66,6 +78,8 @@ public class StringListGUI
panelBuilder.item(5, this.getButton(Button.REMOVE));
panelBuilder.item(6, this.getButton(Button.CLEAR));
panelBuilder.item(8, this.getButton(Button.MODE));
panelBuilder.item(44, this.getButton(Button.CANCEL));
int slot = 10;
@ -139,14 +153,25 @@ public class StringListGUI
description = Collections.emptyList();
icon = new ItemStack(Material.WHITE_STAINED_GLASS_PANE);
clickHandler = (panel, user, clickType, slot) -> {
new AnvilGUI(BentoBox.getInstance(),
this.user.getPlayer(),
" ",
(player, reply) -> {
this.value.add(reply);
this.build();
return reply;
});
if (this.useAnvil)
{
new AnvilGUI(BentoBox.getInstance(),
this.user.getPlayer(),
" ",
(player, reply) -> {
this.value.add(reply);
this.build();
return reply;
});
}
else
{
this.startConversion(value ->
this.value.add(value),
this.user.getTranslation("challenges.gui.descriptions.admin.add-text-line"));
}
return true;
};
break;
@ -176,11 +201,29 @@ public class StringListGUI
};
break;
}
case MODE:
{
name = this.user.getTranslation("challenges.gui.buttons.admin.input-mode");
description = Collections.singletonList(this.user.getTranslation("challenges.gui.descriptions.admin.input-mode"));
icon = this.useAnvil ? new ItemStack(Material.ANVIL) : new ItemStack(Material.MAP);
clickHandler = (panel, user, clickType, slot) -> {
this.useAnvil = !this.useAnvil;
panel.getInventory().setItem(slot, this.getButton(button).getItem());
return true;
};
break;
}
default:
return null;
}
return new PanelItem(icon, name, GuiUtils.stringSplit(description, this.lineLength), false, clickHandler, false);
return new PanelItemBuilder().
icon(icon).
name(name).
description(GuiUtils.stringSplit(description, this.lineLength)).
glow(false).
clickHandler(clickHandler).
build();
}
@ -195,19 +238,102 @@ public class StringListGUI
name(element).
icon(Material.PAPER).
clickHandler((panel, user1, clickType, i) -> {
new AnvilGUI(BentoBox.getInstance(),
this.user.getPlayer(),
element,
(player, reply) -> {
this.value.set(stringIndex, reply);
this.build();
return reply;
});
if (this.useAnvil)
{
new AnvilGUI(BentoBox.getInstance(),
this.user.getPlayer(),
element,
(player, reply) -> {
this.value.set(stringIndex, reply);
this.build();
return reply;
});
}
else
{
this.startConversion(
value -> this.value.set(stringIndex, value),
this.user.getTranslation("challenges.gui.descriptions.admin.edit-text-line"),
element);
}
return true;
}).build();
}
/**
* This method will close opened gui and writes inputText in chat. After players answers on inputText in
* chat, message will trigger consumer and gui will reopen.
* @param consumer Consumer that accepts player output text.
* @param question Message that will be displayed in chat when player triggers conversion.
*/
private void startConversion(Consumer<String> consumer, @NonNull String question)
{
this.startConversion(consumer, question, null);
}
/**
* This method will close opened gui and writes inputText in chat. After players answers on inputText in
* chat, message will trigger consumer and gui will reopen.
* @param consumer Consumer that accepts player output text.
* @param question Message that will be displayed in chat when player triggers conversion.
* @param message Message that will be set in player text field when clicked on question.
*/
private void startConversion(Consumer<String> consumer, @NonNull String question, @Nullable String message)
{
final User user = this.user;
Conversation conversation =
new ConversationFactory(BentoBox.getInstance()).withFirstPrompt(
new StringPrompt()
{
/**
* @see Prompt#getPromptText(ConversationContext)
*/
@Override
public String getPromptText(ConversationContext conversationContext)
{
// Close input GUI.
user.closeInventory();
if (message != null)
{
// Create Edit Text message.
TextComponent component = new TextComponent(user.getTranslation("challenges.gui.descriptions.admin.click-to-edit"));
component.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, message));
// Send question and message to player.
user.getPlayer().spigot().sendMessage(component);
}
// There are no editable message. Just return question.
return question;
}
/**
* @see Prompt#acceptInput(ConversationContext, String)
*/
@Override
public Prompt acceptInput(ConversationContext conversationContext, String answer)
{
// Add answer to consumer.
consumer.accept(answer);
// Reopen GUI
StringListGUI.this.build();
// End conversation
return Prompt.END_OF_CONVERSATION;
}
}).
withLocalEcho(false).
buildConversation(user.getPlayer());
conversation.begin();
}
// ---------------------------------------------------------------------
// Section: Enums
// ---------------------------------------------------------------------
@ -223,7 +349,8 @@ public class StringListGUI
REMOVE,
CANCEL,
CLEAR,
SAVE
SAVE,
MODE
}
@ -242,6 +369,11 @@ public class StringListGUI
*/
private User user;
/**
* Boolean that indicate if editing should happen in anvil.
*/
private boolean useAnvil;
/**
* Current value.
*/

View File

@ -13,6 +13,7 @@ import java.util.List;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
/**
@ -347,7 +348,12 @@ public class GuiUtils
{
private BorderBlock(ItemStack icon)
{
super(icon.clone(), " ", Collections.emptyList(), false, null, false);
super(new PanelItemBuilder().
icon(icon.clone()).
name(" ").
description(Collections.emptyList()).
glow(false).
clickHandler(null));
}

View File

@ -15,16 +15,16 @@
package world.bentobox.challenges.utils;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_13_R2.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.lang.reflect.Field;
import java.util.*;
import net.minecraft.server.v1_13_R2.NBTBase;
import net.minecraft.server.v1_13_R2.NBTTagCompound;
import net.minecraft.server.v1_13_R2.NBTTagList;
import world.bentobox.bentobox.BentoBox;
/**
@ -191,10 +191,11 @@ public enum HeadLib
public ItemStack toItemStack(int amount, String displayName, String... loreLines)
{
ItemStack item = new ItemStack(Material.PLAYER_HEAD, amount);
ItemMeta meta = item.getItemMeta();
if (displayName != null)
// Set Lora and DisplayName
if (meta != null && displayName != null)
{
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', displayName));
if (loreLines.length != 0)
@ -207,64 +208,26 @@ public enum HeadLib
item.setItemMeta(meta);
}
return this.setSkullOwner(item, this.getSkullOwner());
}
// ---------------------------------------------------------------------
// Section: Private inner methods
// ---------------------------------------------------------------------
/**
* This method returns SkullOwner or create new one if it is not created yet.
* SkullOwner is NBTTagCompound object that contains information about player_head skin.
* @return skullOwner object.
*/
private Object getSkullOwner()
{
if (this.skullOwner == null)
// Set correct Skull texture
if (meta != null && this.textureValue != null && !this.textureValue.isEmpty())
{
this.skullOwner = this.createOwnerCompound(this.uuid, this.textureValue);
GameProfile profile = new GameProfile(UUID.fromString(this.uuid), null);
profile.getProperties().put("textures", new Property("textures", this.textureValue));
try
{
Field profileField = meta.getClass().getDeclaredField("profile");
profileField.setAccessible(true);
profileField.set(meta, profile);
item.setItemMeta(meta);
}
catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e)
{
BentoBox.getInstance().log("Error while creating Skull Icon");
}
}
return this.skullOwner;
}
/**
* This method creates new NBTTagCompound object that contains UUID and texture link.
* @param id - UUID of user.
* @param textureValue - Encoded texture string.
* @return NBTTagCompound object that contains all necessary information about player_head skin.
*/
private NBTTagCompound createOwnerCompound(String id, String textureValue)
{
NBTTagCompound skullOwner = new NBTTagCompound();
skullOwner.setString("Id", id);
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound value = new NBTTagCompound();
value.setString("Value", textureValue);
textures.add(value);
properties.set("textures", textures);
skullOwner.set("Properties", properties);
return skullOwner;
}
/**
* This method adds SkullOwner tag to given item.
* @param item Item whom SkullOwner tag must be added.
* @param compound NBTTagCompound object that contains UUID and texture link.
* @return new copy of given item with SkullOwner tag.
*/
private ItemStack setSkullOwner(ItemStack item, Object compound)
{
net.minecraft.server.v1_13_R2.ItemStack nmsStack = CraftItemStack.asNMSCopy(item);
nmsStack.getOrCreateTag().set("SkullOwner", (NBTBase) compound);
return CraftItemStack.asBukkitCopy(nmsStack);
return item;
}

View File

@ -1,6 +1,6 @@
name: Challenges
main: world.bentobox.challenges.ChallengesAddon
version: ${version}
version: ${version}${build.number}
repository: 'BentoBoxWorld/Challenges'
metrics: true

View File

@ -1,787 +0,0 @@
##########################################################################################
# Example challenges.yml file. This is the same format as ASkyBlock.
# Use the cimport command to import the challenges to your world.
# For example: /bsbadmin challenges import
# to overwrite previous challenges, use /bsbadmin challenges import overwrite
# Once challenges are imported, you can edit them directly in the database folder.
# BSkyBlock offers more features in the native challenge definition files.
# Do not use ASkyBlock format for editing challenges, as it misses a lot of functions that
# is added in new Challenges Add-on. This feature is just for admins who want to use old
# challenges for new BentoBox plugin.
# This is just a converter, not editor.
#
##########################################################################################
# Rewards and required items have to be described using Bukkit Materials
# and be exactly correct
# Do not use Type Id numbers - they will not work!
# Challenges can be one of three types - inventory, island or level.
# inventory - means the player must have the items on them
# island - means the items have to be on the island and within 10 blocks of the player
# entities are also supported, e.g., COW.
# level - means the island level has to be equal or over this amount.
# If level is set as nothing '', then the challenge is a free challenge and can be
# done at any time.
# Challenges can be repeatable only if they are inventory challenges
# permissions can be given as a reward
#
# Reward Commands - commands can be run when a challenge is completed and repeated
# Commands are:
# rewardcommands:
# - command1
# - command2
# repeatrewardcommands:
# - command1
# - command2
# The commands are listed and run in order. Do not put a / in front of the command.
# The token [player] will be replaced with the player's name.
# Example:
# rewardcommands:
# - pex promote [player]
# - heal [player]
# - warp winner_circle [player]
# If a command fails, it will be noted in the console.
#
# The format for POTIONS is as follows:
#
# Format POTION:NAME:<LEVEL>:<EXTENDED>:<SPLASH/LINGER>:QTY
# LEVEL, EXTENDED, SPLASH, LINGER are optional.
# LEVEL is a number, 1 or 2
# LINGER is for V1.9 servers and later
# Examples:
# POTION:STRENGTH:1:EXTENDED:SPLASH:1
# POTION:INSTANT_DAMAGE:2::LINGER:2
# POTION:JUMP:2:NOTEXTENDED:NOSPLASH:1
# POTION:WEAKNESS::::1 - any weakness potion
#
# Valid potion names are:
# WATER, REGEN, SPEED, FIRE_RESISTANCE, POISON, INSTANT_HEAL, NIGHT_VISION, WEAKNESS,
# STRENGTH, SLOWNESS, JUMP, INSTANT_DAMAGE, WATER_BREATHING, INVISIBILITY
# For V1.9 these are also available:
# LUCK, MUNDANE, THICK, AWKWARD
#
#
# Reseting islands and challenges - usually challenges are reset when a player resets
# their island (see resetchallenges in config.yml). You can stop some challenges from
# being reset by using resetallowed:false in the challenge.
##########################################################################################
challenges:
# Challenge levels - list as many as you like. If a challenge's level is '' it can
# be done anytime. You cannot name a challenge the same as a level.
levels: 'Novice Competent Expert Advanced Elite'
# The number of undone tasks that can be left on a level before unlocking next level
waiveramount: 1
# Free levels - which levels above should be auto done when reached, therefore unlocking next level.
# Example:
# freelevels: 'Novice' will immediately put player onto Competent level challenges
# freelevels: 'Novice Competent' will make all Novice, Competent and Expert challenges available immediately.
# freelevels: 'Competent' will open Competent and Expert levels once Novice is complete
freelevels: ''
# This section determines what happens when a player unlocks a new level
# The subname should correspond to the levels listed above
# Note that there is no section for the first level as it is automatically unlocked
levelUnlock:
Competent:
# What additional message to send player
message: 'Congratulations - you unlocked the &9Competent level!'
rewardDesc: 'A diamond!'
itemReward: 'DIAMOND:1'
moneyReward: 100
expReward: 100
# List permissions separated by spaces
permissionReward: ''
# Commands to run on this player. Use [player] for their name.
commands:
#- kit tools [player]
#- some other command
Expert:
# What additional message to send player
message: 'Congratulations - you unlocked the &aExpert level!'
rewardDesc: '3 diamonds!'
itemReward: 'DIAMOND:3'
moneyReward: 100
expReward: 100
permissionReward: ''
# Commands to run on this player. Use [player] for their name.
commands:
#- kit tools [player]
#- some other command
Advanced:
# What additional message to send player
message: 'Congratulations - you unlocked the &bAdvanced level!'
rewardDesc: '5 diamonds!'
itemReward: 'DIAMOND:5'
moneyReward: 100
expReward: 100
permissionReward: ''
# Commands to run on this player. Use [player] for their name.
commands:
#- kit tools [player]
#- some other command
Elite:
# What additional message to send player
message: 'Congratulations - you unlocked the &dElite level!'
rewardDesc: '7 diamonds!'
itemReward: 'DIAMOND:7'
moneyReward: 100
expReward: 100
permissionReward: ''
# Commands to run on this player. Use [player] for their name.
commands:
#- kit tools [player]
#- some other command
# Challenge list
# Challenge names must be in lowercase. Do not use the same name as a level!
challengeList:
glassmaker:
friendlyname: 'Glass Maker'
description: 'Create 1 block of glass'
icon: GLASS
level: 'Novice'
type: inventory
requiredItems: 'GLASS:1'
# You can require the player has a certain amount of money for inventory challenges.
# Remember to mention it in the description!
# If takeItems is true, the money will be removed, so you may want to give it
# back in the reward.
#requiredMoney: 10
takeItems: true
itemReward: 'ICE:1'
rewardText: '1 block of ice'
#rewardcommands:
#- kit tools [player]
moneyReward: 10
expReward: 30
permissionReward: ''
repeatable: true
repeatItemReward: 'ICE:1'
repeatRewardText: '1 block of ice'
repeatMoneyReward: 5
repeatExpReward: 10
#repeatrewardcommands:
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 2
# Allow this challenge to reset when the player resets their island
# Default is true. Set to false to keep this challenge completed.
# Admins can always reset challenges even if this is set to false.
resetallowed: true
breadmaker:
friendlyname: 'Bread Maker'
description: 'Bake 21 loaves of bread'
icon: BREAD
level: 'Novice'
type: inventory
requiredItems: 'BREAD:21'
takeItems: true
itemReward: 'DIRT:5'
rewardText: '5 dirt'
moneyReward: 10
expReward: 30
permissionReward: ''
repeatable: true
repeatItemReward: 'DIRT:1'
repeatRewardText: '1 dirt'
repeatMoneyReward: 5
repeatExpReward: 10
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
dyemaker:
friendlyname: 'Dye Maker'
description: 'Craft 32 cactus green dyes'
icon: CACTUS_GREEN
level: 'Novice'
type: inventory
requiredItems: 'CACTUS_GREEN:32'
takeItems: true
itemReward: 'OAK_SAPLING:2 BIRCH_SAPLING:2 JUNGLE_SAPLING:2 SPRUCE_SAPLING:2'
rewardText: '2 oak, 2 birch, 2 jungle and 2 spruce saplings'
moneyReward: 10
expReward: 30
permissionReward: ''
repeatable: true
repeatItemReward: 'ACACIA_SAPLING:1 DARK_OAK_SAPLING:1 OAK_SAPLING:1 BIRCH_SAPLING:1 JUNGLE_SAPLING:1 SPRUCE_SAPLING:1'
repeatRewardText: '1 of each kind of sapling'
repeatMoneyReward: 5
repeatExpReward: 10
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
papermaker:
friendlyname: 'Paper Maker'
description: 'Create 21 pages of paper'
icon: PAPER
level: 'Novice'
type: inventory
requiredItems: 'PAPER:21'
takeItems: true
itemReward: 'DIRT:5 CLAY:15'
rewardText: '5 dirt and 15 clay blocks'
moneyReward: 15
expReward: 30
permissionReward: ''
repeatable: true
repeatItemReward: 'SAND:2'
repeatRewardText: '2 sand blocks'
repeatMoneyReward: 5
repeatExpReward: 10
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
cobblemaker:
friendlyname: 'Cobble Maker'
description: 'Create a cobblestone generator and mine 64 cobblestone.'
icon: COBBLESTONE
level: 'Novice'
type: inventory
requiredItems: 'COBBLESTONE:64'
takeItems: true
itemReward: 'LEATHER:4'
permissionReward: ''
rewardText: '4 leather - boots or a book perhaps?'
moneyReward: 10
expReward: 30
repeatable: true
repeatItemReward: 'LEATHER:1'
repeatRewardText: '1 leather'
repeatMoneyReward: 5
repeatExpReward: 10
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
seedbank:
friendlyname: 'Seedbank'
description: 'Collect 32 melon seeds, 32 pumpkin seeds, 32 beetroot seeds and 32 wheat seeds'
icon: PUMPKIN_SEEDS
level: 'Novice'
type: inventory
requiredItems: 'MELON_SEEDS:32 PUMPKIN_SEEDS:32 WHEAT_SEEDS:32 BEETROOT_SEEDS:32'
takeItems: true
itemReward: 'DIRT:5 VINE:20'
rewardText: '5 dirt blocks and 20 vines'
moneyReward: 15
expReward: 30
permissionReward: ''
repeatable: true
repeatItemReward: 'DIRT:2 VINE:20'
repeatRewardText: '2 dirt blocks and 5 vines'
repeatMoneyReward: 5
repeatExpReward: 10
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
stewmaker:
friendlyname: 'Stew Maker'
description: 'Cook up 18 bowls of mushroom stew'
icon: MUSHROOM_STEW
level: 'Novice'
type: inventory
requiredItems: 'MUSHROOM_STEW:18'
takeItems: true
itemReward: 'MYCELIUM:2'
rewardText: '2 mycelium blocks'
moneyReward: 15
expReward: 30
permissionReward: ''
repeatable: true
repeatItemReward: 'MYCELIUM:1'
repeatRewardText: '1 mycelium block'
repeatMoneyReward: 5
repeatExpReward: 10
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
builder:
friendlyname: 'Builder'
description: 'Reach island level 10 (/[label] level).'
icon: OAK_WOOD
level: 'Novice'
type: level
requiredItems: 10
takeItems: false
itemReward: 'IRON_PICKAXE:1 DIRT:5 SPONGE:1'
rewardText: '1 iron pickaxe, 5 dirt and a Sponge'
moneyReward: 50
expReward: 50
permissionReward: ''
repeatable: false
repeatItemReward: ''
repeatRewardText: ''
repeatMoneyReward: 0
repeatExpReward: 0
grinder:
description: 'Kill monsters and collect 64 rotten flesh, 32 skeleton bones, 32 string, 32 arrows, 16 gunpowder, 5 spider eyes'
icon: BONE
level: 'Competent'
type: inventory
requiredItems: 'ROTTEN_FLESH:64 STRING:32 GUNPOWDER:16 ARROW:32 BONE:32 SPIDER_EYE:5'
takeItems: true
itemReward: 'REDSTONE:16 IRON_ORE:5 FLINT:1 POTION:WATER_BREATHING:1 POTION:NIGHT_VISION:1'
rewardText: '16 redstone dust, 1 flint, 1 water breathing potion, 1 night vision potion and 5 iron(ore)'
moneyReward: 75
expReward: 75
permissionReward: ''
repeatable: true
repeatItemReward: 'REDSTONE:2 IRON_ORE:1 FLINT:1 POTION:WATER_BREATHING:1'
repeatRewardText: '2 redstone dust, 1 flint, 1 water breathing potion and 1 iron(ore)'
repeatMoneyReward: 15
repeatExpReward: 15
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
farmer:
description: 'Harvest 64 units of the following: wheat, sugar, melon, carrots, potatoes, pumpkin'
icon: WHEAT
level: 'Competent'
type: inventory
requiredItems: 'WHEAT:64 SUGAR:64 MELON:64 CARROT:64 POTATO:64 PUMPKIN:64'
takeItems: true
itemReward: 'REDSTONE:16 COCOA_BEANS:1 PIG_SPAWN_EGG:1 COW_SPAWN_EGG:1 CHICKEN_SPAWN_EGG:1'
rewardText: '16 redstone dust, 1 cocoa bean, 1 spawn egg (chicken,cow,pig)'
moneyReward: 75
expReward: 75
permissionReward: ''
repeatable: true
repeatItemReward: 'COCOA_BEANS:1 PIG_SPAWN_EGG:1 COW_SPAWN_EGG:1 CHICKEN_SPAWN_EGG:1'
repeatRewardText: '1 cocoa bean, 1 spawn egg (chicken,cow,pig)'
repeatMoneyReward: 20
repeatExpReward: 20
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
angler:
friendlyname: 'Angler'
description: 'Catch and cook 10 salmon fish'
icon: COOKED_SALMON
level: 'Competent'
type: inventory
requiredItems: 'COOKED_SALMON:10'
takeItems: true
itemReward: 'REDSTONE:16 IRON_ORE:5 INK_SAC:5'
rewardText: '16 redstone dust, 5 inksacs, 5 iron (ore)'
moneyReward: 75
expReward: 75
permissionReward: ''
repeatable: true
repeatItemReward: 'REDSTONE:2 IRON_ORE:1 INK_SAC:1'
repeatRewardText: '2 redstone dust, 1 inksac, 1 iron (ore)'
repeatMoneyReward: 15
repeatExpReward: 15
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
treecutter:
friendlyname: 'Treecutter'
description: 'Create a tree farm and collect 16 oak, birch, jungle, acacia, dark oak and spruce logs'
icon: OAK_LOG
level: 'Competent'
type: inventory
requiredItems: 'OAK_LOG:16 BIRCH_LOG:16 JUNGLE_LOG:16 SPRUCE_LOG:16 ACACIA_LOG:16 DARK_OAK_LOG:16'
takeItems: true
itemReward: 'REDSTONE:16 IRON_ORE:5 WOLF_SPAWN_EGG:1'
rewardText: '16 redstone dust, 5 iron (ore), 1 wolf spawn egg'
moneyReward: 75
expReward: 75
permissionReward: ''
repeatable: true
repeatItemReward: 'REDSTONE:2 IRON_ORE:1'
repeatRewardText: '2 redstone dust, 1 iron (ore)'
repeatMoneyReward: 15
repeatExpReward: 15
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
cookiemaker:
friendlyname: 'Cookie Maker'
description: 'Make 128 cookies and a bucket of milk'
icon: COOKIE
level: 'Competent'
type: inventory
requiredItems: 'MILK_BUCKET:1 COOKIE:128'
takeItems: true
itemReward: 'REDSTONE:16 IRON_ORE:5'
rewardText: '16 redstone dust, 5 iron (ore)'
moneyReward: 75
expReward: 75
permissionReward: ''
repeatable: true
repeatItemReward: 'REDSTONE:2 IRON_ORE:1'
repeatRewardText: '2 redstone dust, 1 iron (ore)'
repeatMoneyReward: 15
repeatExpReward: 15
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
craftsman:
friendlyname: 'Craftsman'
description: 'Reach island level 75 (/[label] level).'
icon: IRON_BLOCK
level: 'Competent'
type: level
requiredItems: 75
takeItems: false
itemReward: 'OBSIDIAN:10'
rewardText: '10 obsidian blocks'
moneyReward: 50
expReward: 50
permissionReward: ''
repeatable: false
repeatItemReward: ''
repeatRewardText: ''
repeatMoneyReward: 0
repeatExpReward: 0
homestead:
friendlyname: 'Homestead'
description: 'Build a house that contains at least 1 oak door, white bed, bookshelf, crafting table, furnace, glass-block window, and wall torch.'
icon: WHITE_BED
level: 'Competent'
type: island
requiredItems: 'WHITE_BED:1 CRAFTING_TABLE:1 GLASS:1 OAK_DOOR:1 FURNACE:1 BOOKSHELF:1 WALL_TORCH:1'
# Search radius - the number of blocks that will be searched around the player
# Minimum 10, which searches from -10 to +10 blocks around the player in x,y,z
# Max is 50 because big searches cause lag
searchRadius: 10
takeItems: false
itemReward: 'JUKEBOX:1 MUSIC_DISC_CHIRP:1 LAPIS_BLOCK:10'
rewardText: '1 jukebox, 1 music disk, 10 lapis lazuli blocks'
moneyReward: 100
expReward: 100
permissionReward: ''
repeatable: false
repeatItemReward: ''
repeatRewardText: ''
repeatMoneyReward: 0
repeatExpReward: 0
nether:
friendlyname: 'Nether'
description: 'Build a nether portal on your island and activate it.'
icon: NETHERRACK
level: 'Expert'
type: island
requiredItems: 'OBSIDIAN:10 NETHER_PORTAL:1'
takeItems: false
itemReward: 'DIAMOND_SWORD:1'
rewardText: '1 diamond sword'
moneyReward: 100
expReward: 100
permissionReward: ''
repeatable: false
repeatItemReward: ''
repeatRewardText: ''
repeatMoneyReward: 0
repeatExpReward: 0
enderpearls:
friendlyname: 'Enderpearls'
description: 'Collect 15 enderpearls from endermen'
icon: ENDER_PEARL
level: 'Expert'
type: inventory
requiredItems: 'ENDER_PEARL:15'
takeItems: true
itemReward: 'GOLD_INGOT:5 BLAZE_ROD:1'
rewardText: '5 gold ingots and 1 blaze rod'
moneyReward: 50
expReward: 100
permissionReward: ''
repeatable: true
repeatItemReward: 'GOLD_INGOT:1 BLAZE_ROD:1'
repeatRewardText: '1 gold ingot and 1 blaze rod'
repeatMoneyReward: 15
repeatExpReward: 15
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
slimeballfarmer:
friendlyname: 'Slimeball Farmer'
description: 'Collect 40 slimeballs from slimes'
icon: SLIME_BALL
level: 'Expert'
type: inventory
requiredItems: 'SLIME_BALL:40'
takeItems: true
itemReward: 'GOLD_INGOT:5 IRON_ORE:5'
rewardText: '5 gold ingots and 5 blocks of iron ore'
moneyReward: 50
expReward: 100
permissionReward: ''
repeatable: true
repeatItemReward: 'REDSTONE:8'
repeatRewardText: '8 redstone dust'
repeatMoneyReward: 15
repeatExpReward: 15
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
baker:
friendlyname: 'baker'
description: 'Bake 5 cakes and 5 pumpkin pies'
icon: CAKE
level: 'Expert'
type: inventory
requiredItems: 'CAKE:5 PUMPKIN_PIE:5'
takeItems: true
itemReward: 'GOLD_INGOT:5 DIAMOND:1'
rewardText: '5 gold ingots and 1 diamond'
moneyReward: 50
expReward: 100
permissionReward: ''
repeatable: true
repeatItemReward: 'IRON_ORE:1'
repeatRewardText: '1 iron (ore)'
repeatMoneyReward: 15
repeatExpReward: 15
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
pioneer:
friendlyname: 'Pioneer'
description: 'Make 1 map and use it, a compass, a clock and collect 64 netherrack, 16 soulsand, and 1 ghast tear'
icon: MAP
level: 'Expert'
type: inventory
requiredItems: 'NETHERRACK:64 SOUL_SAND:16 GHAST_TEAR:1 MAP:1 COMPASS:1 CLOCK:1'
takeItems: true
itemReward: 'POWERED_RAIL:32 RAIL:256 DIAMOND:1 OCELOT_SPAWN_EGG:1'
rewardText: '256 rails, 32 powered rails, 1 ocelot spawn egg, 1 diamond'
moneyReward: 100
expReward: 100
permissionReward: ''
repeatable: true
repeatItemReward: 'IRON_ORE:1'
repeatRewardText: '1 iron (ore)'
repeatMoneyReward: 20
repeatExpReward: 20
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
mason:
friendlyname: 'Mason'
description: 'Reach island level 150 (/[label] level).'
icon: GOLD_BLOCK
level: 'Expert'
type: level
requiredItems: 150
takeItems: false
itemReward: 'DIAMOND:1 DIRT:20 GOLD_BLOCK:2'
rewardText: '1 diamond, 20 dirt, and 2 gold blocks'
moneyReward: 150
expReward: 150
permissionReward: ''
repeatable: false
repeatItemReward: ''
repeatRewardText: ''
repeatMoneyReward: 0
repeatExpReward: 0
shepherd:
friendlyname: 'Shepherd'
description: 'Collect 5 of every color of wool'
icon: BLUE_WOOL
level: 'Advanced'
type: inventory
requiredItems: 'BLACK_WOOL:5 BLUE_WOOL:5 BROWN_WOOL:5 CYAN_WOOL:5 GRAY_WOOL:5 GREEN_WOOL:5 LIGHT_BLUE_WOOL:5 LIGHT_GRAY_WOOL:5 LIME_WOOL:5 MAGENTA_WOOL:5 ORANGE_WOOL:5 PINK_WOOL:5 PURPLE_WOOL:5 RED_WOOL:5 WHITE_WOOL:5 YELLOW_WOOL:5 '
takeItems: true
itemReward: 'DIAMOND:2 MUSIC_DISC_CAT:1 MUSIC_DISC_BLOCKS:1 MUSIC_DISC_STAL:1 SHEEP_SPAWN_EGG:1 EMERALD:5'
rewardText: '2 diamonds, 5 emeralds, 3 music disks, 1 sheep spawn egg'
moneyReward: 200
expReward: 200
permissionReward: ''
repeatable: true
repeatItemReward: 'EMERALD:1 SHEEP_SPAWN_EGG:1'
repeatRewardText: '1 emerald, 1 sheep spawn egg'
repeatMoneyReward: 20
repeatExpReward: 20
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
alchemist:
friendlyname: 'Alchemist'
description: 'Brew 1 potion of Fire Resistance, Slowness, Swiftness, Healing, Harming, Invisibility, Strength and Regeneration'
icon: BREWING_STAND
level: 'Advanced'
type: inventory
requiredItems: 'POTION:FIRE_RESISTANCE::::1 POTION:SLOWNESS::::1 POTION:SPEED::::1 POTION:INSTANT_HEAL::::1 POTION:INSTANT_DAMAGE::::1 POTION:INVISIBILITY::::1 POTION:STRENGTH::::1 POTION:REGEN::::1'
takeItems: true
itemReward: 'ENCHANTING_TABLE:1'
rewardText: 'Enchanting Table'
moneyReward: 200
expReward: 200
permissionReward: ''
repeatable: true
repeatItemReward: 'DIAMOND:1'
repeatRewardText: '1 diamond'
repeatMoneyReward: 20
repeatExpReward: 20
dj:
friendlyname: 'DJ'
description: 'Craft a jukebox and collect all music discs'
icon: MUSIC_DISC_CHIRP
level: 'Advanced'
type: inventory
requiredItems: 'MUSIC_DISC_11:1 MUSIC_DISC_13:1 MUSIC_DISC_BLOCKS:1 MUSIC_DISC_CAT:1 MUSIC_DISC_CHIRP:1 MUSIC_DISC_FAR:1 MUSIC_DISC_MALL:1 MUSIC_DISC_MELLOHI:1 MUSIC_DISC_STAL:1 MUSIC_DISC_STRAD:1 MUSIC_DISC_WAIT:1 MUSIC_DISC_WARD:1 JUKEBOX:1'
takeItems: true
itemReward: 'DIAMOND:3 EMERALD:10 GOLD_INGOT:5'
rewardText: '3 diamonds, 10 emeralds and 5 gold ingots'
moneyReward: 200
expReward: 200
permissionReward: ''
repeatable: true
repeatItemReward: 'DIAMOND:1 EMERALD:5 GOLD_INGOT:2'
repeatRewardText: '1 diamond, 5 emeralds and 2 gold bars'
repeatMoneyReward: 20
repeatExpReward: 20
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
gemcollector:
friendlyname: 'Gem Collector'
description: 'Collect 50 emeralds'
icon: EMERALD
level: 'Advanced'
type: inventory
requiredItems: 'EMERALD:50'
takeItems: true
itemReward: 'DIAMOND:10'
rewardText: '10 diamonds'
moneyReward: 200
expReward: 200
permissionReward: ''
repeatable: true
repeatItemReward: 'GOLD_INGOT:2'
repeatRewardText: '2 gold ingots'
repeatMoneyReward: 20
repeatExpReward: 20
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
culinaryartist:
friendlyname: 'Culinary Artist'
description: 'Collect 1 of every kind of cooked or crafted edible food (no raw food, zombie flesh, or super golden apples)'
icon: GOLDEN_APPLE
level: 'Advanced'
type: inventory
requiredItems: 'BAKED_POTATO:1 BREAD:1 CAKE:1 COOKED_CHICKEN:1 COOKED_COD:1 COOKED_SALMON:1 COOKED_PORKCHOP:1 COOKED_RABBIT:1 COOKIE:1 GOLDEN_APPLE:0:1 GOLDEN_CARROT:1 MUSHROOM_STEW:1 PUMPKIN_PIE:1 COOKED_BEEF:1'
takeItems: true
itemReward: 'GOLD_BLOCK:2 MUSIC_DISC_MALL:1 MUSIC_DISC_WAIT:1 MUSIC_DISC_13:1 MOOSHROOM_SPAWN_EGG:1 EMERALD:5'
rewardText: '2 gold blocks, 3 music discs, 1 mooshroom spawn egg, and 5 emeralds'
moneyReward: 200
expReward: 200
permissionReward: ''
repeatable: true
repeatItemReward: 'GOLD_INGOT:10 MOOSHROOM_SPAWN_EGG:1 EMERALD:1'
repeatRewardText: '10 gold ingots, 1 mooshroom spawn egg, 1 emerald'
repeatMoneyReward: 20
repeatExpReward: 20
# Max times limits how many times a challenge can be done. Comment out to make unlimited
maxtimes: 100
beaconator:
friendlyname: 'Beaconator'
description: 'Build a beacon and let it shine!'
icon: BEACON
level: 'Advanced'
type: island
requiredItems: 'BEACON:1'
takeItems: false
itemReward: 'STONE_BRICKS:20 CHISELED_STONE_BRICKS:20 CRACKED_STONE_BRICKS:20 MOSSY_STONE_BRICKS:20'
rewardText: '20 blocks of every kind of stone brick'
moneyReward: 300
expReward: 300
permissionReward: ''
repeatable: false
repeatItemReward: ''
repeatRewardText: ''
repeatMoneyReward: 0
repeatExpReward: 0
ittakesavillage:
friendlyname: 'It Takes A Village'
description: 'Hold a village meeting with 10 villagers!'
icon: STONE
level: 'Advanced'
type: island
requiredItems: 'VILLAGER:10'
takeItems: false
itemReward: 'HOPPER:4'
rewardText: '4 hoppers'
moneyReward: 300
expReward: 300
permissionReward: ''
repeatable: false
repeatItemReward: ''
repeatRewardText: ''
repeatMoneyReward: 0
repeatExpReward: 0
myprecious:
friendlyname: 'My Precious'
description: 'Build an iron golem'
icon: NAME_TAG
level: 'Advanced'
type: island
requiredItems: 'IRON_GOLEM:1'
takeItems: false
itemReward: 'NAME_TAG:1 ANVIL:1 CAULDRON:1 IRON_BLOCK:2'
rewardText: 'A name tag, an anvil, a cauldron and 2 iron blocks'
moneyReward: 300
expReward: 300
permissionReward: ''
repeatable: false
repeatItemReward: ''
repeatRewardText: ''
repeatMoneyReward: 0
repeatExpReward: 0
snowplay:
friendlyname: 'Snow Play!'
description: 'Build a snow golem'
icon: SNOWBALL
level: 'Advanced'
type: island
requiredItems: 'SNOWMAN:1'
takeItems: false
itemReward: 'DIAMOND_SHOVEL:1'
rewardText: 'A diamond spade - get shoveling!'
moneyReward: 300
expReward: 300
permissionReward: ''
repeatable: false
repeatItemReward: ''
repeatRewardText: ''
repeatMoneyReward: 0
repeatExpReward: 0
itsaparty:
friendlyname: "It's a party"
description: 'Have a party! Invite 4 friends.'
icon: PUMPKIN_PIE
level: 'Advanced'
type: island
requiredItems: 'PLAYER:5'
takeItems: false
itemReward: 'EMERALD:6 PUMPKIN_PIE:6'
rewardText: '6 Emeralds, 6 pumpkin pies'
moneyReward: 200
expReward: 200
permissionReward: ''
repeatable: false
repeatItemReward: ''
repeatRewardText: ''
repeatMoneyReward: 0
repeatExpReward: 0
itsamonsterparty:
friendlyname: "It's a Monster Party"
description: 'Have a party - all monsters invited! Get close to a Skeleton, Zombie, Spider, Creeper and Enderman all at the same time.'
icon: SKELETON_SKULL
level: 'Advanced'
type: island
requiredItems: 'SKELETON:1 ZOMBIE:1 SPIDER:1 CREEPER:1 ENDERMAN:1'
takeItems: false
itemReward: 'SKELETON_SKULL:1 ZOMBIE_HEAD:1 CREEPER_HEAD:1'
rewardText: 'Skulls!'
moneyReward: 200
expReward: 400
permissionReward: ''
repeatable: false
repeatItemReward: ''
repeatRewardText: ''
repeatMoneyReward: 0
repeatExpReward: 0
acidduke:
friendlyname: 'Arch Duke'
description: 'Achieve an island level of 1000'
icon: DIAMOND_BLOCK
level: 'Elite'
type: level
requiredItems: 1000
takeItems: false
itemReward: 'DIAMOND:1'
rewardText: '1 diamond'
moneyReward: 250
expReward: 250
permissionReward: ''
repeatable: false
repeatItemReward: ''
repeatRewardText: ''
repeatMoneyReward: 0
repeatExpReward: 0

View File

@ -100,6 +100,14 @@ reset-challenges: true
# Broadcast 1st time challenge completion messages to all players.
# Change to false if the spam becomes too much.
broadcast-messages: true
title:
#
# Shows a title screen for player after completion a challenge or level.
# Message can be edited via language settings.
show-title: true
#
# Integer that represents how long title will be visible for player.
title-showtime: 70
#
# This list stores GameModes in which Challenges addon should not work.
# To disable addon it is necessary to write its name in new line that starts with -. Example:
@ -109,4 +117,4 @@ disabled-gamemodes: []
#
uniqueId: config
#
configVersion: v2
configVersion: v3

File diff suppressed because it is too large Load Diff

View File

@ -12,30 +12,31 @@ challenges:
main:
parameters: ''
description: 'Main admin command. Opens GUI.'
complete:
description: 'Mark challenge complete'
parameters: '<player> <unique challenge name>'
create:
description: 'Opens GUI that allows to create challenge.'
parameters: '<unique challenge name>'
surrounding:
description: 'Create a surrounding challenge.'
parameters: '<challenge name>'
import:
description: 'Import challenges from challenges.yml'
parameters: '<overwrite>'
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'
parameters: ''
reset:
description: 'Reset challenge to 0 times / incomplete'
parameters: '<player> <unique challenge name>'
description: 'Reload challenges from the database|Parameter hard means that addon will reset connection to database.'
parameters: '[hard]'
show:
description: 'This method prints in chat all challenges that exist in world.'
parameters: ''
defaults:
description: 'This method shows subcommands that allows to import/export default challenges.'
parameters: '[command]'
defaults-import:
description: 'This method allows to import default challenges.'
parameters: ''
defaults-generate:
description: 'This method allows to export existing challenges into default.json file.'
parameters: '[overwrite] - allows to overwrite existing file.'
user:
description: 'This method opens Challenges GUI.'
parameters: ''
main:
description: 'This method opens Challenges GUI.'
parameters: ''
complete:
description: 'This method allows to complete challenge without GUI.'
parameters: '<challenge_id> [count]'
gui:
title:
admin:
@ -57,6 +58,7 @@ challenges:
toggle-environment: '&aToggle Environment'
edit-text-fields: '&aEdit Text Fields'
challenges: '&aChallenges'
game-modes: '&aChoose GameMode'
buttons:
admin:
complete: 'Complete user challenge'
@ -68,8 +70,6 @@ challenges:
delete-challenge: 'Remove challenge'
delete-level: 'Remove level'
import: 'Import ASkyblock Challenges'
backward: 'Import 0.3.0 Challenges'
backward-player: 'Fix 0.3.0 PlayerData'
settings: 'Edit Settings'
properties: 'Properties'
requirements: 'Requirements'
@ -85,7 +85,7 @@ challenges:
remove-on-complete: 'Remove after completion'
name: 'Friendly Name'
required-entities: 'Required Entities'
remove-entities: 'Remove Entities'
remove-entities: 'Kill Entities'
required-blocks: 'Required Blocks'
remove-blocks: 'Remove Blocks'
search-radius: 'Search Radius'
@ -143,6 +143,11 @@ challenges:
history-lifespan: 'History LifeSpan'
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'
next: 'Next'
previous: 'Previous'
return: 'Return'
@ -155,7 +160,7 @@ challenges:
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.'
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.'
@ -164,8 +169,6 @@ challenges:
edit-level: 'Allows to edit any Level settings.'
delete-challenge: 'Allows remove any Challenge.'
delete-level: 'Allows remove any Level.'
backward: 'Allows to import challenges from 0.3.0 and below addon version.'
backward-player: 'Allows to fix corrupted PlayerData from 0.3.0 version.|&2USE ONLY IF NECESSARY|&2MAY NOT WORK IN ALL SITUATIONS'
settings: 'Allows to change addon settings.'
properties: 'Allows to change general properties'
requirements: 'Allows to manage requirements'
@ -229,9 +232,17 @@ challenges:
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 string 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.'
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.'
click-to-edit: '&4Click here to edit input.'
edit-text-line: '&6 Edit text message!'
add-text-line: '&6 Add 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.'
current-value: '|&6Current value: [value].'
enabled: 'Active'
disabled: 'Disabled'
@ -281,16 +292,29 @@ challenges:
money-reward: '&6Money reward: $[value]'
reward-items: '&6Reward Items:'
reward-commands: '&6Reward Commands:'
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: 'Successfully completed'
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: 'Successfully completed'
level-subtitle: '[friendlyName]'
messages:
admin:
hit-things: 'Hit things to add them to the list of things required. Right click when done.'
you-added: 'You added one [thing] to the challenge'
challenge-created: '[challenge] created!'
you-completed-challenge: '&2You completed the [value] challenge!'
you-repeated-challenge: '&2You repeated the [value] challenge!'
you-completed-level: '&2You completed the [value] level!'
name-has-completed-challenge: '&5[name] has completed the [value] challenge!'
name-has-completed-level: '&5[name] has completed the [value] level!'
challenge-created: '[challenge]&r created!'
you-completed-challenge: '&2You completed the [value] &r&2challenge!'
you-repeated-challenge: '&2You repeated the [value] &r&2challenge!'
you-repeated-challenge-multiple: '&2You repeated the [value] &r&2challenge [count] times!'
you-completed-level: '&2You completed the [value] &r&2level!'
name-has-completed-challenge: '&5[name] has completed the [value] &r&5challenge!'
name-has-completed-level: '&5[name] has completed the [value] &r&5level!'
import-levels: 'Start importing Levels'
import-challenges: 'Start importing Challenges'
no-levels: 'Warning: No levels defined in challenges.yml'
@ -298,6 +322,8 @@ challenges:
load-skipping: '"[value]" already exists - skipping'
load-overwriting: 'Overwriting "[value]"'
load-add: 'Adding new object: [value]'
defaults-file-overwrite: 'defaults.json exists. It will be overwritten.'
defaults-file-completed: 'defaults.json file is populated with challenges from [world]!'
errors:
no-name: '&cMissing challenge name'
unknown-challenge: '&cUnknown challenge'
@ -322,6 +348,12 @@ challenges:
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!'
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!'
missing-level: '&cChallenge Level [level] is not defined in database. It may case some errors!'
protection:
flags:
CHALLENGES_ISLAND_PROTECTION:
@ -331,4 +363,4 @@ 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."
name: "Challenges Island limitation"
hint: "No challenges outside island"
version: 9
version: 11

View File

@ -0,0 +1,336 @@
###########################################################################################################
# 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 #
###########################################################################################################
### Credits ###
# Tastybento: maintainer
# SrAcosta: traductor
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:'
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."
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

View File

@ -0,0 +1,364 @@
###########################################################################################
# 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 ###
# BONNe: maintainer
challenges:
commands:
admin:
main:
parameters: ''
description: 'Administratora komanda, kura atver izvēlnes logu.'
import:
description: 'Šī metode importē Uzdevumus no challenges.yml faila.|Parametrs [overwrite] nozīmē, ka esošie uzdevumi vai līmeņi ar tādu pašu ID tiks pārrakstīti.'
parameters: '[overwrite]'
reload:
description: 'Šī metode pārlādē Challenges papildinājumu.|Parametrs [hard] nozīmē, ka tiks pārlādēts arī savienojums ar datubāzi.'
parameters: '[hard]'
show:
description: 'Šī komanda izvada visus uzdevumu nosaukumus sarakstē.'
parameters: ''
defaults:
description: 'Šī komanda izvada apakškomandas, kas pārvalda sākotnējos uzdevumus/līmeņus.'
parameters: '[komanda]'
defaults-import:
description: 'Šī metode ļauj uzstādīt sākotnējos uzdevumus un to līmeņus.'
parameters: ''
defaults-generate:
description: 'Šī metode izveidos failu defaults.json, kas saturēs šīs pasaules uzdevumus un līmeņus.|Parametrs overwrite ļauj pārrakstīt pāri esošajam failam.'
parameters: '[overwrite]'
user:
main:
description: 'Šī metode atver Uzdevumu logu.'
parameters: ''
complete:
description: 'Šī metode ļauj izpildīt uzdevumus neatverot Uzdevumu logu.|Beigās pierakstot skaitli, kas lielāks par 0 ļauj izpildīt uzdevumus vairākas reizes.'
parameters: '<uzdevuma id> [reižu skaits]'
gui:
title:
admin:
gui-title: '&aUzdevumu administrēšana'
edit-challenge-title: '&aLabot Uzdevumu'
edit-level-title: '&aLabot Līmeni'
settings-title: '&aLabot Iestatījumus'
choose-challenge-title: '&aIzvēlēties Uzdevumu'
choose-level-title: '&aIzvēlēties Līmeni'
choose-user-title: '&aIzvēlēties Spēlētāju'
manage-blocks: '&aPārvaldīt Blokus'
manage-entities: '&aPārvaldīt Radības'
confirm-title: '&aApstiprināt'
manage-items: '&aPārvaldīt Lietas'
manage-numbers: '&aSkaitļu Panelis'
select-block: '&aIzvēlēties Bloku'
select-challenge: '&aIzvēlēties Uzdevumu'
select-entity: '&aIzvēlēties Radību'
toggle-environment: '&aPārvaldīt Vidi'
edit-text-fields: '&aLabot Teksta Laukus'
challenges: '&aUzdevumi'
game-modes: '&aIzvēlēties Spēles Režīmu'
buttons:
admin:
complete: 'Pabeigt uzdevumu spēlētājam'
reset: 'Noņemt uzdevuma izpildi spēlētājam'
create-challenge: 'Izveidot jaunu uzdevumu'
create-level: 'Izveidot jaunu līmeni'
edit-challenge: 'Labot uzdevumu'
edit-level: 'Labot līmeni'
delete-challenge: 'Izmest uzdevumu'
delete-level: 'Izmest līmeni'
import: 'Importēt ASkyblock Uzdevumus'
settings: 'Pārvaldīt Iestatījumus'
properties: 'Rekvizīti'
requirements: 'Prasības'
rewards: 'Atlīdzības'
challenges: 'Uzdevumi'
type: 'Uzdevuma Tips'
deployment: 'Pieejams'
icon: 'Ikona'
locked-icon: 'Aizvērtā ikona'
description: 'Apraksts'
order: 'Secība'
environment: 'Vide'
remove-on-complete: 'Noņemt pēc izpildes'
name: 'Nosaukums'
required-entities: 'Nepieciešamās radības'
remove-entities: 'Nogalināt radības'
required-blocks: 'Nepieciešamie bloki'
remove-blocks: 'Iznīcināt blokus'
search-radius: 'Meklēšanas distnace'
required-permissions: 'Nepieciešamās atļaujas'
required-items: 'Nepieciešamie priekšmeti'
remove-items: 'Noņemt priekšmetus'
required-experience: 'Nepieciešamā pieredze'
remove-experience: 'Noņemt pieredzi'
required-level: 'Nepieciešamais salas līmenis'
required-money: 'Nepieciešamā nauda'
remove-money: 'Noņemt naudu'
reward-text: 'Atlīdzības ziņa'
reward-items: 'Atlīdzības priekšmeti'
reward-experience: 'Atlīdzības pieredze'
reward-money: 'Atlīdzības nauda'
reward-commands: 'Atlīdzības komandas'
repeatable: 'Atkārtojamība'
repeat-count: 'Maksimālais skaits'
repeat-reward-text: 'Atkārtotās atlīdzības ziņa'
repeat-reward-items: 'Atkārtotās atlīdzības priekšmeti'
repeat-reward-experience: 'Atkārtotās atlīdzības pieredze'
repeat-reward-money: 'Atkārtotās atlīdzības nauda'
repeat-reward-commands: 'Atkārtotās atlīdzības komandas'
waiver-amount: 'Neizpildāmo skaits'
add-challenge: 'Pievienot Uzdevumu'
remove-challenge: 'Noņemt Uzdevumu'
reset-on-new: 'Iztīrīt veidojot jaunu salu'
broadcast: 'Paziņot par izpildi'
remove-completed: 'Noņemt pēc izpildes'
glow: 'Mirdzēt pēc izpildes'
free-at-top: 'Brīvie uzdevumi augšā'
line-length: 'Apraksta līnijas garums'
toggle-user-list: 'Spēlētāju saraksts'
remove-selected: 'Noņemt iezīmētos'
add: 'Pievienot'
show-eggs: 'Pārslēgt attēlošanas režīmu'
accept: 'Apstiprināt'
decline: 'Noraidīt'
save: 'Saglabāt'
cancel: 'Pārtraukt'
input: 'Ievads'
value: 'Vērtība'
set: '='
increase: '+'
reduce: '-'
multiply: '*'
clear: 'Notīrīt'
remove-empty: 'Noņemt tukšos'
number: '[number]'
level-lore: 'Līmeņa Apraksts'
challenge-lore: 'Uzdevuma Apraksts'
gui-view-mode: 'Rādīt visus spēles režīmus'
gui-mode: 'Rādīt esošās pasaules uzdevumus'
history-store: 'Uzdevumu Vēsture'
history-lifespan: 'Vēstures Dzīvesilgums'
island-store: 'Kopīgi salas uzdevumi'
default-locked-icon: 'Slēgta līmeņa ikona'
input-mode: 'Pārslēgt ievades metodi'
title-enable: 'Izpildes virsraksts'
title-showtime: 'Virsrakta rādīšanas ilgums'
default-import: 'Importēt standarta Uzdevumus'
default-export: 'Exportēt esošos Uzdevumus'
next: 'Nākošā'
previous: 'Iepriekšējā'
return: 'Atgriezties'
descriptions:
admin:
save: 'Saglabāt un atgriezties iepriekšējā izvēlnē.'
cancel: 'Atgriezties iepriekšējā izvēlnē. &cDati netiks saglabāti.'
input: 'Atvērt teksta lauka ievadi.'
set: 'Uzstādīšanas operācija.'
increase: 'Saskaitīšanas operācija.'
reduce: 'Atņemšanas operācija.'
multiply: 'Reizināšanas operācija.'
import: 'Ļauj importēt ASkyblock Uzdevumus.|Ar labo peles klikšķi tas ļauj pārslēgt pārrakstīšanas modi.|Nepieciešams Challenges.yml fails ./BentoBox/addons/Challenges mapītē.'
complete: 'Ļauj pabeigt uzdevumus jebkuram spēlētājam.|Spēlētājs nedabūs izpildes atlīdzības.'
reset: 'Ļauj noņemt uzdevumu izpildi spēlētājam.|Ar labo peles klikšķi tas ļauj pārslēgdz iespēju nodzēst visus izpildes datus.'
create-challenge: 'Ļauj izveidot jaunu Uzdevumu.'
create-level: 'Ļauj izveidot jaunu Līmeni.'
edit-challenge: 'Ļauj labot Uzdevuma opcijas.'
edit-level: 'Ļauj labot Līmeņa opcijas.'
delete-challenge: 'Ļauj izdzēst Uzdevumu.'
delete-level: 'Ļauj izdzēst Līmeni.'
settings: 'Ļauj labot Papildinājuma iestatījumus.'
properties: 'Ļauj labot rekvizītus.'
requirements: 'Ļauj labot prasības'
rewards: 'Ļauj pārvaldīt atlīdzības'
challenges: 'Ļauj pārvaldīt Līmeņa uzdevumus (pievienot / noņemt).'
deployment: 'Ļauj nobloķēt uzdevuma izpildi.|Uzdevumu nevarēs izpildīt, ja opcija nav aktīva.'
icon-challenge: 'Uzdevuma ikona, kas parādīsies lietotāja izvēlnē.'
icon-level: 'Līmeņa ikona, kas parādīsies lietotāja izvēlnē.'
locked-icon: 'Neatklāta (neatvērta) Līmeņa ikona, kas parādīsies lietotāja izvēlnē.'
description: 'Ļauj labot aprakstu.'
order: 'Ļauj labot secību.'
environment: 'Ļauj izvēlēties, kurās vidēs Uzdevumu var pildīt.'
type: 'Ļauj uzstādīt Uzdevuma tipu. Katram tipam ir savādākas prasības.'
remove-on-complete: 'Šīs opcijas ieslēgšana nozīmē, ka Uzdevumu nerādīs lietotāja logos, ja tas ir izpildīts.'
name-challenge: 'Ļauj labot Uzdevuma nosaukumu.'
name-level: 'Ļauj labot Līmeņa nosaukumu.'
required-entities: 'Ļauj pārvaldīt nepieciešamās radības.|Radības:|'
remove-entities: 'Ļauj noņemt (nogalināt) radības pēc Uzdevuma izpildes.'
required-blocks: 'Ļauj pārvaldīt nepieciešamos blokus.|Bloki:|'
remove-blocks: 'Ļauj noņemt (aizstāt ar gaisu) blokus pēc Uzdevuma izpildes.'
search-radius: 'Distance no spēlētāja, kādā prasītie bloki un radības tiks meklētas.'
required-permissions: 'Nepieciešamās atļaujas, lai izpildītu Uzdevumu.|Atļaujas:'
required-items: 'Nepieciešamās lietas spēlētāja inventārā.|Lietas:'
remove-items: 'Ļauj izņemt lietas no spēlētāja inventāra pēc Uzdevuma izpildes.'
required-experience: 'Ļauj nodefinēt nepieciešamo spēlētāja pieredzes daudzumu, lai izpildītu uzdevumu.'
remove-experience: 'Ļauj noņemt pieprasīto pieredzes daudzumu pēc Uzdevuma izpildes.'
required-level: 'Ļauj definēt nepieciešamo salas līmeni Uzdevuma izpildei.|&cNepieciešams Levels papildinājums.'
required-money: 'Ļauj definēt nepieciešamo naudas daudzumu spēlētāja kontā.|&cNepieciešams Vault un ekonomikas papildinājumi.'
remove-money: 'Ļauj noņemt naudu no spēlētāja konta pēc Uzdevuma izpildes.|&cNepieciešams Vault un ekonomikas papildinājumi.'
reward-text: 'Ļauj mainīt ziņu, kas parādīsies spēlētājam pēc Uzdevuma izpildes.'
reward-items: 'Ļauj pārvaldīt lietas, kuras iegūs spēlētājs pēc Uzdevuma izpildes.|Lietas:'
reward-experience: 'Ļauj mainīt pieredzi, ko iegūs spēlētājs pēc Uzdevuma izpildes.'
reward-money: 'Ļauj mainīt naudas daudzumu, ko iegūs spēlētājs pēc Uzdevuma izpildes.|&cNepieciešams Vault un ekonomikas papildinājumi.'
reward-commands: 'Ļauj definēt komandas, kuras tiks izpildītas pēc Uzdevuma izpildes.|&c***Pievienojot "[SELF]" sākumā nozīmē, ka komandu izpildīs spēlētājs, piemēram. "/kill"|&c***Teksts "[player]" tiks pārtaisīts par izpildītāja lietotājvārdu, piemēram "/kill [player]" tiks pārveidots par "/kill BONNe1704"|Komandas:'
repeatable: 'Ļauj definēt vai uzdevumu var pildīt atkārtoti.'
repeat-count: 'Ļauj definēt cik reizes uzdevumu var pildīt atkārtoti. Cipars 0 nozīmē, ka uzdevumu var pildīt neierobežotu daudzumu reižu.'
repeat-reward-text: 'Ļauj definēt ziņu, kuru rādīs spēlētājam pēc atkārtotas Uzdevuma izpldes.'
repeat-reward-items: 'Ļauj pārvaldīt atkārtotas izpildes atlīdzības lietas.|Lietas:'
repeat-reward-experience: 'Ļauj mainīt atkārtotas izpildes atlīdzības pieredzes daudzmumu.'
repeat-reward-money: 'Ļauj definēt atkārtotas izpildes naudas atlīdzības lielumu.|&cNepieciešams Vault un ekonomikas papildinājumi.'
repeat-reward-commands: 'Ļauj definēt komandas, kuras tiks izpildītas pēc Uzdevuma atkārtotas izpildes.|&c***Pievienojot "[SELF]" sākumā nozīmē, ka komandu izpildīs spēlētājs, piemēram. "/kill"|&c***Teksts "[player]" tiks pārtaisīts par izpildītāja lietotājvārdu, piemēram "/kill [player]" tiks pārveidots par "/kill BONNe1704"|Komandas:'
waiver-amount: 'Ļauj definēt cik daudz uzdevumi var tikt atstāti neizpildīti, lai atvērtu nākošo līmeni.'
reward-text-level: 'Ļauj definēt ziņu, kas tiks nosūtīta spēlētājiem pēc Līmeņa izpildes.'
add-challenge: 'Ļauj pievienot jebkuru Uzdevumu šim Līmenim.'
remove-challenge: 'Ļauj noņemt Uzdevumu no šī Līmeņa.'
reset-on-new: 'Ļauj pārslēgt opciju, kas notīra spēlētāja izpildītos Uzdevumus un Līmeņus, ja tas atsāk no sākuma, pamet vai tiek izmests no salas.'
broadcast: 'Ļauj ieslēgt/izslēgt paziņojumu visiem tiešsaitē esošajiem spēlētājiem, ka spēlētājs izpildījis Uzdevumu vai Līmeni pirmo reizi.'
remove-completed: 'Ļauj ieslēgt/izslēgt opciju, kas paslēps visus izpildītos uzdevumus, kurus vairs nevar atkārtot.'
glow: 'Ļauj ieslēgt/izslēgt opciju, kas liks mirdzēt izpildītajiem Uzdevumiem/Līmeņiem.'
free-at-top: 'Ļauj definēt kurā rindā būs brīvie uzdevumi (bez līmeņa). Pirmā vai pēdējā rinda.'
line-length: 'Ļauj definēt cik simbolus gara rindiņa būs redzama lietu aprakstos.'
toggle-user-list: 'Ļauj pārslēgt spēlētāju saraksta režīmu.'
mode-online: 'Spēlētāji, kas ir tiešsaitē.'
mode-in-world: 'Spēlētāji, kas ir spēles režīma pasaulē.'
mode-with-island: 'Spēlētāji, kam ir sala šajā režīmā.'
selected: 'Iezīmēts'
remove-selected: 'Dzēst iezīmētos elementus.|Iezīmēt elementus var ar labo peles klikšķi.'
show-eggs: 'Ļauj pārslēgt radību attainošanas režīmu no olām uz galvu ikonām.'
level-lore: 'Ļauj definēt kādus elementus rādīs Līmeņu aprakstos.'
challenge-lore: 'Ļauj definēt kādus elementus rādīs Uzdevumu aprakstos.'
gui-view-mode: 'Ļauj definēt vai /challenges logs rādīs visus spēles režīmus vai uzdevumus no spēlētāja pasaules.'
history-store: 'Ļauj ieslēgt/izslēgt uzdevumu izpildes vēstures saglabāšanu.'
history-lifespan: 'Ļauj mainīt cik pēdējās dienas dati tiks glabāti.|0 nozīmē, ka dati netiks dzēsti.'
island-store: 'Ļauj mainīt datu saglabāšanas režīmu. Dati var tikt glabāti katrai salai, vai katram spēlētājam.|&cMAINOT REŽĪMUS DATI NETIKS PĀRVEIDOTI.'
default-locked-icon: 'Ļauj mainīt neatklāto līmeņu ikonu.|Katrs līmenis šo opciju var pārrakstīt.'
gui-mode: 'Ļauj ieslēgt/izslēgt vienas komandas opciju. Komandu var mainīt konfigurācijas failā.|&2Nepieciešama servera restartēšana.'
click-to-edit: '&4Uzspied šeit, lai labotu.'
edit-text-line: '&6 Labo teksta ziņu'
add-text-line: '&6 Pievieno jaunu teksta ziņu!'
input-mode: 'Pārslēgties starp sarakstes un lakts ievades veidu.'
title-enable: 'Ļauj ieslēgt/izlēgt virsraksta parādīšanos pēc pirmās Uzdevuma/Līmeņa izpildes.'
title-showtime: 'Ļauj mainīt cik ilgi virsraksts spēlētājam būs redzams.'
default-import: 'Ļauj ielādēt sākotnējos uzdevumus.'
default-export: 'Ļauj eksportēt uzdevumus uz defaults.json failu.'
current-value: '|&6Šī brīža vērtība: [value].'
enabled: 'Aktīvs'
disabled: 'Neaktīvs'
type:
island: '- Teritorijas tips:| (ļauj definēt nepieciešamos blokus vai monstrus ap spēlētāju)'
inventory: '- Inventora tips:| (ļauj definēt nepieciešamās lietas spēlētāja inventorā)'
other: '- Citi tips:| (ļauj definēt cita veida uzdevumus)'
the-end: '- Beigas'
nether: '- Elle'
normal: '- Virszeme'
entity: '- [entity] : [count]'
block: '- [block] : [count]'
permission: '- [permission]'
item: '- [count] x [item]'
item-meta: ' ([meta])'
item-enchant: ' - [enchant] [level]'
command: '- [command]'
level-unlocked: 'Uzspied, lai redzētu [level] uzdevumus!'
level-locked: 'Jāpabeidz vēl [count] uzdevumus no [level] līmeņa, lai atklātu šo līmeni!'
challenge-description:
level: '&FLīmenis: [level]'
completed: '&BIzpildīts'
completed-times-of: 'Izpildīts [donetimes] no [maxtimes] reizēm'
maxed-reached: 'Izpildīts [donetimes] no [maxtimes] reizēm'
completed-times: 'Izpildīts [donetimes] reizes'
warning-items-take: '&cVisas pieprasītas lietas tiks izņemtas no tava inventāra!'
objects-close-by: '&cVisiem nepieciešamajiem blokie, un radībām nepieciešams būt tuvu tev un uz tavas salas!'
warning-entities-kill: '&cVisas pieprasītās radības tiks noņemtas (nogalinātas) pēc Uzdevuma izpildes!'
warning-blocks-remove: '&cVisi nepieciešamie bloki tiks noņemti (aizstāti ar gaisu) pēc Uzdevuma izpildes!'
not-repeatable: '&cŠis Uzdevums nav atkārtojams!'
experience-reward: '&6Pieredzes atlīdzība: [value]'
money-reward: '&6Naudas atlīdzība: $[value]'
required-experience: '&6Nepieciešamā pieredze: [value]'
required-money: '&6Nepieciešamā nauda: $[value]'
required-island-level: '&6Nepieciešamais salas līmenis: [value]'
environment: 'Nepieciešamā pasaule:'
reward-items: '&6Atlīdzības lietas:'
reward-commands: '&6Atlīdzības komandas:'
required-items: 'Nepieciešamās lietas:'
required-entities: 'Nepieciešamās radības:'
required-blocks: 'Nepieciešamās bloki:'
level-description:
completed: '&BIzpildīts'
completed-challenges-of: '&3Tu esi izpildījis [number] no [max] uzdevumiem šajā līmenī.'
waver-amount: '&6Tu vari izlaist [value] uzdevumus, lai atvērtu nākošo līmeni.'
experience-reward: '&6Pieredzes atlīdzība: [value]'
money-reward: '&6Naudas atlīdzība: $[value]'
reward-items: '&6Atlīdzības lietas:'
reward-commands: '&6Atlīdzības komandas:'
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: 'Veiksmīgi izpildīts uzdevums'
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: 'Veiksmīgi pabeigts līmenis'
level-subtitle: '[friendlyName]'
messages:
admin:
challenge-created: '[challenge]&r izveidots!'
you-completed-challenge: '&2Tu izpildīji [value] &r&2uzdevumu!'
you-repeated-challenge: '&2Tu atkārtoji [value] &r&2uzdevumu!'
you-repeated-challenge-multiple: '&2Tu atkārtoji [value] &r&2uzdevumu [count] reizes!'
you-completed-level: '&2Tu izpildīji [value] &r&2līmeni!'
name-has-completed-challenge: '&5[name] izpildīja [value] &r&5uzdevumu!'
name-has-completed-level: '&5[name] izpildīja visus uzdevumus no [value] &r&5līmeņa!'
import-levels: 'Sāk importēt līmeņus'
import-challenges: 'Sāk importēt uzdevumus'
no-levels: '&cUzmanību, nav definēti līmeņi iekš challenges.yml faila'
import-number: 'Importēti [number] uzdevumi'
load-skipping: '"[value]" jau ekistē - izlaiž'
load-overwriting: 'Pārraksta "[value]"'
load-add: 'Pievieno jaunu: [value]'
defaults-file-overwrite: 'defaults.json jau existē. Tas tiek pārrakstīts.'
defaults-file-completed: 'defaults.json failā ir sarakstīti uzdevumi un līmeņi no [world]!'
errors:
no-name: '&cTrūkst Uzdevuma nosaukums'
unknown-challenge: '&cNezināms uzdevums'
unique-id: '&cUnikālais ID "[id]" nav derīgs.'
wrong-icon: '&cDotais materiāls "[value]" neeksistē vai arī nevar tikt izmantots kā ikona.'
not-valid-integer: '&cDotais cipars "[value]" nav derīgs!|Skaitlim jābūt no [min] līdz [max].'
not-a-integer: '&c"[value]" nav skaitlis!'
not-deployed: '&cUzdevums nav ieslēgts! Tā izpilde ir bloķēta.'
not-on-island: '&cTev nepieciešams būt uz savas salas, lai izpildītu uzdevumu!'
challenge-level-not-available: '&cŠī uzdevuma līmenis nav atklāts. Tu nevari to pildīt.'
not-repeatable: '&cŠis uzdevums nav atkārtojams!'
wrong-environment: '&cTu neesi pareizajā pasaulē!'
not-enough-items: '&cTev nav pietiekoši daudz [items], lai pabeigtu šo uzdevumu!'
not-close-enough: '&c[number] bloku rādiusā ap tevi nav nepieciešamais bloku daudzums.'
you-still-need: '&cTev vēl nepieciešams [amount] x [item]'
missing-addon: '&cNevar izpildīt uzdevumu. Serverī nav uzstādīti nepieciešamie papildinājumi.'
incorrect: '&cNevar izpildīt uzdevumu. Prasības nav korektas.'
not-enough-money: '&cNepietiek naudas. Tavā kontā vajag būt [value] vienībām, lai izpildītu Uzdevumu.'
not-enough-experience: '&cNepietiek pieredzes. Tev jābūt [value] pieredzei, lai izpildītu Uzdevumu.'
island-level: '&cSalas līmenim ir nepieciešams būt lielākam par [number]!'
import-no-file: '&cNevarēja atrast challenges.yml failu, no kura importēt!'
no-load: '&cKļūda: Nevarēja ielādēt challenges.yml. [message]'
load-error: '&cKļūda: Nevarēja ielādēt [value].'
no-rank: "&cTev nav nepieciešamais rangs, lai šo darītu."
cannot-remove-items: '&cDažas lietas nevarēja izņemt no inventāra!'
exist-challenges-or-levels: '&cŠajā pasaulē jau eksistē Uzdevumi. Nevar turpināt!'
defaults-file-exist: '&cdefaults.json jau eksistē. Lieto overwrite, lai to pārrakstītu!'
defaults-file-error: '&cRadās kļūda veidojot defaults.json failu! Pārbaudi konsoli!'
no-challenges: '&cŠajā pasaulē nav izveidoti uzdevumi!'
missing-level: '&cLīmenis [level] nav definēts datubāzē. Tas var radīt problēmas!'
protection:
flags:
CHALLENGES_ISLAND_PROTECTION:
description: "&5&oPārslēdz kurš var|&5&opildīt uzdevumus"
name: "Uzdevumu izpildes aizsardzība"
CHALLENGES_WORLD_PROTECTION:
description: "&5&oĻauj pārslēgt vai|&5&ospēlētājam ir nepieciešams\n&5&obūt uz salais,\n&5&olai pildītu uzdevumus."
name: "Uzdevumu salas ierobežosāna"
hint: "Uzdevumus nevar pildīt ārpus salas"
version: 11

View File

@ -1,23 +1,27 @@
/**
*
*/
package world.bentobox.challenges.tasks;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
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.challenges.ChallengesAddon;
@ -25,140 +29,202 @@ import world.bentobox.bentobox.api.user.User;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Bukkit.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.GOLD_BLOCK, 32)
};
List<ItemStack> required;
private ChallengesAddon addon;
private PlayerInventory inv;
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 {
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<>();
}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
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<>();
/**
* Test method for {@link TryToComplete#removeItems(java.util.List)}.
*/
@Test
public void testRemoveItemsSuccess() {
Material reqMat = Material.PAPER;
int reqQty = 21;
required.add(new ItemStack(reqMat, reqQty));
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<Material, Integer> removed = x.removeItems(required);
assertTrue(removed.get(reqMat) == reqQty);
}
Server server = mock(Server.class);
ItemFactory itemFactory = mock(ItemFactory.class);
when(server.getItemFactory()).thenReturn(itemFactory);
/**
* Test method for {@link TryToComplete#removeItems(java.util.List)}.
*/
@Test
public void testRemoveItemsMax() {
Material reqMat = Material.PAPER;
int reqQty = 50;
required.add(new ItemStack(reqMat, reqQty));
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<Material, Integer> removed = x.removeItems(required);
assertTrue(removed.get(reqMat) == 32);
}
// Test will not work with items that has meta data.
when(itemFactory.getItemMeta(any())).thenReturn(null);
when(itemFactory.equals(null, null)).thenReturn(true);
/**
* Test method for {@link TryToComplete#removeItems(java.util.List)}.
*/
@Test
public void testRemoveItemsZero() {
Material reqMat = Material.PAPER;
int reqQty = 0;
required.add(new ItemStack(reqMat, reqQty));
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<Material, Integer> removed = x.removeItems(required);
assertTrue(removed.get(reqMat) == null);
}
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getServer()).thenReturn(server);
/**
* Test method for {@link TryToComplete#removeItems(java.util.List)}.
*/
@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<Material, Integer> removed = x.removeItems(required);
assertTrue(removed.get(Material.PAPER) == 21);
}
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List)}.
*/
@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<Material, Integer> removed = x.removeItems(required);
assertTrue(removed.get(Material.PAPER) == 21);
assertTrue(removed.get(Material.CACTUS) == 10);
}
/**
* Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
*/
@Test
public void testRemoveItemsSuccess() {
Material requiredMaterial = Material.PAPER;
int requiredQuantity = 21;
/**
* Test method for {@link TryToComplete#removeItems(java.util.List)}.
*/
@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<Material, Integer> removed = x.removeItems(required);
assertTrue(removed.isEmpty());
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)}.
*/
@Test
public void testRemoveItemsFail() {
required.add(new ItemStack(Material.GOLD_BLOCK, 55));
TryToComplete x = new TryToComplete(addon);
x.user(user);
Map<Material, Integer> removed = x.removeItems(required);
// It will remove 32, but not any more
assertTrue(removed.get(Material.GOLD_BLOCK) == 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)}.
*/
@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)}.
*/
@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)}.
*/
@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)}.
*/
@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)}.
*/
@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)}.
*/
@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)}.
*/
@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)}.
*/
@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);
}
}