diff --git a/pom.xml b/pom.xml
index 97b2f18..5df5469 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
world.bentobox
challenges
- 0.3.1-SNAPSHOT
+ 0.5.0-SNAPSHOT
Challenges
Challenges is an add-on for BentoBox, an expandable Minecraft Bukkit plugin for island-type games like ASkyBlock or AcidIsland.
@@ -60,6 +60,10 @@
vault-repo
http://nexus.hc.to/content/repositories/pub_releases
+
+ wesjd-repo
+ https://nexus.wesjd.net/repository/thirdparty/
+
@@ -69,6 +73,12 @@
1.13.2-R0.1-SNAPSHOT
provided
+
+ org.spigotmc
+ spigot
+ 1.13.2-R0.1-SNAPSHOT
+ provided
+
org.mockito
mockito-all
@@ -90,7 +100,7 @@
world.bentobox
bentobox
- 1.1-SNAPSHOT
+ 1.1
provided
@@ -111,6 +121,11 @@
+
+ net.wesjd
+ anvilgui
+ 1.2.1-SNAPSHOT
+
@@ -195,8 +210,16 @@
maven-shade-plugin
3.1.1
- false
+ true
+
+
+ package
+
+ shade
+
+
+
org.apache.maven.plugins
diff --git a/src/main/java/world/bentobox/challenges/ChallengesAddon.java b/src/main/java/world/bentobox/challenges/ChallengesAddon.java
index 4d3f27d..6f4cc94 100644
--- a/src/main/java/world/bentobox/challenges/ChallengesAddon.java
+++ b/src/main/java/world/bentobox/challenges/ChallengesAddon.java
@@ -1,13 +1,18 @@
package world.bentobox.challenges;
-import org.bukkit.Bukkit;
+import org.bukkit.Bukkit;
+import java.util.Optional;
+
+import world.bentobox.bentobox.api.addons.Addon;
+import world.bentobox.bentobox.api.configuration.Config;
+import world.bentobox.bentobox.hooks.VaultHook;
import world.bentobox.challenges.commands.ChallengesCommand;
import world.bentobox.challenges.commands.admin.Challenges;
import world.bentobox.challenges.listeners.ResetListener;
import world.bentobox.challenges.listeners.SaveListener;
-import world.bentobox.bentobox.api.addons.Addon;
-import world.bentobox.bentobox.api.commands.CompositeCommand;
+import world.bentobox.level.Level;
+
/**
* Add-on to BSkyBlock that enables challenges
@@ -16,90 +21,269 @@ import world.bentobox.bentobox.api.commands.CompositeCommand;
*/
public class ChallengesAddon extends Addon {
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
private ChallengesManager challengesManager;
- private String permissionPrefix = "addon";
- private FreshSqueezedChallenges importManager;
+
+ private ChallengesImportManager importManager;
+
+ private Settings settings;
+
private boolean hooked;
+ /**
+ * This boolean indicate if economy is enabled.
+ */
+ private boolean economyProvided;
+
+ /**
+ * VaultHook that process economy.
+ * todo: because of BentoBox limitations.
+ */
+ private Optional vaultHook = null;
+
+ /**
+ * Level addon.
+ */
+ private Level levelAddon;
+
+ /**
+ * This indicate if level addon exists.
+ */
+ private boolean levelProvided;
+
+// ---------------------------------------------------------------------
+// Section: Constants
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Permission prefix for addon.
+ */
+ private static final String PERMISSION_PREFIX = "addon";
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ */
@Override
public void onLoad() {
// Save default config.yml
- saveDefaultConfig();
+ this.saveDefaultConfig();
+ // Load the plugin's config
+ this.loadSettings();
}
+
+ /**
+ * {@inheritDoc}
+ */
@Override
public void onEnable() {
// Check if it is enabled - it might be loaded, but not enabled.
- if (getPlugin() == null || !getPlugin().isEnabled()) {
+ if (this.getPlugin() == null || !this.getPlugin().isEnabled()) {
Bukkit.getLogger().severe("BentoBox is not available or disabled!");
this.setState(State.DISABLED);
return;
}
// Challenges Manager
- challengesManager = new ChallengesManager(this);
+ this.challengesManager = new ChallengesManager(this);
// Challenge import setup
- importManager = new FreshSqueezedChallenges(this);
+ this.importManager = new ChallengesImportManager(this);
- // Register commands - run one tick later to allow all addons to load
- // AcidIsland hook in
- getPlugin().getAddonsManager().getAddonByName("AcidIsland").ifPresent(a -> {
- CompositeCommand acidIslandCmd = getPlugin().getCommandsManager().getCommand("ai");
- if (acidIslandCmd != null) {
- new ChallengesCommand(this, acidIslandCmd);
- CompositeCommand acidCmd = getPlugin().getCommandsManager().getCommand("acid");
- new Challenges(this, acidCmd);
- hooked = true;
+ this.getPlugin().getAddonsManager().getGameModeAddons().forEach(gameModeAddon -> {
+ if (!this.settings.getDisabledGameModes().contains(gameModeAddon.getDescription().getName()))
+ {
+ if (gameModeAddon.getPlayerCommand().isPresent())
+ {
+ new ChallengesCommand(this, gameModeAddon.getPlayerCommand().get());
+ this.hooked = true;
+ }
+
+ if (gameModeAddon.getAdminCommand().isPresent())
+ {
+ new Challenges(this, gameModeAddon.getAdminCommand().get());
+ this.hooked = true;
+ }
+ }
+ });
+
+ if (this.hooked) {
+ // Try to find Level addon and if it does not exist, display a warning
+
+ Optional level = this.getAddonByName("Level");
+
+ if (!level.isPresent())
+ {
+ this.logWarning("Level add-on not found so level challenges will not work!");
+ this.levelAddon = null;
}
- });
- getPlugin().getAddonsManager().getAddonByName("BSkyBlock").ifPresent(a -> {
- // BSkyBlock hook in
- CompositeCommand bsbIslandCmd = getPlugin().getCommandsManager().getCommand("island");
- if (bsbIslandCmd != null) {
- new ChallengesCommand(this, bsbIslandCmd);
- CompositeCommand bsbAdminCmd = getPlugin().getCommandsManager().getCommand("bsbadmin");
- new Challenges(this, bsbAdminCmd);
- hooked = true;
+ else
+ {
+ this.levelProvided = true;
+ this.levelAddon = (Level) level.get();
}
- });
- // If the add-on never hooks in, then it is useless
- if (!hooked) {
- logError("Challenges could not hook into AcidIsland or BSkyBlock so will not do anything!");
+
+ // BentoBox limitation. Cannot check hooks, as HookManager is created after loading addons.
+// Optional vault = this.getPlugin().getVault();
+//
+// if (!vault.isPresent() || !vault.get().hook())
+// {
+// this.vaultHook = null;
+// this.logWarning("Economy plugin not found so money options will not work!");
+// }
+// else
+// {
+// this.economyProvided = true;
+// this.vaultHook = vault.get();
+// }
+
+ // Register the reset listener
+ this.registerListener(new ResetListener(this));
+ // Register the autosave listener.
+ this.registerListener(new SaveListener(this));
+ } else {
+ this.logError("Challenges could not hook into AcidIsland or BSkyBlock so will not do anything!");
this.setState(State.DISABLED);
- return;
}
- // Try to find Level addon and if it does not exist, display a warning
- if (!getAddonByName("Level").isPresent()) {
- logWarning("Level add-on not found so level challenges will not work!");
- }
- // Register the reset listener
- this.registerListener(new ResetListener(this));
- // Register the autosave listener.
- this.registerListener(new SaveListener(this));
- // Done
}
+
+ /**
+ * {@inheritDoc}
+ */
@Override
- public void onDisable(){
- if (challengesManager != null) {
- challengesManager.save();
+ public void onReload()
+ {
+ if (this.hooked) {
+ this.challengesManager.save();
+
+ this.loadSettings();
+ this.getLogger().info("Challenges addon reloaded.");
}
}
- public ChallengesManager getChallengesManager() {
- return challengesManager;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onDisable() {
+ if (this.hooked) {
+ this.challengesManager.save();
+ }
+
+ if (this.settings != null)
+ {
+ new Config<>(this, Settings.class).saveConfigObject(this.settings);
+ }
}
+
+ /**
+ * This method loads addon configuration settings in memory.
+ */
+ private void loadSettings() {
+ this.settings = new Config<>(this, Settings.class).loadConfigObject();
+
+ if (this.settings == null) {
+ // Disable
+ this.logError("Challenges settings could not load! Addon disabled.");
+ this.setState(State.DISABLED);
+ }
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Getters
+// ---------------------------------------------------------------------
+
+
+ /**
+ * @return challengesManager
+ */
+ public ChallengesManager getChallengesManager() {
+ return this.challengesManager;
+ }
+
+
+ /**
+ * @return Permission Prefix.
+ */
@Override
public String getPermissionPrefix() {
- return permissionPrefix ;
+ return PERMISSION_PREFIX;
}
+
/**
* @return the importManager
*/
- public FreshSqueezedChallenges getImportManager() {
- return importManager;
+ public ChallengesImportManager getImportManager() {
+ return this.importManager;
}
+
+ /**
+ * @return the challenge settings.
+ */
+ public Settings getChallengesSettings()
+ {
+ return this.settings;
+ }
+
+
+ /**
+ *
+ * @return economyProvided variable.
+ */
+ public boolean isEconomyProvided()
+ {
+ if (!this.economyProvided && this.getPlugin().getVault().isPresent() && this.vaultHook == null)
+ {
+ this.vaultHook = this.getPlugin().getVault();
+ this.economyProvided = this.vaultHook.get().hook();
+ }
+
+ return this.economyProvided;
+ }
+
+
+ /**
+ * Returns VaultHook. Used to get easier access to Economy. NEVER USE WITHOUT isEconomyProvided or null
+ * check.
+ * @return VaultHook or null.
+ */
+ public VaultHook getEconomyProvider()
+ {
+ return vaultHook.orElseGet(null);
+ }
+
+
+ /**
+ *
+ * @return levelProvided variable.
+ */
+ public boolean isLevelProvided()
+ {
+ return levelProvided;
+ }
+
+
+ /**
+ * This method returns Level addon. Used to easier access to Level. NEVER USE WITHOUT isLevelProvided or null
+ * @return LevelAddon or null.
+ */
+ public Level getLevelAddon()
+ {
+ return levelAddon;
+ }
}
diff --git a/src/main/java/world/bentobox/challenges/FreshSqueezedChallenges.java b/src/main/java/world/bentobox/challenges/ChallengesImportManager.java
similarity index 71%
rename from src/main/java/world/bentobox/challenges/FreshSqueezedChallenges.java
rename to src/main/java/world/bentobox/challenges/ChallengesImportManager.java
index ef2af71..c16ab32 100644
--- a/src/main/java/world/bentobox/challenges/FreshSqueezedChallenges.java
+++ b/src/main/java/world/bentobox/challenges/ChallengesImportManager.java
@@ -16,17 +16,21 @@ import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
-import world.bentobox.challenges.database.object.ChallengeLevels;
-import world.bentobox.challenges.database.object.Challenges;
+import world.bentobox.bentobox.util.ItemParser;
+import world.bentobox.challenges.database.object.ChallengeLevel;
+import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.util.Util;
+import world.bentobox.challenges.utils.GuiUtils;
+
/**
* Imports challenges
* @author tastybento
*
*/
-public class FreshSqueezedChallenges {
+public class ChallengesImportManager
+{
private ChallengesAddon addon;
private YamlConfiguration chal;
@@ -35,7 +39,7 @@ public class FreshSqueezedChallenges {
* Import challenges from challenges.yml
* @param challengesAddon
*/
- public FreshSqueezedChallenges(ChallengesAddon challengesAddon) {
+ public ChallengesImportManager(ChallengesAddon challengesAddon) {
this.addon = challengesAddon;
File challengeFile = new File(addon.getDataFolder(), "challenges.yml");
if (!challengeFile.exists()) {
@@ -63,13 +67,13 @@ public class FreshSqueezedChallenges {
user.sendMessage("challenges.admin.import.no-load","[message]", e.getMessage());
return false;
}
- makeLevels(user);
+ makeLevels(user, world, overwrite);
makeChallenges(user, world, overwrite);
addon.getChallengesManager().save();
return true;
}
- private void makeLevels(User user) {
+ private void makeLevels(User user, World world, boolean overwrite) {
// Parse the levels
String levels = chal.getString("challenges.levels", "");
if (!levels.isEmpty()) {
@@ -77,22 +81,23 @@ public class FreshSqueezedChallenges {
String[] lvs = levels.split(" ");
int order = 0;
for (String level : lvs) {
- ChallengeLevels challengeLevel = new ChallengeLevels();
+ ChallengeLevel challengeLevel = new ChallengeLevel();
challengeLevel.setFriendlyName(level);
- challengeLevel.setUniqueId(level);
+ challengeLevel.setUniqueId(Util.getWorld(world).getName() + "_" + level);
challengeLevel.setOrder(order++);
- challengeLevel.setWaiveramount(chal.getInt("challenges.waiveramount"));
+ challengeLevel.setWorld(Util.getWorld(world).getName());
+ challengeLevel.setWaiverAmount(chal.getInt("challenges.waiveramount"));
// Check if there is a level reward
ConfigurationSection unlock = chal.getConfigurationSection("challenges.levelUnlock." + level);
if (unlock != null) {
challengeLevel.setUnlockMessage(unlock.getString("message"));
- challengeLevel.setRewardDescription(unlock.getString("rewardDesc",""));
+ challengeLevel.setRewardText(unlock.getString("rewardDesc",""));
challengeLevel.setRewardItems(parseItems(unlock.getString("itemReward","")));
- challengeLevel.setMoneyReward(unlock.getInt("moneyReward"));
- challengeLevel.setExpReward(unlock.getInt("expReward"));
+ challengeLevel.setRewardMoney(unlock.getInt("moneyReward"));
+ challengeLevel.setRewardExperience(unlock.getInt("expReward"));
challengeLevel.setRewardCommands(unlock.getStringList("commands"));
}
- addon.getChallengesManager().storeLevel(challengeLevel);
+ addon.getChallengesManager().loadLevel(challengeLevel, overwrite, user, false);
}
} else {
user.sendMessage("challenges.admin.import.no-levels");
@@ -102,53 +107,63 @@ public class FreshSqueezedChallenges {
/**
* Imports challenges
* @param overwrite
- * @param args
*/
private void makeChallenges(User user, World world, boolean overwrite) {
int size = 0;
// Parse the challenge file
ConfigurationSection chals = chal.getConfigurationSection("challenges.challengeList");
for (String challenge : chals.getKeys(false)) {
- Challenges newChallenge = new Challenges();
+ Challenge newChallenge = new Challenge();
newChallenge.setUniqueId(Util.getWorld(world).getName() + "_" + challenge);
newChallenge.setDeployed(true);
ConfigurationSection details = chals.getConfigurationSection(challenge);
newChallenge.setFriendlyName(details.getString("friendlyname", challenge));
- newChallenge.setWorld(Util.getWorld(world).getName());
- newChallenge.setDescription(addon.getChallengesManager().stringSplit(details.getString("description", "")));
- newChallenge.setIcon(new ParseItem(addon, details.getString("icon") + ":1").getItem());
- newChallenge.setLevel(details.getString("level", ChallengesManager.FREE));
- newChallenge.setChallengeType(Challenges.ChallengeType.valueOf(details.getString("type","INVENTORY").toUpperCase()));
+ newChallenge.setDescription(GuiUtils.stringSplit(details.getString("description", "")));
+ newChallenge.setIcon(ItemParser.parse(details.getString("icon") + ":1"));
+
+ if (details.getString("type").equalsIgnoreCase("level"))
+ {
+ // Fix for older version config
+ newChallenge.setChallengeType(Challenge.ChallengeType.OTHER);
+ }
+ else
+ {
+ newChallenge.setChallengeType(Challenge.ChallengeType.valueOf(details.getString("type","INVENTORY").toUpperCase()));
+ }
+
newChallenge.setTakeItems(details.getBoolean("takeItems",true));
newChallenge.setRewardText(details.getString("rewardText", ""));
newChallenge.setRewardCommands(details.getStringList("rewardcommands"));
newChallenge.setRewardMoney(details.getInt("moneyReward",0));
- newChallenge.setRewardExp(details.getInt("expReward"));
+ newChallenge.setRewardExperience(details.getInt("expReward"));
newChallenge.setRepeatable(details.getBoolean("repeatable"));
newChallenge.setRepeatRewardText(details.getString("repeatRewardText",""));
newChallenge.setRepeatMoneyReward(details.getInt("repearMoneyReward"));
- newChallenge.setRepeatExpReward(details.getInt("repeatExpReward"));
+ newChallenge.setRepeatExperienceReward(details.getInt("repeatExpReward"));
newChallenge.setRepeatRewardCommands(details.getStringList("repeatrewardcommands"));
newChallenge.setMaxTimes(details.getInt("maxtimes"));
// TODO reset allowed
- newChallenge.setReqMoney(details.getInt("requiredMoney"));
- newChallenge.setReqExp(details.getInt("requiredExp"));
+ newChallenge.setRequiredMoney(details.getInt("requiredMoney"));
+ newChallenge.setRequiredExperience(details.getInt("requiredExp"));
String reqItems = details.getString("requiredItems","");
- if (newChallenge.getChallengeType().equals(Challenges.ChallengeType.INVENTORY)) {
+ if (newChallenge.getChallengeType().equals(Challenge.ChallengeType.INVENTORY)) {
newChallenge.setRequiredItems(parseItems(reqItems));
- } else if (newChallenge.getChallengeType().equals(Challenges.ChallengeType.LEVEL)) {
- newChallenge.setReqIslandlevel(Long.parseLong(reqItems));
- } else if (newChallenge.getChallengeType().equals(Challenges.ChallengeType.ISLAND)) {
+ } else if (newChallenge.getChallengeType().equals(Challenge.ChallengeType.OTHER)) {
+ newChallenge.setRequiredIslandLevel(Long.parseLong(reqItems));
+ } else if (newChallenge.getChallengeType().equals(Challenge.ChallengeType.ISLAND)) {
parseEntities(newChallenge, reqItems);
}
newChallenge.setRewardItems(parseItems(details.getString("itemReward")));
newChallenge.setRepeatItemReward(parseItems(details.getString("repeatItemReward")));
// Save
- if (addon.getChallengesManager().storeChallenge(newChallenge, overwrite, user, false)) {
+ this.addon.getChallengesManager().addChallengeToLevel(newChallenge,
+ addon.getChallengesManager().getLevel(Util.getWorld(world).getName() + "_" + details.getString("level")));
+
+ if (addon.getChallengesManager().loadChallenge(newChallenge, overwrite, user, false)) {
size++;
}
}
- addon.getChallengesManager().sortChallenges();
+
user.sendMessage("challenges.admin.import.number", "[number]", String.valueOf(size));
}
@@ -157,7 +172,7 @@ public class FreshSqueezedChallenges {
* @param challenge - challenge to be adjusted
* @param string - string from YAML file
*/
- private void parseEntities(Challenges challenge, String string) {
+ private void parseEntities(Challenge challenge, String string) {
Map req = new EnumMap<>(EntityType.class);
Map blocks = new EnumMap<>(Material.class);
if (!string.isEmpty()) {
@@ -179,7 +194,7 @@ public class FreshSqueezedChallenges {
List result = new ArrayList<>();
if (!reqList.isEmpty()) {
for (String s : reqList.split(" ")) {
- ItemStack item = new ParseItem(addon,s).getItem();
+ ItemStack item = ItemParser.parse(s);
if (item != null) {
result.add(item);
}
@@ -187,7 +202,4 @@ public class FreshSqueezedChallenges {
}
return result;
}
-
-
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java
index 7e2dfdb..007de11 100644
--- a/src/main/java/world/bentobox/challenges/ChallengesManager.java
+++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java
@@ -1,517 +1,957 @@
package world.bentobox.challenges;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Optional;
-import java.util.Set;
-import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import java.util.*;
import java.util.stream.Collectors;
-import org.apache.commons.lang.WordUtils;
-import org.bukkit.ChatColor;
-import org.bukkit.Material;
-import org.bukkit.World;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-
-import world.bentobox.challenges.commands.admin.SurroundChallengeBuilder;
-import world.bentobox.challenges.database.object.ChallengeLevels;
-import world.bentobox.challenges.database.object.Challenges;
-import world.bentobox.challenges.database.object.Challenges.ChallengeType;
-import world.bentobox.challenges.database.object.ChallengesPlayerData;
-import world.bentobox.challenges.panel.ChallengesPanels;
-import world.bentobox.bentobox.api.configuration.Config;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.util.Util;
-
-public class ChallengesManager {
-
- public static final String FREE = "Free";
- private Map> challengeMap;
- private Config chConfig;
- private Config lvConfig;
- private Database players;
- private ChallengesPanels challengesPanels;
- private Map playerData;
- private ChallengesAddon addon;
-
- public ChallengesManager(ChallengesAddon addon) {
- this.addon = addon;
- // Set up the configs
- chConfig = new Config<>(addon, Challenges.class);
- lvConfig = new Config<>(addon, ChallengeLevels.class);
- // Players is where all the player history will be stored
- players = new Database<>(addon, ChallengesPlayerData.class);
- // Cache of challenges
- challengeMap = new LinkedHashMap<>();
- // Cache of player data
- playerData = new HashMap<>();
- load();
- }
-
- /**
- * Load player from database into the cache or create new player data
- * @param user - user to add
- */
- private void addPlayer(User user) {
- if (playerData.containsKey(user.getUniqueId())) {
- return;
- }
- // The player is not in the cache
- // Check if the player exists in the database
- if (players.objectExists(user.getUniqueId().toString())) {
- // Load player from database
- ChallengesPlayerData data = players.loadObject(user.getUniqueId().toString());
- // Store in cache
- playerData.put(user.getUniqueId(), data);
- } else {
- // Create the player data
- ChallengesPlayerData pd = new ChallengesPlayerData(user.getUniqueId().toString());
- players.saveObject(pd);
- // Add to cache
- playerData.put(user.getUniqueId(), pd);
- }
- }
-
- /**
- * Check how many times a player has done a challenge before
- * @param user - user
- * @param challenge - challenge
- * @return - number of times
- */
- public long checkChallengeTimes(User user, Challenges challenge, World world) {
- addPlayer(user);
- return playerData.get(user.getUniqueId()).getTimes(world, challenge.getUniqueId());
- }
-
- /**
- * Creates a simple example description of the requirements
- * @param user - user of this command
- * @param requiredItems - list of items
- * @return Description list
- */
- private List createDescription(User user, List requiredItems) {
- addPlayer(user);
- List result = new ArrayList<>();
- result.add(user.getTranslation("challenges.admin.create.description"));
- for (ItemStack item : requiredItems) {
- result.add(user.getTranslation("challenges.admin.create.description-item-color") + item.getAmount() + " x " + Util.prettifyText(item.getType().toString()));
- }
- return result;
- }
-
- /**
- * Creates an inventory challenge
- * @param user - the user who is making the challenge
- * @param inventory - the inventory that will be used to make the challenge
- */
- public boolean createInvChallenge(User user, Inventory inventory) {
- addPlayer(user);
- if (inventory.getContents().length == 0) {
- return false;
- }
- Challenges newChallenge = new Challenges();
- newChallenge.setChallengeType(ChallengeType.INVENTORY);
- newChallenge.setFriendlyName(inventory.getTitle());
- newChallenge.setDeployed(false);
- List requiredItems = new ArrayList<>();
- inventory.forEach(item -> {
- if (item != null && !item.getType().equals(Material.AIR)) {
- requiredItems.add(item);
- }
- });
- newChallenge.setRequiredItems(requiredItems);
- newChallenge.setTakeItems(true);
- newChallenge.setUniqueId(inventory.getTitle());
- newChallenge.setIcon(new ItemStack(Material.MAP));
- newChallenge.setLevel(FREE);
- newChallenge.setDescription(createDescription(user, requiredItems));
-
- // Move all the items back to the player's inventory
- inventory.forEach(item -> {
- if (item != null) {
- Map residual = user.getInventory().addItem(item);
- // Drop any residual items at the foot of the player
- residual.forEach((k, v) -> user.getWorld().dropItem(user.getLocation(), v));
- }
- });
-
- // Save the challenge
- if (!chConfig.saveConfigObject(newChallenge)) {
- user.sendRawMessage(ChatColor.RED + "Challenge creation failed!");
- return false;
- }
- user.sendRawMessage("Success");
- return true;
- }
-
- /**
- * Create a surrounding challenge
- * @param challengeInfo - info on the challenge from the builder
- * @return true if successful, false if not
- */
- public boolean createSurroundingChallenge(SurroundChallengeBuilder challengeInfo) {
- if (challengeInfo.getReqBlocks().isEmpty() && challengeInfo.getReqEntities().isEmpty()) {
- challengeInfo.getOwner().sendMessage("challenges.error.no-items-clicked");
- return false;
- }
- Challenges newChallenge = new Challenges();
- newChallenge.setChallengeType(ChallengeType.ISLAND);
- newChallenge.setFriendlyName(challengeInfo.getName());
- newChallenge.setDeployed(true);
- newChallenge.setRequiredBlocks(challengeInfo.getReqBlocks());
- newChallenge.setRequiredEntities(challengeInfo.getReqEntities());
- newChallenge.setUniqueId(challengeInfo.getName());
- newChallenge.setIcon(new ItemStack(Material.ARMOR_STAND));
- newChallenge.setLevel(FREE);
-
- // Save the challenge
- if (!chConfig.saveConfigObject(newChallenge)) {
- challengeInfo.getOwner().sendMessage("challenges.error.could-not-save");
- return false;
- }
- return true;
- }
-
- /**
- * Get the list of all challenge unique names.
- * @return List of challenge names
- */
- public List getAllChallengesList() {
- List result = new ArrayList<>();
- challengeMap.values().forEach(ch -> ch.forEach(c -> result.add(c.getUniqueId())));
- return result;
- }
-
- /**
- * Get the list of all challenge unique names for world.
- * @param world - the world to check
- * @return List of challenge names
- */
- public List getAllChallengesList(World world) {
- List result = new ArrayList<>();
- challengeMap.values().forEach(ch -> ch.stream().filter(c -> c.getWorld().equals(Util.getWorld(world).getName())).forEach(c -> result.add(c.getUniqueId())));
- return result;
- }
-
- /**
- * Get challenge by name
- * @param name - unique name of challenge
- * @param world - world to check
- * @return - challenge or null if it does not exist
- */
- public Challenges getChallenge(String name, World world) {
- String worldName = Util.getWorld(world).getName();
- for (Set ch : challengeMap.values()) {
- Optional challenge = ch.stream().filter(c -> c.getUniqueId().equalsIgnoreCase(worldName + name)).findFirst();
- if (challenge.isPresent()) {
- return challenge.get();
- }
- }
- return null;
- }
-
- /**
- * Get the status on every level
- * @param user - user
- * @param world - world to check
- * @return Level status - how many challenges still to do on which level
- */
- public List getChallengeLevelStatus(User user, World world) {
- addPlayer(user);
- ChallengesPlayerData pd = playerData.get(user.getUniqueId());
- List result = new ArrayList<>();
- ChallengeLevels previousLevel = null;
- // The first level is always unlocked
- boolean isUnlocked = true;
- // For each challenge level, check how many the user has done
- for (Entry> en : challengeMap.entrySet()) {
- int total = challengeMap.values().size();
- int waiverAmount = en.getKey().getWaiveramount();
- int challengesDone = (int) en.getValue().stream().filter(ch -> pd.isChallengeDone(world, ch.getUniqueId())).count();
- int challsToDo = Math.max(0,total - challengesDone - waiverAmount);
- boolean complete = challsToDo > 0 ? false : true;
- // Create result class with the data
- result.add(new LevelStatus(en.getKey(), previousLevel, challsToDo, complete, isUnlocked));
- // Set up the next level for the next loop
- previousLevel = en.getKey();
- isUnlocked = complete;
- }
- return result;
- }
-
- /**
- * Get the challenge list
- * @return the challengeList
- */
- public Map> getChallengeList() {
- // TODO return the challenges for world
- return challengeMap;
- }
-
- /**
- * Get the set of challenges for this level for this world
- * @param level - the level required
- * @param world
- * @return the set of challenges for this level, or the first set of challenges if level is blank, or a blank list if there are no challenges
- */
- public Set getChallenges(String level, World world) {
- String worldName = Util.getWorld(world).getName();
- Optional lv = challengeMap.keySet().stream().filter(l -> l.getUniqueId().equalsIgnoreCase(level)).findFirst();
- // Get the challenges applicable to this world
- return lv.isPresent() ? challengeMap.get(lv.get()).stream()
- .filter(c -> c.getWorld().equalsIgnoreCase(worldName) || c.getWorld().isEmpty()).collect(Collectors.toSet())
- : new HashSet<>();
- }
-
- /**
- * @return the challengesPanels
- */
- public ChallengesPanels getChallengesPanels() {
- return challengesPanels;
- }
-
- /**
- * Get the previous level to the one supplied
- * @param currentLevel - the current level
- * @return the previous level, or null if there is none
- */
- public ChallengeLevels getPreviousLevel(ChallengeLevels currentLevel) {
- ChallengeLevels result = null;
- for (ChallengeLevels level : challengeMap.keySet()) {
- if (level.equals(currentLevel)) {
- return result;
- }
- result = level;
- }
- return result;
- }
-
- /**
- * Check if a challenge exists - case insensitive
- * @param name - name of challenge
- * @return true if it exists, otherwise false
- */
- public boolean isChallenge(String name) {
- for (Set ch : challengeMap.values()) {
- if (ch.stream().anyMatch(c -> c.getUniqueId().equalsIgnoreCase(name))) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Check if a challenge exists in world - case insensitive
- * @param world - world to check
- * @param name - name of challenge
- * @return true if it exists, otherwise false
- */
- public boolean isChallenge(World world, String name) {
- for (Set ch : challengeMap.values()) {
- if (ch.stream().filter(c -> c.getWorld().equals(Util.getWorld(world).getName())).anyMatch(c -> c.getUniqueId().equalsIgnoreCase(name))) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Checks if a challenge is complete or not
- * @param uniqueId - unique ID - player's UUID
- * @param challengeName - Challenge uniqueId
- * @return - true if completed
- */
- public boolean isChallengeComplete(User user, String challengeName, World world) {
- addPlayer(user);
- return playerData.get(user.getUniqueId()).isChallengeDone(world, challengeName);
- }
-
- /**
- * Check is user can see level
- * @param user - user
- * @param level - level unique id
- * @return true if level is unlocked
- */
- public boolean isLevelUnlocked(User user, String level, World world) {
- addPlayer(user);
- return getChallengeLevelStatus(user, world).stream().filter(LevelStatus::isUnlocked).anyMatch(lv -> lv.getLevel().getUniqueId().equalsIgnoreCase(level));
- }
-
- /**
- * Clear and reload all challenges
- */
- public void load() {
- // Load the challenges
- challengeMap.clear();
- addon.getLogger().info("Loading challenges...");
- chConfig.loadConfigObjects().forEach(this::storeChallenge);
- sortChallenges();
- players.loadObjects().forEach(pd -> {
- try {
- UUID uuid = UUID.fromString(pd.getUniqueId());
- playerData.put(uuid,pd);
- } catch (Exception e) {
- addon.getLogger().severe("UUID for player in challenge data file is invalid!");
- }
- });
- }
-
- /**
- * Save configs and player data
- */
- public void save() {
- challengeMap.entrySet().forEach(en -> {
- lvConfig.saveConfigObject(en.getKey());
- en.getValue().forEach(chConfig::saveConfigObject);
- });
- savePlayers();
- }
-
- private void savePlayers() {
- playerData.values().forEach(players :: saveObject);
- }
-
- private void savePlayer(UUID playerUUID) {
- if (playerData.containsKey(playerUUID)) {
- players.saveObject(playerData.get(playerUUID));
- }
- }
-
- /**
- * Sets the challenge as complete and increments the number of times it has been completed
- * @param user - user
- * @param challengeUniqueId - unique challenge id
- * @param world - world to set
- */
- public void setChallengeComplete(User user, String challengeUniqueId, World world) {
- addPlayer(user);
- playerData.get(user.getUniqueId()).setChallengeDone(world, challengeUniqueId);
- // Save
- savePlayer(user.getUniqueId());
- }
-
- /**
- * Reset the challenge to zero time / not done
- * @param user - user
- * @param challengeUniqueId - unique challenge id
- * @param world - world to set
- */
- public void setResetChallenge(User user, String challengeUniqueId, World world) {
- addPlayer(user);
- playerData.get(user.getUniqueId()).setChallengeTimes(world, challengeUniqueId, 0);
- // Save
- savePlayer(user.getUniqueId());
- }
-
- /**
- * @param challengeList the challengeList to set
- */
- public void setChallengeList(Map> challengeList) {
- this.challengeMap = challengeList;
- }
-
- public void sortChallenges() {
- // Sort the challenge list into level order
- challengeMap = challengeMap.entrySet().stream()
- .sorted(Map.Entry.comparingByKey())
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
- (oldValue, newValue) -> oldValue, LinkedHashMap::new));
- }
+import world.bentobox.challenges.database.object.Challenge;
+import world.bentobox.challenges.database.object.ChallengeLevel;
+import world.bentobox.challenges.database.object.ChallengesPlayerData;
+import world.bentobox.challenges.utils.LevelStatus;
- /**
- * Store challenge silently. Used when loading.
- * @param challenge
- * @return true if successful
- */
- private boolean storeChallenge(Challenges challenge) {
- return storeChallenge(challenge, true, null, true);
- }
+/**
+ * This class manges challenges. It allows access to all data that is stored to database.
+ * It also provides information about challenge level status for each user.
+ */
+public class ChallengesManager
+{
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
- /**
- * Stores the challenge.
- * @param challenge - challenge
- * @param overwrite - true if previous challenge should be overwritten
- * @param user - user making the request
- * @param silent - if true, no messages are sent to user
- * @return - true if imported
- */
- public boolean storeChallenge(Challenges challenge, boolean overwrite, User user, boolean silent) {
- // See if we have this level already
- ChallengeLevels level;
- if (lvConfig.configObjectExists(challenge.getLevel())) {
- // Get it from the database
- level = lvConfig.loadConfigObject(challenge.getLevel());
- } else {
- // Make it
- level = new ChallengeLevels();
- level.setUniqueId(challenge.getLevel());
- lvConfig.saveConfigObject(level);
- }
- challengeMap.putIfAbsent(level, new HashSet<>());
- if (challengeMap.get(level).contains(challenge)) {
- if (!overwrite) {
- if (!silent) {
- user.sendMessage("challenges.admin.import.skipping", "[challenge]", challenge.getFriendlyName());
- }
- return false;
- } else {
- if (!silent) {
- user.sendMessage("challenges.admin.import.overwriting", "[challenge]", challenge.getFriendlyName());
- }
- challengeMap.get(level).add(challenge);
- return true;
- }
- }
- if (!silent) {
- user.sendMessage("challenges.admin.import.imported", "[challenge]", challenge.getFriendlyName());
- }
- challengeMap.get(level).add(challenge);
- return true;
- }
+ /**
+ * This config object stores structures for challenge objects.
+ */
+ private Database challengeDatabase;
- /**
- * Store a challenge level
- * @param level the challenge level
- */
- public void storeLevel(ChallengeLevels level) {
- lvConfig.saveConfigObject(level);
- }
+ /**
+ * This config object stores structures for challenge level objects.
+ */
+ private Database levelDatabase;
- /**
- * Simple splitter
- * @param string - string to be split
- * @return list of split strings
- */
- public List stringSplit(String string) {
- string = ChatColor.translateAlternateColorCodes('&', string);
- // Check length of lines
- List result = new ArrayList<>();
- Arrays.asList(string.split("\\|")).forEach(line -> result.addAll(Arrays.asList(WordUtils.wrap(line,25).split("\\n"))));
- return result;
- }
+ /**
+ * This database allows to access player challenge data.
+ */
+ private Database playersDatabase;
- /**
- * Resets all the challenges for user in world
- * @param uuid - island owner's UUID
- * @param world - world
- */
- public void resetAllChallenges(UUID uuid, World world) {
- User user = User.getInstance(uuid);
- addPlayer(user);
- playerData.get(user.getUniqueId()).reset(world);
- // Save
- savePlayer(user.getUniqueId());
+ /**
+ * This is local cache that links challenge unique id with challenge object.
+ */
+ private Map challengeCacheData;
- }
+ /**
+ * This is local cache that links level unique id with level object.
+ */
+ private Map levelCacheData;
+
+ /**
+ * This is local cache that links UUID with corresponding player challenge data.
+ */
+ private Map playerCacheData;
+
+ /**
+ * This variable allows to access ChallengesAddon.
+ */
+ private ChallengesAddon addon;
-}
+// ---------------------------------------------------------------------
+// Section: Constants
+// ---------------------------------------------------------------------
+
+
+ /**
+ * String for free Challenge Level.
+ */
+ public static final String FREE = "";
+
+
+// ---------------------------------------------------------------------
+// Section: Constructor
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Initial constructor. Inits and loads all data.
+ * @param addon challenges addon.
+ */
+ public ChallengesManager(ChallengesAddon addon)
+ {
+ this.addon = addon;
+ // Set up the configs
+ this.challengeDatabase = new Database<>(addon, Challenge.class);
+ this.levelDatabase = new Database<>(addon, ChallengeLevel.class);
+ // Players is where all the player history will be stored
+ this.playersDatabase = new Database<>(addon, ChallengesPlayerData.class);
+
+ // Init all cache objects.
+ this.challengeCacheData = new HashMap<>();
+ this.levelCacheData = new HashMap<>();
+ this.playerCacheData = new HashMap<>();
+
+ this.load();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Loading and storing methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Clear and reload all challenges
+ */
+ public void load()
+ {
+ this.challengeCacheData.clear();
+ this.levelCacheData.clear();
+ 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);
+ }
+
+
+ /**
+ * Load challenge silently. Used when loading.
+ *
+ * @param challenge Challenge that must be loaded.
+ * @return true if successful
+ */
+ private void loadChallenge(Challenge challenge)
+ {
+ this.loadChallenge(challenge, true, null, true);
+ }
+
+
+ /**
+ * Load the challenge.
+ *
+ * @param challenge - challenge
+ * @param overwrite - true if previous challenge should be overwritten
+ * @param user - user making the request
+ * @param silent - if true, no messages are sent to user
+ * @return - true if imported
+ */
+ public boolean loadChallenge(Challenge challenge,
+ boolean overwrite,
+ User user,
+ boolean silent)
+ {
+ if (this.challengeCacheData.containsKey(challenge.getUniqueId()))
+ {
+ if (!overwrite)
+ {
+ if (!silent)
+ {
+ user.sendMessage("challenges.admin.import.skipping",
+ "[object]", challenge.getFriendlyName());
+ }
+
+ return false;
+ }
+ else
+ {
+ if (!silent)
+ {
+ user.sendMessage("challenges.admin.import.overwriting",
+ "[object]", challenge.getFriendlyName());
+ }
+ }
+ }
+ else
+ {
+ if (!silent)
+ {
+ user.sendMessage("challenges.admin.import.add",
+ "[object]", challenge.getFriendlyName());
+ }
+ }
+
+ this.challengeCacheData.put(challenge.getUniqueId(), challenge);
+ return true;
+ }
+
+
+ /**
+ * Store a challenge level
+ *
+ * @param level the challenge level
+ */
+ private void loadLevel(ChallengeLevel level)
+ {
+ this.loadLevel(level, true, null, true);
+ }
+
+
+ /**
+ * This method loads given level into local cache. It provides functionality to
+ * overwrite local value with new one, and send message to given user.
+ * @param level of type ChallengeLevel that must be loaded in local cache.
+ * @param overwrite of type boolean that indicate if local element must be overwritten.
+ * @param user of type User who will receive messages.
+ * @param silent of type boolean that indicate if message to user must be sent.
+ * @return boolean that indicate about load status.
+ */
+ public boolean loadLevel(ChallengeLevel level, boolean overwrite, User user, boolean silent)
+ {
+ if (!this.isValidLevel(level))
+ {
+ user.sendMessage("challenges.admin.import.error",
+ "[object]", level.getFriendlyName());
+
+ return false;
+ }
+
+ if (this.levelCacheData.containsKey(level.getUniqueId()))
+ {
+ if (!overwrite)
+ {
+ if (!silent)
+ {
+ user.sendMessage("challenges.admin.import.skipping",
+ "[object]", level.getFriendlyName());
+ }
+
+ return false;
+ }
+ else
+ {
+ if (!silent)
+ {
+ user.sendMessage("challenges.admin.import.overwriting",
+ "[object]", level.getFriendlyName());
+ }
+ }
+ }
+ else
+ {
+ if (!silent)
+ {
+ user.sendMessage("challenges.admin.import.add",
+ "[object]", level.getFriendlyName());
+ }
+ }
+
+ this.levelCacheData.put(level.getUniqueId(), level);
+ return true;
+ }
+
+
+ /**
+ * This method stores PlayerData into local cache.
+ * @param playerData ChallengesPlayerData that must be loaded.
+ */
+ private void loadPlayerData(ChallengesPlayerData playerData)
+ {
+ try
+ {
+ UUID uuid = UUID.fromString(playerData.getUniqueId());
+ this.playerCacheData.put(uuid, playerData);
+ }
+ catch (Exception e)
+ {
+ this.addon.getLogger().severe("UUID for player in challenge data file is invalid!");
+ }
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Other storing related methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method checks if given level all challenges exists in local cache or database.
+ * It also checks if world where level must operate exists.
+ * @param level that must be validated
+ * @return true ir level is valid, otherwise false.
+ */
+ private boolean isValidLevel(ChallengeLevel level)
+ {
+ if (!this.addon.getPlugin().getIWM().inWorld(Bukkit.getWorld(level.getWorld())))
+ {
+ return false;
+ }
+
+ for (String uniqueID : level.getChallenges())
+ {
+ if (!this.challengeCacheData.containsKey(uniqueID))
+ {
+ if (this.challengeDatabase.objectExists(uniqueID))
+ {
+ this.loadChallenge(this.challengeDatabase.loadObject(uniqueID));
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Load player from database into the cache or create new player data
+ *
+ * @param user - user to add
+ */
+ private void addPlayer(User user)
+ {
+ if (this.playerCacheData.containsKey(user.getUniqueId()))
+ {
+ return;
+ }
+
+ // The player is not in the cache
+ // Check if the player exists in the database
+
+ if (this.playersDatabase.objectExists(user.getUniqueId().toString()))
+ {
+ // Load player from database
+ ChallengesPlayerData data = this.playersDatabase.loadObject(user.getUniqueId().toString());
+ // Store in cache
+ this.playerCacheData.put(user.getUniqueId(), data);
+ }
+ else
+ {
+ // Create the player data
+ ChallengesPlayerData pd = new ChallengesPlayerData(user.getUniqueId().toString());
+ this.playersDatabase.saveObject(pd);
+ // Add to cache
+ this.playerCacheData.put(user.getUniqueId(), pd);
+ }
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Saving methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method init all cached object saving to database.
+ */
+ public void save()
+ {
+ this.saveChallenges();
+ this.saveLevels();
+ this.savePlayers();
+ }
+
+
+ /**
+ * This method saves all challenges to database.
+ */
+ private void saveChallenges()
+ {
+ this.challengeCacheData.values().forEach(this.challengeDatabase::saveObject);
+ }
+
+
+ /**
+ * This method saves given challenge object to database.
+ * @param challenge object that must be saved
+ */
+ private void saveChallenge(Challenge challenge)
+ {
+ this.challengeDatabase.saveObject(challenge);
+ }
+
+
+ /**
+ * This method saves all levels to database.
+ */
+ private void saveLevels()
+ {
+ this.levelCacheData.values().forEach(this.levelDatabase::saveObject);
+ }
+
+
+ /**
+ * This method saves given level into database.
+ * @param level object that must be saved
+ */
+ private void saveLevel(ChallengeLevel level)
+ {
+ this.levelDatabase.saveObject(level);
+ }
+
+
+ /**
+ * This method saves all players to database.
+ */
+ private void savePlayers()
+ {
+ this.playerCacheData.values().forEach(this.playersDatabase::saveObject);
+ }
+
+
+ /**
+ * This method saves player with given UUID.
+ * @param playerUUID users UUID.
+ */
+ private void savePlayer(UUID playerUUID)
+ {
+ if (this.playerCacheData.containsKey(playerUUID))
+ {
+ this.playersDatabase.saveObject(this.playerCacheData.get(playerUUID));
+ }
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Player Data related methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method returns all players who have done at least one challenge in given world.
+ * @param world World in which must search challenges.
+ * @return List with players who have done at least on challenge.
+ */
+ public List getPlayers(World world)
+ {
+ List allChallengeList = this.getAllChallengesNames(world);
+
+ // This is using Database, as some users may not be in the cache.
+
+ return this.playersDatabase.loadObjects().stream().filter(playerData ->
+ allChallengeList.stream().anyMatch(playerData::isChallengeDone)).
+ map(playerData -> Bukkit.getPlayer(UUID.fromString(playerData.getUniqueId()))).
+ collect(Collectors.toList());
+ }
+
+
+ /**
+ * This method returns how many times a player has done a challenge before
+ * @param user - user
+ * @param challenge - challenge
+ * @return - number of times
+ */
+ public long getChallengeTimes(User user, Challenge challenge)
+ {
+ this.addPlayer(user);
+ return this.playerCacheData.get(user.getUniqueId()).getTimes(challenge.getUniqueId());
+ }
+
+
+ /**
+ * Checks if a challenge is complete or not
+ *
+ * @param user - User who must be checked.
+ * @param challenge - Challenge
+ * @return - true if completed
+ */
+ public boolean isChallengeComplete(User user, Challenge challenge)
+ {
+ this.addPlayer(user);
+ return this.playerCacheData.get(user.getUniqueId()).isChallengeDone(challenge.getUniqueId());
+ }
+
+
+ /**
+ * Get the status on every level
+ *
+ * @param user - user
+ * @param world - world
+ * @return Level status - how many challenges still to do on which level
+ */
+ public List getChallengeLevelStatus(User user, World world)
+ {
+ this.addPlayer(user);
+ ChallengesPlayerData playerData = this.playerCacheData.get(user.getUniqueId());
+
+ List challengeLevelList = this.getLevels(world);
+
+ List result = new ArrayList<>();
+
+ // The first level is always unlocked and previous for it is null.
+ ChallengeLevel previousLevel = null;
+ int doneChallengeCount = 0;
+
+ // For each challenge level, check how many the user has done
+ for (ChallengeLevel level : challengeLevelList)
+ {
+ // To find how many challenges user still must do in previous level, we must
+ // know how many challenges there were and how many has been done. Then
+ // remove waiver amount to get count of challenges that still necessary to do.
+
+ int challengesToDo = previousLevel == null ? 0 :
+ (previousLevel.getChallenges().size() - doneChallengeCount - level.getWaiverAmount());
+
+ // As level already contains unique ids of challenges, just iterate through them.
+ doneChallengeCount = (int) level.getChallenges().stream().filter(playerData::isChallengeDone).count();
+
+ result.add(new LevelStatus(
+ level,
+ previousLevel,
+ challengesToDo,
+ level.getChallenges().size() == doneChallengeCount,
+ challengesToDo <= 0));
+
+ previousLevel = level;
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Check is user can see given level.
+ *
+ * @param user - user
+ * @param world - world
+ * @param level - level
+ * @return true if level is unlocked
+ */
+ public boolean isLevelUnlocked(User user, World world, ChallengeLevel level)
+ {
+ this.addPlayer(user);
+
+ return this.getChallengeLevelStatus(user, world).stream().
+ filter(LevelStatus::isUnlocked).
+ anyMatch(lv -> lv.getLevel().equals(level));
+ }
+
+
+ /**
+ * Sets the challenge as complete and increments the number of times it has been
+ * completed
+ *
+ * @param user - user
+ * @param challenge - challenge
+ */
+ public void setChallengeComplete(User user, Challenge challenge)
+ {
+ this.addPlayer(user);
+ this.playerCacheData.get(user.getUniqueId()).setChallengeDone(challenge.getUniqueId());
+ // Save
+ this.savePlayer(user.getUniqueId());
+ }
+
+
+ /**
+ * Reset the challenge to zero time / not done
+ *
+ * @param user - user
+ * @param challenge - challenge
+ */
+ public void resetChallenge(User user, Challenge challenge)
+ {
+ this.addPlayer(user);
+ this.playerCacheData.get(user.getUniqueId()).setChallengeTimes(challenge.getUniqueId(), 0);
+ // Save
+ this.savePlayer(user.getUniqueId());
+ }
+
+
+
+ /**
+ * Resets all the challenges for user in world
+ *
+ * @param user - island owner's UUID
+ * @param world - world
+ */
+ public void resetAllChallenges(User user, World world)
+ {
+ this.addPlayer(user);
+ this.playerCacheData.get(user.getUniqueId()).reset(world);
+ // Save
+ this.savePlayer(user.getUniqueId());
+ }
+
+
+ /**
+ * This method returns if given user has been already completed given level.
+ * @param level Level that must be checked.
+ * @param user User who need to be checked.
+ * @return true, if level is already completed.
+ */
+ public boolean isLevelCompleted(User user, ChallengeLevel level)
+ {
+ this.addPlayer(user);
+ return this.playerCacheData.get(user.getUniqueId()).isLevelDone(level.getUniqueId());
+ }
+
+
+ /**
+ * This method checks all level challenges and checks if all challenges are done.
+ * @param level Level that must be checked.
+ * @param user User who need to be checked.
+ * @return true, if all challenges are done, otherwise false.
+ */
+ public boolean validateLevelCompletion(User user, ChallengeLevel level)
+ {
+ this.addPlayer(user);
+ ChallengesPlayerData playerData = this.playerCacheData.get(user.getUniqueId());
+ long doneChallengeCount = level.getChallenges().stream().filter(playerData::isChallengeDone).count();
+
+ return level.getChallenges().size() == doneChallengeCount;
+ }
+
+
+ /**
+ * This method sets given level as completed.
+ * @param level Level that must be completed.
+ * @param user User who complete level.
+ */
+ public void setLevelComplete(User user, ChallengeLevel level)
+ {
+ this.addPlayer(user);
+ this.playerCacheData.get(user.getUniqueId()).addCompletedLevel(level.getUniqueId());
+ // Save
+ this.savePlayer(user.getUniqueId());
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Challenges related methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Get the list of all challenge unique names for world.
+ *
+ * @param world - the world to check
+ * @return List of challenge names
+ */
+ public List getAllChallengesNames(World world)
+ {
+ String worldName = Util.getWorld(world).getName();
+ // TODO: Probably need to check also database.
+ return this.challengeCacheData.values().stream().
+ sorted(Comparator.comparing(Challenge::getOrder)).
+ filter(challenge -> challenge.getUniqueId().startsWith(worldName)).
+ map(Challenge::getUniqueId).
+ collect(Collectors.toList());
+ }
+
+
+ /**
+ * Get the list of all challenge for world.
+ *
+ * @param world - the world to check
+ * @return List of challenges
+ */
+ public List getAllChallenges(World world)
+ {
+ String worldName = Util.getWorld(world).getName();
+ // TODO: Probably need to check also database.
+ return this.challengeCacheData.values().stream().
+ sorted(Comparator.comparing(Challenge::getOrder)).
+ filter(challenge -> challenge.getUniqueId().startsWith(worldName)).
+ collect(Collectors.toList());
+ }
+
+
+ /**
+ * Free challenges... Challenges without a level.
+ * @param world World in which challenges must be searched.
+ * @return List with free challenges in given world.
+ */
+ public List getFreeChallenges(World world)
+ {
+ // Free Challenges hides under FREE level.
+ return this.getAllChallenges(world).stream().
+ filter(challenge -> challenge.getLevel().equals(FREE)).
+ collect(Collectors.toList());
+ }
+
+
+ /**
+ * Level which challenges must be received
+ * @param level Challenge level.
+ * @return List with challenges in given level.
+ */
+ public List getLevelChallenges(ChallengeLevel level)
+ {
+ return level.getChallenges().stream().
+ map(this::getChallenge).
+ filter(Objects::nonNull).
+ collect(Collectors.toList());
+ }
+
+
+ /**
+ * Get challenge by name. Case sensitive
+ *
+ * @param name - unique name of challenge
+ * @return - challenge or null if it does not exist
+ */
+ public Challenge getChallenge(String name)
+ {
+ if (this.challengeCacheData.containsKey(name))
+ {
+ return this.challengeCacheData.get(name);
+ }
+ else
+ {
+ // check database.
+ if (this.challengeDatabase.objectExists(name))
+ {
+ Challenge challenge = this.challengeDatabase.loadObject(name);
+ this.challengeCacheData.put(name, challenge);
+ return challenge;
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Check if a challenge exists - case insensitive
+ *
+ * @param name - name of challenge
+ * @return true if it exists, otherwise false
+ */
+ public boolean containsChallenge(String name)
+ {
+ if (this.challengeCacheData.containsKey(name))
+ {
+ return true;
+ }
+ else
+ {
+ // check database.
+ if (this.challengeDatabase.objectExists(name))
+ {
+ Challenge challenge = this.challengeDatabase.loadObject(name);
+ this.challengeCacheData.put(name, challenge);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * This method creates and returns new challenge with given uniqueID.
+ * @param uniqueID - new ID for challenge.
+ * @return Challenge that is currently created.
+ */
+ public Challenge createChallenge(String uniqueID)
+ {
+ if (!this.containsChallenge(uniqueID))
+ {
+ Challenge challenge = new Challenge();
+ challenge.setUniqueId(uniqueID);
+
+ this.saveChallenge(challenge);
+ this.loadChallenge(challenge);
+
+ return challenge;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+ /**
+ * This method removes challenge from cache and memory.
+ * @param challenge that must be removed.
+ */
+ public void deleteChallenge(Challenge challenge)
+ {
+ if (this.challengeCacheData.containsKey(challenge.getUniqueId()))
+ {
+ this.challengeCacheData.remove(challenge.getUniqueId());
+ this.challengeDatabase.deleteObject(challenge);
+ }
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Level related methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method returns list of challenge levels in given world.
+ * @param world for which levels must be searched.
+ * @return List with challenges in given world.
+ */
+ public List getLevels(World world)
+ {
+ String worldName = Util.getWorld(world).getName();
+ // TODO: Probably need to check also database.
+ return this.levelCacheData.values().stream().
+ sorted(ChallengeLevel::compareTo).
+ filter(challenge -> challenge.getUniqueId().startsWith(worldName)).
+ collect(Collectors.toList());
+ }
+
+
+ /**
+ * Get challenge level by its challenge.
+ *
+ * @param challenge - challenge which level must be returned.
+ * @return - challenge level or null if it does not exist
+ */
+ public ChallengeLevel getLevel(Challenge challenge)
+ {
+ if (!challenge.getLevel().equals(FREE))
+ {
+ return this.getLevel(challenge.getLevel());
+ }
+
+ return new ChallengeLevel();
+ }
+
+
+ /**
+ * Get challenge level by name. Case sensitive
+ *
+ * @param name - unique name of challenge level
+ * @return - challenge level or null if it does not exist
+ */
+ public ChallengeLevel getLevel(String name)
+ {
+ if (this.levelCacheData.containsKey(name))
+ {
+ return this.levelCacheData.get(name);
+ }
+ else
+ {
+ // check database.
+ if (this.levelDatabase.objectExists(name))
+ {
+ ChallengeLevel level = this.levelDatabase.loadObject(name);
+ this.levelCacheData.put(name, level);
+ return level;
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Check if a challenge level exists - case insensitive
+ *
+ * @param name - name of challenge level
+ * @return true if it exists, otherwise false
+ */
+ public boolean containsLevel(String name)
+ {
+ if (this.levelCacheData.containsKey(name))
+ {
+ return true;
+ }
+ else
+ {
+ // check database.
+ if (this.levelDatabase.objectExists(name))
+ {
+ ChallengeLevel level = this.levelDatabase.loadObject(name);
+ this.levelCacheData.put(name, level);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * This method adds given challenge to given challenge level.
+ * @param newChallenge Challenge who must change owner.
+ * @param newLevel Level who must add new challenge
+ */
+ public void addChallengeToLevel(Challenge newChallenge, ChallengeLevel newLevel)
+ {
+ if (newChallenge.getLevel().equals(FREE))
+ {
+ newLevel.getChallenges().add(newChallenge.getUniqueId());
+ newChallenge.setLevel(newLevel.getUniqueId());
+
+ this.saveLevel(newLevel);
+ this.saveChallenge(newChallenge);
+ }
+ else
+ {
+ ChallengeLevel oldLevel = this.getLevel(newChallenge.getLevel());
+
+ if (!oldLevel.equals(newLevel))
+ {
+ this.removeChallengeFromLevel(newChallenge, newLevel);
+ newLevel.getChallenges().add(newChallenge.getUniqueId());
+ newChallenge.setLevel(newLevel.getUniqueId());
+
+ this.saveLevel(newLevel);
+ this.saveChallenge(newChallenge);
+ }
+ }
+ }
+
+
+ /**
+ * This method removes given challenge from given challenge level.
+ * @param challenge Challenge which must leave level.
+ * @param level level which lost challenge
+ */
+ public void removeChallengeFromLevel(Challenge challenge, ChallengeLevel level)
+ {
+ if (level.getChallenges().contains(challenge.getUniqueId()))
+ {
+ level.getChallenges().remove(challenge.getUniqueId());
+ challenge.setLevel(FREE);
+ this.saveLevel(level);
+ this.saveChallenge(challenge);
+ }
+ }
+
+
+ /**
+ * This method creates and returns new challenges level with given uniqueID.
+ * @param uniqueID - new ID for challenge level.
+ * @return ChallengeLevel that is currently created.
+ */
+ public ChallengeLevel createLevel(String uniqueID)
+ {
+ if (!this.containsLevel(uniqueID))
+ {
+ ChallengeLevel level = new ChallengeLevel();
+ level.setUniqueId(uniqueID);
+
+ this.saveLevel(level);
+ this.loadLevel(level);
+
+ return level;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+ /**
+ * This method removes challenge level from cache and memory.
+ * @param challengeLevel Level that must be removed.
+ */
+ public void deleteChallengeLevel(ChallengeLevel challengeLevel)
+ {
+ if (this.levelCacheData.containsKey(challengeLevel.getUniqueId()))
+ {
+ this.levelCacheData.remove(challengeLevel.getUniqueId());
+ this.levelDatabase.deleteObject(challengeLevel);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/challenges/ParseItem.java b/src/main/java/world/bentobox/challenges/ParseItem.java
index f3272a4..67fd806 100644
--- a/src/main/java/world/bentobox/challenges/ParseItem.java
+++ b/src/main/java/world/bentobox/challenges/ParseItem.java
@@ -11,7 +11,10 @@ import org.bukkit.potion.PotionType;
* Used for converting config file entries to objects
* @author tastybento
*
+ * @deprecated
+ * @see world.bentobox.bentobox.util.ItemParser#parse(String)
*/
+@Deprecated
public class ParseItem {
private final ItemStack item;
diff --git a/src/main/java/world/bentobox/challenges/Settings.java b/src/main/java/world/bentobox/challenges/Settings.java
new file mode 100644
index 0000000..39c8248
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/Settings.java
@@ -0,0 +1,184 @@
+package world.bentobox.challenges;
+
+
+import java.util.HashSet;
+import java.util.Set;
+
+import world.bentobox.bentobox.api.configuration.ConfigComment;
+import world.bentobox.bentobox.api.configuration.ConfigEntry;
+import world.bentobox.bentobox.api.configuration.StoreAt;
+import world.bentobox.bentobox.database.objects.DataObject;
+
+
+@StoreAt(filename="config.yml", path="addons/Challenges")
+@ConfigComment("Challenges Configuration [version]")
+@ConfigComment("This config file is dynamic and saved when the server is shutdown.")
+@ConfigComment("You cannot edit it while the server is running because changes will")
+@ConfigComment("be lost! Use in-game settings GUI or edit when server is offline.")
+@ConfigComment("")
+public class Settings implements DataObject
+{
+ @ConfigComment("")
+ @ConfigComment("Reset Challenges - if this is true, player's challenges will reset when they")
+ @ConfigComment("reset an island or if they are kicked or leave a team. Prevents exploiting the")
+ @ConfigComment("challenges by doing them repeatedly.")
+ private boolean resetChallenges = true;
+
+ @ConfigComment("")
+ @ConfigComment("Broadcast 1st time challenge completion messages to all players.")
+ @ConfigComment("Change to false if the spam becomes too much.")
+ private boolean broadcastMessages = true;
+
+ @ConfigComment("")
+ @ConfigComment("Remove non-repeatable challenges from the challenge GUI when complete.")
+ private boolean removeCompleteOneTimeChallenges = false;
+
+ @ConfigComment("")
+ @ConfigComment("Add enchanted glow to completed challenges")
+ private boolean addCompletedGlow = true;
+
+ @ConfigComment("")
+ @ConfigComment("This indicate if free challenges must be at the start (true) or at the end (false) of list.")
+ private boolean freeChallengesFirst = true;
+
+ @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:")
+ @ConfigComment("disabled-gamemodes:")
+ @ConfigComment(" - BSkyBlock")
+ @ConfigEntry(path = "disabled-gamemodes")
+ private Set disabledGameModes = new HashSet<>();
+
+ /**
+ * Default variable.
+ */
+ @ConfigComment("")
+ private String uniqueId = "config";
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ @Override
+ public String getUniqueId()
+ {
+ return this.uniqueId;
+ }
+
+
+ /**
+ * @return resetChallenges value.
+ */
+ public boolean isResetChallenges()
+ {
+ return this.resetChallenges;
+ }
+
+
+ /**
+ * @return broadcastMessages value.
+ */
+ public boolean isBroadcastMessages()
+ {
+ return this.broadcastMessages;
+ }
+
+
+ /**
+ * @return removeCompleteOneTimeChallenges value.
+ */
+ public boolean isRemoveCompleteOneTimeChallenges()
+ {
+ return this.removeCompleteOneTimeChallenges;
+ }
+
+
+ /**
+ * @return addCompletedGlow value.
+ */
+ public boolean isAddCompletedGlow()
+ {
+ return this.addCompletedGlow;
+ }
+
+
+ /**
+ * @return disabledGameModes value.
+ */
+ public Set getDisabledGameModes()
+ {
+ return this.disabledGameModes;
+ }
+
+
+ /**
+ * @return freeChallengesFirst value.
+ */
+ public boolean isFreeChallengesFirst()
+ {
+ return this.freeChallengesFirst;
+ }
+
+
+ @Override
+ public void setUniqueId(String uniqueId)
+ {
+ this.uniqueId = uniqueId;
+ }
+
+
+ /**
+ * @param resetChallenges new resetChallenges value.
+ */
+ public void setResetChallenges(boolean resetChallenges)
+ {
+ this.resetChallenges = resetChallenges;
+ }
+
+
+ /**
+ * @param broadcastMessages new broadcastMessages value.
+ */
+ public void setBroadcastMessages(boolean broadcastMessages)
+ {
+ this.broadcastMessages = broadcastMessages;
+ }
+
+
+ /**
+ * @param removeCompleteOneTimeChallenges new removeCompleteOneTimeChallenges value.
+ */
+ public void setRemoveCompleteOneTimeChallenges(boolean removeCompleteOneTimeChallenges)
+ {
+ this.removeCompleteOneTimeChallenges = removeCompleteOneTimeChallenges;
+ }
+
+
+ /**
+ * @param addCompletedGlow new addCompletedGlow value.
+ */
+ public void setAddCompletedGlow(boolean addCompletedGlow)
+ {
+ this.addCompletedGlow = addCompletedGlow;
+ }
+
+
+ /**
+ * @param disabledGameModes new disabledGameModes value.
+ */
+ public void setDisabledGameModes(Set disabledGameModes)
+ {
+ this.disabledGameModes = disabledGameModes;
+ }
+
+
+ /**
+ * @param freeChallengesFirst new freeChallengesFirst value.
+ */
+ public void setFreeChallengesFirst(boolean freeChallengesFirst)
+ {
+ this.freeChallengesFirst = freeChallengesFirst;
+ }
+}
diff --git a/src/main/java/world/bentobox/challenges/commands/ChallengesCommand.java b/src/main/java/world/bentobox/challenges/commands/ChallengesCommand.java
index bb2cc7a..67ddf60 100644
--- a/src/main/java/world/bentobox/challenges/commands/ChallengesCommand.java
+++ b/src/main/java/world/bentobox/challenges/commands/ChallengesCommand.java
@@ -3,10 +3,10 @@ package world.bentobox.challenges.commands;
import java.util.List;
import world.bentobox.challenges.ChallengesAddon;
-import world.bentobox.challenges.panel.ChallengesPanels2;
-import world.bentobox.challenges.panel.ChallengesPanels2.Mode;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
+import world.bentobox.challenges.panel.user.ChallengesGUI;
+
public class ChallengesCommand extends CompositeCommand {
public static final String CHALLENGE_COMMAND = "challenges";
@@ -19,7 +19,11 @@ public class ChallengesCommand extends CompositeCommand {
public boolean execute(User user, String label, List args) {
// Open up the challenges GUI
if (user.isPlayer()) {
- new ChallengesPanels2((ChallengesAddon) getAddon(), user, user, args.isEmpty() ? "" : args.get(0), getWorld(), getPermissionPrefix(), getTopLabel(), Mode.PLAYER);
+ new ChallengesGUI((ChallengesAddon) this.getAddon(),
+ this.getWorld(),
+ user,
+ this.getTopLabel(),
+ this.getPermissionPrefix()).build();
return true;
}
// Show help
diff --git a/src/main/java/world/bentobox/challenges/commands/admin/Challenges.java b/src/main/java/world/bentobox/challenges/commands/admin/Challenges.java
index 1115ff7..a73a127 100644
--- a/src/main/java/world/bentobox/challenges/commands/admin/Challenges.java
+++ b/src/main/java/world/bentobox/challenges/commands/admin/Challenges.java
@@ -3,10 +3,10 @@ package world.bentobox.challenges.commands.admin;
import java.util.List;
import world.bentobox.challenges.ChallengesAddon;
-import world.bentobox.challenges.panel.ChallengesPanels2;
-import world.bentobox.challenges.panel.ChallengesPanels2.Mode;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
+import world.bentobox.challenges.panel.admin.AdminGUI;
+
public class Challenges extends CompositeCommand {
@@ -25,7 +25,7 @@ public class Challenges extends CompositeCommand {
this.setDescription("challenges.admin.description");
// Register sub commands
new ImportCommand(getAddon(), this);
- new CompleteChallenge(getAddon(), this);
+ // new CompleteChallenge(getAddon(), this);
new ReloadChallenges(getAddon(), this);
new ResetChallenge(getAddon(), this);
//new ShowChallenges(getAddon(), this);
@@ -37,7 +37,12 @@ public class Challenges extends CompositeCommand {
public boolean execute(User user, String label, List args) {
// Open up the admin challenges GUI
if (user.isPlayer()) {
- new ChallengesPanels2((ChallengesAddon) getAddon(), user, user, args.isEmpty() ? "" : args.get(0), getWorld(), getPermissionPrefix(), getTopLabel(), Mode.ADMIN);
+ new AdminGUI((ChallengesAddon) this.getAddon(),
+ this.getWorld(),
+ user,
+ this.getTopLabel(),
+ this.getPermissionPrefix()).build();
+
return true;
}
return false;
diff --git a/src/main/java/world/bentobox/challenges/commands/admin/CompleteChallenge.java b/src/main/java/world/bentobox/challenges/commands/admin/CompleteChallenge.java
index 486662a..1a156fe 100644
--- a/src/main/java/world/bentobox/challenges/commands/admin/CompleteChallenge.java
+++ b/src/main/java/world/bentobox/challenges/commands/admin/CompleteChallenge.java
@@ -51,13 +51,13 @@ public class CompleteChallenge extends CompositeCommand {
return false;
}
// Check for valid challenge name
- if (!manager.isChallenge(getWorld(), args.get(1))) {
+ if (!manager.containsChallenge(args.get(1))) {
user.sendMessage("challenges.admin.complete.unknown-challenge");
return false;
}
// Complete challenge
User target = User.getInstance(targetUUID);
- manager.setChallengeComplete(target, args.get(1), getWorld());
+ manager.setChallengeComplete(target, this.manager.getChallenge(args.get(1)));
user.sendMessage("general.success");
return true;
}
@@ -70,7 +70,7 @@ public class CompleteChallenge extends CompositeCommand {
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.getAllChallengesList(getWorld()), lastArg));
+ return Optional.of(Util.tabLimit(manager.getAllChallengesNames(getWorld()), lastArg));
}
return Optional.empty();
}
diff --git a/src/main/java/world/bentobox/challenges/commands/admin/CreateChallenge.java b/src/main/java/world/bentobox/challenges/commands/admin/CreateChallenge.java
index 2024ccc..4d3f69d 100644
--- a/src/main/java/world/bentobox/challenges/commands/admin/CreateChallenge.java
+++ b/src/main/java/world/bentobox/challenges/commands/admin/CreateChallenge.java
@@ -9,6 +9,11 @@ import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.user.User;
+
+/**
+ * @deprecated Challenges can be creaded via GUI.
+ */
+@Deprecated
public class CreateChallenge extends CompositeCommand {
/**
diff --git a/src/main/java/world/bentobox/challenges/commands/admin/CreateSurrounding.java b/src/main/java/world/bentobox/challenges/commands/admin/CreateSurrounding.java
index e55c6d3..3ce860a 100644
--- a/src/main/java/world/bentobox/challenges/commands/admin/CreateSurrounding.java
+++ b/src/main/java/world/bentobox/challenges/commands/admin/CreateSurrounding.java
@@ -25,8 +25,9 @@ import world.bentobox.bentobox.util.Util;
/**
* Command to create a surrounding type challenge
* @author tastybento
- *
+ * @deprecated Required blocks can be added via GUI. Not necessary.
*/
+@Deprecated
public class CreateSurrounding extends CompositeCommand implements Listener {
HashMap inProgress = new HashMap<>();
diff --git a/src/main/java/world/bentobox/challenges/commands/admin/ResetChallenge.java b/src/main/java/world/bentobox/challenges/commands/admin/ResetChallenge.java
index a644015..5e762d5 100644
--- a/src/main/java/world/bentobox/challenges/commands/admin/ResetChallenge.java
+++ b/src/main/java/world/bentobox/challenges/commands/admin/ResetChallenge.java
@@ -13,6 +13,11 @@ 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;
@@ -51,13 +56,13 @@ public class ResetChallenge extends CompositeCommand {
return false;
}
// Check for valid challenge name
- if (!manager.isChallenge(getWorld(), args.get(1))) {
+ if (!manager.containsChallenge(args.get(1))) {
user.sendMessage("challenges.admin.complete.unknown-challenge");
return false;
}
// Complete challenge
User target = User.getInstance(targetUUID);
- manager.setResetChallenge(target, args.get(1), getWorld());
+ manager.resetChallenge(target, manager.getChallenge(args.get(1)));
user.sendMessage("general.success");
return true;
}
@@ -70,7 +75,7 @@ public class ResetChallenge extends CompositeCommand {
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.getAllChallengesList(getWorld()), lastArg));
+ return Optional.of(Util.tabLimit(manager.getAllChallengesNames(getWorld()), lastArg));
}
return Optional.empty();
}
diff --git a/src/main/java/world/bentobox/challenges/commands/admin/ShowChallenges.java b/src/main/java/world/bentobox/challenges/commands/admin/ShowChallenges.java
index 8842647..97eb1bb 100644
--- a/src/main/java/world/bentobox/challenges/commands/admin/ShowChallenges.java
+++ b/src/main/java/world/bentobox/challenges/commands/admin/ShowChallenges.java
@@ -28,7 +28,7 @@ public class ShowChallenges extends CompositeCommand {
@Override
public boolean execute(User user, String label, List args) {
- ((ChallengesAddon)getAddon()).getChallengesManager().getAllChallengesList().forEach(user::sendRawMessage);
+ ((ChallengesAddon)getAddon()).getChallengesManager().getAllChallengesNames(this.getWorld()).forEach(user::sendRawMessage);
return true;
}
diff --git a/src/main/java/world/bentobox/challenges/commands/admin/SurroundChallengeBuilder.java b/src/main/java/world/bentobox/challenges/commands/admin/SurroundChallengeBuilder.java
index 5ff9bce..037b0af 100644
--- a/src/main/java/world/bentobox/challenges/commands/admin/SurroundChallengeBuilder.java
+++ b/src/main/java/world/bentobox/challenges/commands/admin/SurroundChallengeBuilder.java
@@ -12,8 +12,9 @@ import world.bentobox.bentobox.api.user.User;
/**
* Enables the state of a Surrounding Challenge to be stored as it is built
* @author tastybento
- *
+ * @deprecated Levels and challenges can be created via GUI. Not necessary command.
*/
+@Deprecated
public class SurroundChallengeBuilder {
private ChallengesAddon addon;
private String name;
@@ -76,7 +77,7 @@ public class SurroundChallengeBuilder {
}
public boolean build() {
- return addon.getChallengesManager().createSurroundingChallenge(this);
+ return false; //addon.getChallengesManager().createSurroundingChallenge(this);
}
diff --git a/src/main/java/world/bentobox/challenges/database/object/Challenge.java b/src/main/java/world/bentobox/challenges/database/object/Challenge.java
new file mode 100644
index 0000000..6d73716
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/database/object/Challenge.java
@@ -0,0 +1,1021 @@
+package world.bentobox.challenges.database.object;
+
+
+import com.google.gson.annotations.Expose;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.entity.EntityType;
+import org.bukkit.inventory.ItemStack;
+import java.util.*;
+
+import world.bentobox.bentobox.api.configuration.ConfigComment;
+import world.bentobox.bentobox.database.objects.DataObject;
+
+
+/**
+ * Data object for challenges
+ * @author tastybento
+ *
+ */
+public class Challenge implements DataObject
+{
+ /**
+ * Empty constructor
+ */
+ public Challenge()
+ {
+ }
+
+
+ /**
+ * This enum holds all Challenge Types.
+ */
+ public enum ChallengeType
+ {
+ /**
+ * The player must have the items on them.
+ */
+ INVENTORY,
+
+ /**
+ * Items or required entities have to be within x blocks of the player.
+ */
+ ISLAND,
+
+ /**
+ * Other type, like required money / experience or island level. This my request
+ * other plugins to be setup before it could work.
+ */
+ OTHER,
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ @ConfigComment("")
+ @ConfigComment("Unique name of the challenge")
+ @Expose
+ private String uniqueId = "";
+
+ @ConfigComment("")
+ @ConfigComment("The name of the challenge. May include color codes. Single line.")
+ @Expose
+ private String friendlyName = "";
+
+ @ConfigComment("")
+ @ConfigComment("Whether this challenge is deployed or not.")
+ @Expose
+ private boolean deployed;
+
+ @ConfigComment("")
+ @ConfigComment("Description of the challenge. Will become the lore on the icon. Can ")
+ @ConfigComment("include & color codes. String List.")
+ @Expose
+ private List description = new ArrayList<>();
+
+ @ConfigComment("")
+ @ConfigComment("The icon in the GUI for this challenge. ItemStack.")
+ @Expose
+ private ItemStack icon = new ItemStack(Material.PAPER);
+
+ @ConfigComment("")
+ @ConfigComment("Order of this challenge. It allows define order for challenges in")
+ @ConfigComment("single level. If order for challenges are equal, it will order by")
+ @ConfigComment("challenge unique id.")
+ @Expose
+ private int order = -1;
+
+ @ConfigComment("")
+ @ConfigComment("Challenge type can be INVENTORY, OTHER or ISLAND.")
+ @Expose
+ private ChallengeType challengeType = ChallengeType.INVENTORY;
+
+ @ConfigComment("")
+ @ConfigComment("List of environments where this challenge will occur: NETHER, NORMAL,")
+ @ConfigComment("THE_END. Leave blank for all.")
+ @Expose
+ private Set environment = new HashSet<>();
+
+ @ConfigComment("")
+ @ConfigComment("If true, the challenge will disappear from the GUI when completed")
+ @Expose
+ private boolean removeWhenCompleted;
+
+ @ConfigComment("")
+ @ConfigComment("Unique challenge ID. Empty means that challenge is in free challenge list.")
+ @Expose
+ private String level = "";
+
+// ---------------------------------------------------------------------
+// Section: Requirement related
+// ---------------------------------------------------------------------
+
+ @ConfigComment("")
+ @ConfigComment("")
+ @ConfigComment("The required permissions to see this challenge. String list.")
+ @Expose
+ private Set requiredPermissions = new HashSet<>();
+
+ @ConfigComment("")
+ @ConfigComment("This is a map of the blocks required in a ISLAND challenge. Material,")
+ @ConfigComment("Integer")
+ @Expose
+ private Map requiredBlocks = new EnumMap<>(Material.class);
+
+ @ConfigComment("")
+ @ConfigComment("Remove the required blocks from the island")
+ @Expose
+ private boolean removeBlocks;
+
+ @ConfigComment("")
+ @ConfigComment("Any entities that must be in the area for ISLAND type challenges. ")
+ @ConfigComment("Map EntityType, Number")
+ @Expose
+ private Map requiredEntities = new EnumMap<>(EntityType.class);
+
+ @ConfigComment("")
+ @ConfigComment("Remove the entities from the island")
+ @Expose
+ private boolean removeEntities;
+
+ @ConfigComment("")
+ @ConfigComment("The items that must be in the inventory to complete the challenge. ")
+ @ConfigComment("ItemStack List.")
+ @Expose
+ private List requiredItems = new ArrayList<>();
+
+ @ConfigComment("")
+ @ConfigComment("Take the required items from the player")
+ @Expose
+ private boolean takeItems = true;
+
+ @ConfigComment("")
+ @ConfigComment("Required experience for challenge completion.")
+ @Expose
+ private int requiredExperience = 0;
+
+ @ConfigComment("")
+ @ConfigComment("Take the experience from the player")
+ @Expose
+ private boolean takeExperience;
+
+ @ConfigComment("")
+ @ConfigComment("Required money for challenge completion. Economy plugins or addons")
+ @ConfigComment("is required for this option.")
+ @Expose
+ private int requiredMoney = 0;
+
+ @ConfigComment("")
+ @ConfigComment("Take the money from the player")
+ @Expose
+ private boolean takeMoney;
+
+ @ConfigComment("")
+ @ConfigComment("Required island level for challenge completion. Plugin or Addon that")
+ @ConfigComment("calculates island level is required for this option.")
+ @Expose
+ private long requiredIslandLevel;
+
+ @ConfigComment("")
+ @ConfigComment("The number of blocks around the player to search for items on an island")
+ @Expose
+ private int searchRadius = 10;
+
+
+// ---------------------------------------------------------------------
+// Section: Rewards
+// ---------------------------------------------------------------------
+
+ @ConfigComment("")
+ @ConfigComment("")
+ @ConfigComment("If this is blank, the reward text will be auto-generated, otherwise")
+ @ConfigComment("this will be used.")
+ @Expose
+ private String rewardText = "";
+
+
+ @ConfigComment("")
+ @ConfigComment("List of items the player will receive first time. ItemStack List.")
+ @Expose
+ private List rewardItems = new ArrayList<>();
+
+ @ConfigComment("")
+ @ConfigComment("Experience point reward")
+ @Expose
+ private int rewardExperience = 0;
+
+ @ConfigComment("")
+ @ConfigComment("Money reward. Economy plugin or addon required for this option.")
+ @Expose
+ private int rewardMoney = 0;
+
+ @ConfigComment("")
+ @ConfigComment("Commands to run when the player completes the challenge for the first")
+ @ConfigComment("time. String List")
+ @Expose
+ private List rewardCommands = new ArrayList<>();
+
+
+// ---------------------------------------------------------------------
+// Section: Repeat Rewards
+// ---------------------------------------------------------------------
+
+
+ @ConfigComment("")
+ @ConfigComment("")
+ @ConfigComment("True if the challenge is repeatable")
+ @Expose
+ private boolean repeatable;
+
+ @ConfigComment("")
+ @ConfigComment("Description of the repeat rewards. If blank, it will be autogenerated.")
+ @Expose
+ private String repeatRewardText = "";
+
+ @ConfigComment("")
+ @ConfigComment("Maximum number of times the challenge can be repeated. 0 or less")
+ @ConfigComment("will mean infinite times.")
+ @Expose
+ private int maxTimes = 1;
+
+ @ConfigComment("")
+ @ConfigComment("Repeat experience reward")
+ @Expose
+ private int repeatExperienceReward = 0;
+
+ @ConfigComment("")
+ @ConfigComment("Reward items for repeating the challenge. List of ItemStacks.")
+ @Expose
+ private List repeatItemReward = new ArrayList<>();
+
+ @ConfigComment("")
+ @ConfigComment("Repeat money reward. Economy plugin or addon required for this option.")
+ @Expose
+ private int repeatMoneyReward;
+
+ @ConfigComment("")
+ @ConfigComment("Commands to run when challenge is repeated. String List.")
+ @Expose
+ private List repeatRewardCommands = new ArrayList<>();
+
+
+// ---------------------------------------------------------------------
+// Section: Getters
+// ---------------------------------------------------------------------
+
+
+ /**
+ * @return the uniqueId
+ */
+ @Override
+ public String getUniqueId()
+ {
+ return uniqueId;
+ }
+
+
+ /**
+ * @return the friendlyName
+ */
+ public String getFriendlyName()
+ {
+ return friendlyName;
+ }
+
+
+ /**
+ * @return the deployed
+ */
+ public boolean isDeployed()
+ {
+ return deployed;
+ }
+
+
+ /**
+ * @return the description
+ */
+ public List getDescription()
+ {
+ return description;
+ }
+
+
+ /**
+ * @return the icon
+ */
+ public ItemStack getIcon()
+ {
+ return icon.clone();
+ }
+
+
+ /**
+ * @return the order
+ */
+ public int getOrder()
+ {
+ return order;
+ }
+
+
+ /**
+ * @return the challengeType
+ */
+ public ChallengeType getChallengeType()
+ {
+ return challengeType;
+ }
+
+
+ /**
+ * @return the environment
+ */
+ public Set getEnvironment()
+ {
+ return environment;
+ }
+
+
+ /**
+ * @return the level
+ */
+ public String getLevel()
+ {
+ return level;
+ }
+
+
+ /**
+ * @return the removeWhenCompleted
+ */
+ public boolean isRemoveWhenCompleted()
+ {
+ return removeWhenCompleted;
+ }
+
+
+ /**
+ * @return the requiredPermissions
+ */
+ public Set getRequiredPermissions()
+ {
+ return requiredPermissions;
+ }
+
+
+ /**
+ * @return the requiredBlocks
+ */
+ public Map getRequiredBlocks()
+ {
+ return requiredBlocks;
+ }
+
+
+ /**
+ * @return the removeBlocks
+ */
+ public boolean isRemoveBlocks()
+ {
+ return removeBlocks;
+ }
+
+
+ /**
+ * @return the requiredEntities
+ */
+ public Map getRequiredEntities()
+ {
+ return requiredEntities;
+ }
+
+
+ /**
+ * @return the removeEntities
+ */
+ public boolean isRemoveEntities()
+ {
+ return removeEntities;
+ }
+
+
+ /**
+ * @return the requiredItems
+ */
+ public List getRequiredItems()
+ {
+ return requiredItems;
+ }
+
+
+ /**
+ * @return the takeItems
+ */
+ public boolean isTakeItems()
+ {
+ return takeItems;
+ }
+
+
+ /**
+ * @return the requiredExperience
+ */
+ public int getRequiredExperience()
+ {
+ return requiredExperience;
+ }
+
+
+ /**
+ * @return the takeExperience
+ */
+ public boolean isTakeExperience()
+ {
+ return takeExperience;
+ }
+
+
+ /**
+ * @return the requiredMoney
+ */
+ public int getRequiredMoney()
+ {
+ return requiredMoney;
+ }
+
+
+ /**
+ * @return the takeMoney
+ */
+ public boolean isTakeMoney()
+ {
+ return takeMoney;
+ }
+
+
+ /**
+ * @return the requiredIslandLevel
+ */
+ public long getRequiredIslandLevel()
+ {
+ return requiredIslandLevel;
+ }
+
+
+ /**
+ * @return the searchRadius
+ */
+ public int getSearchRadius()
+ {
+ return searchRadius;
+ }
+
+
+ /**
+ * @return the rewardText
+ */
+ public String getRewardText()
+ {
+ return rewardText;
+ }
+
+
+ /**
+ * @return the rewardItems
+ */
+ public List getRewardItems()
+ {
+ return rewardItems;
+ }
+
+
+ /**
+ * @return the rewardExperience
+ */
+ public int getRewardExperience()
+ {
+ return rewardExperience;
+ }
+
+
+ /**
+ * @return the rewardMoney
+ */
+ public int getRewardMoney()
+ {
+ return rewardMoney;
+ }
+
+
+ /**
+ * @return the rewardCommands
+ */
+ public List getRewardCommands()
+ {
+ return rewardCommands;
+ }
+
+
+ /**
+ * @return the repeatable
+ */
+ public boolean isRepeatable()
+ {
+ return repeatable;
+ }
+
+
+ /**
+ * @return the repeatRewardText
+ */
+ public String getRepeatRewardText()
+ {
+ return repeatRewardText;
+ }
+
+
+ /**
+ * @return the maxTimes
+ */
+ public int getMaxTimes()
+ {
+ return maxTimes;
+ }
+
+
+ /**
+ * @return the repeatExperienceReward
+ */
+ public int getRepeatExperienceReward()
+ {
+ return repeatExperienceReward;
+ }
+
+
+ /**
+ * @return the repeatItemReward
+ */
+ public List getRepeatItemReward()
+ {
+ return repeatItemReward;
+ }
+
+
+ /**
+ * @return the repeatMoneyReward
+ */
+ public int getRepeatMoneyReward()
+ {
+ return repeatMoneyReward;
+ }
+
+
+ /**
+ * @return the repeatRewardCommands
+ */
+ public List getRepeatRewardCommands()
+ {
+ return repeatRewardCommands;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Setters
+// ---------------------------------------------------------------------
+
+
+ /**
+ * @param uniqueId the uniqueId to set
+ */
+ @Override
+ public void setUniqueId(String uniqueId)
+ {
+ this.uniqueId = uniqueId;
+ }
+
+
+ /**
+ * This method sets the friendlyName value.
+ * @param friendlyName the friendlyName new value.
+ *
+ */
+ public void setFriendlyName(String friendlyName)
+ {
+ this.friendlyName = friendlyName;
+ }
+
+
+ /**
+ * This method sets the deployed value.
+ * @param deployed the deployed new value.
+ *
+ */
+ public void setDeployed(boolean deployed)
+ {
+ this.deployed = deployed;
+ }
+
+
+ /**
+ * This method sets the description value.
+ * @param description the description new value.
+ *
+ */
+ public void setDescription(List description)
+ {
+ this.description = description;
+ }
+
+
+ /**
+ * This method sets the icon value.
+ * @param icon the icon new value.
+ *
+ */
+ public void setIcon(ItemStack icon)
+ {
+ this.icon = icon;
+ }
+
+
+ /**
+ * This method sets the order value.
+ * @param order the order new value.
+ *
+ */
+ public void setOrder(int order)
+ {
+ this.order = order;
+ }
+
+
+ /**
+ * This method sets the challengeType value.
+ * @param challengeType the challengeType new value.
+ *
+ */
+ public void setChallengeType(ChallengeType challengeType)
+ {
+ this.challengeType = challengeType;
+ }
+
+
+ /**
+ * This method sets the environment value.
+ * @param environment the environment new value.
+ *
+ */
+ public void setEnvironment(Set environment)
+ {
+ this.environment = environment;
+ }
+
+
+ /**
+ * This method sets the level value.
+ * @param level the level new value.
+ */
+ public void setLevel(String level)
+ {
+ this.level = level;
+ }
+
+
+ /**
+ * This method sets the removeWhenCompleted value.
+ * @param removeWhenCompleted the removeWhenCompleted new value.
+ *
+ */
+ public void setRemoveWhenCompleted(boolean removeWhenCompleted)
+ {
+ this.removeWhenCompleted = removeWhenCompleted;
+ }
+
+
+ /**
+ * This method sets the requiredPermissions value.
+ * @param requiredPermissions the requiredPermissions new value.
+ *
+ */
+ public void setRequiredPermissions(Set requiredPermissions)
+ {
+ this.requiredPermissions = requiredPermissions;
+ }
+
+
+ /**
+ * This method sets the requiredBlocks value.
+ * @param requiredBlocks the requiredBlocks new value.
+ *
+ */
+ public void setRequiredBlocks(Map requiredBlocks)
+ {
+ this.requiredBlocks = requiredBlocks;
+ }
+
+
+ /**
+ * This method sets the removeBlocks value.
+ * @param removeBlocks the removeBlocks new value.
+ *
+ */
+ public void setRemoveBlocks(boolean removeBlocks)
+ {
+ this.removeBlocks = removeBlocks;
+ }
+
+
+ /**
+ * This method sets the requiredEntities value.
+ * @param requiredEntities the requiredEntities new value.
+ *
+ */
+ public void setRequiredEntities(Map requiredEntities)
+ {
+ this.requiredEntities = requiredEntities;
+ }
+
+
+ /**
+ * This method sets the removeEntities value.
+ * @param removeEntities the removeEntities new value.
+ *
+ */
+ public void setRemoveEntities(boolean removeEntities)
+ {
+ this.removeEntities = removeEntities;
+ }
+
+
+ /**
+ * This method sets the requiredItems value.
+ * @param requiredItems the requiredItems new value.
+ *
+ */
+ public void setRequiredItems(List requiredItems)
+ {
+ this.requiredItems = requiredItems;
+ }
+
+
+ /**
+ * This method sets the takeItems value.
+ * @param takeItems the takeItems new value.
+ *
+ */
+ public void setTakeItems(boolean takeItems)
+ {
+ this.takeItems = takeItems;
+ }
+
+
+ /**
+ * This method sets the requiredExperience value.
+ * @param requiredExperience the requiredExperience new value.
+ *
+ */
+ public void setRequiredExperience(int requiredExperience)
+ {
+ this.requiredExperience = requiredExperience;
+ }
+
+
+ /**
+ * This method sets the takeExperience value.
+ * @param takeExperience the takeExperience new value.
+ *
+ */
+ public void setTakeExperience(boolean takeExperience)
+ {
+ this.takeExperience = takeExperience;
+ }
+
+
+ /**
+ * This method sets the requiredMoney value.
+ * @param requiredMoney the requiredMoney new value.
+ *
+ */
+ public void setRequiredMoney(int requiredMoney)
+ {
+ this.requiredMoney = requiredMoney;
+ }
+
+
+ /**
+ * This method sets the takeMoney value.
+ * @param takeMoney the takeMoney new value.
+ *
+ */
+ public void setTakeMoney(boolean takeMoney)
+ {
+ this.takeMoney = takeMoney;
+ }
+
+
+ /**
+ * This method sets the requiredIslandLevel value.
+ * @param requiredIslandLevel the requiredIslandLevel new value.
+ *
+ */
+ public void setRequiredIslandLevel(long requiredIslandLevel)
+ {
+ this.requiredIslandLevel = requiredIslandLevel;
+ }
+
+
+ /**
+ * This method sets the searchRadius value.
+ * @param searchRadius the searchRadius new value.
+ *
+ */
+ public void setSearchRadius(int searchRadius)
+ {
+ this.searchRadius = searchRadius;
+ }
+
+
+ /**
+ * This method sets the rewardText value.
+ * @param rewardText the rewardText new value.
+ *
+ */
+ public void setRewardText(String rewardText)
+ {
+ this.rewardText = rewardText;
+ }
+
+
+ /**
+ * This method sets the rewardItems value.
+ * @param rewardItems the rewardItems new value.
+ *
+ */
+ public void setRewardItems(List rewardItems)
+ {
+ this.rewardItems = rewardItems;
+ }
+
+
+ /**
+ * This method sets the rewardExperience value.
+ * @param rewardExperience the rewardExperience new value.
+ *
+ */
+ public void setRewardExperience(int rewardExperience)
+ {
+ this.rewardExperience = rewardExperience;
+ }
+
+
+ /**
+ * This method sets the rewardMoney value.
+ * @param rewardMoney the rewardMoney new value.
+ *
+ */
+ public void setRewardMoney(int rewardMoney)
+ {
+ this.rewardMoney = rewardMoney;
+ }
+
+
+ /**
+ * This method sets the rewardCommands value.
+ * @param rewardCommands the rewardCommands new value.
+ *
+ */
+ public void setRewardCommands(List rewardCommands)
+ {
+ this.rewardCommands = rewardCommands;
+ }
+
+
+ /**
+ * This method sets the repeatable value.
+ * @param repeatable the repeatable new value.
+ *
+ */
+ public void setRepeatable(boolean repeatable)
+ {
+ this.repeatable = repeatable;
+ }
+
+
+ /**
+ * This method sets the repeatRewardText value.
+ * @param repeatRewardText the repeatRewardText new value.
+ *
+ */
+ public void setRepeatRewardText(String repeatRewardText)
+ {
+ this.repeatRewardText = repeatRewardText;
+ }
+
+
+ /**
+ * This method sets the maxTimes value.
+ * @param maxTimes the maxTimes new value.
+ *
+ */
+ public void setMaxTimes(int maxTimes)
+ {
+ this.maxTimes = maxTimes;
+ }
+
+
+ /**
+ * This method sets the repeatExperienceReward value.
+ * @param repeatExperienceReward the repeatExperienceReward new value.
+ *
+ */
+ public void setRepeatExperienceReward(int repeatExperienceReward)
+ {
+ this.repeatExperienceReward = repeatExperienceReward;
+ }
+
+
+ /**
+ * This method sets the repeatItemReward value.
+ * @param repeatItemReward the repeatItemReward new value.
+ *
+ */
+ public void setRepeatItemReward(List repeatItemReward)
+ {
+ this.repeatItemReward = repeatItemReward;
+ }
+
+
+ /**
+ * This method sets the repeatMoneyReward value.
+ * @param repeatMoneyReward the repeatMoneyReward new value.
+ *
+ */
+ public void setRepeatMoneyReward(int repeatMoneyReward)
+ {
+ this.repeatMoneyReward = repeatMoneyReward;
+ }
+
+
+ /**
+ * This method sets the repeatRewardCommands value.
+ * @param repeatRewardCommands the repeatRewardCommands new value.
+ *
+ */
+ public void setRepeatRewardCommands(List repeatRewardCommands)
+ {
+ this.repeatRewardCommands = repeatRewardCommands;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Other methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * @see java.lang.Object#hashCode()
+ * @return int
+ */
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode());
+ return result;
+ }
+
+
+ /**
+ * @see java.lang.Object#equals(Object) ()
+ * @param obj of type Object
+ * @return boolean
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof Challenge))
+ {
+ return false;
+ }
+
+ Challenge other = (Challenge) obj;
+
+ if (uniqueId == null)
+ {
+ return other.uniqueId == null;
+ }
+ else
+ {
+ return uniqueId.equals(other.uniqueId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java b/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java
new file mode 100644
index 0000000..de4c71b
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java
@@ -0,0 +1,472 @@
+package world.bentobox.challenges.database.object;
+
+
+import com.google.gson.annotations.Expose;
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import world.bentobox.bentobox.api.configuration.ConfigComment;
+import world.bentobox.bentobox.database.objects.DataObject;
+import world.bentobox.challenges.ChallengesManager;
+
+/**
+ * Represent a challenge level
+ * @author tastybento
+ *
+ */
+public class ChallengeLevel implements DataObject, Comparable
+{
+ /**
+ * Constructor ChallengeLevel creates a new ChallengeLevel instance.
+ */
+ public ChallengeLevel()
+ {
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ @ConfigComment("")
+ @ConfigComment("Level name")
+ @Expose
+ private String uniqueId = ChallengesManager.FREE;
+
+ @ConfigComment("")
+ @ConfigComment("A friendly name for the level. If blank, level name is used.")
+ @Expose
+ private String friendlyName = "";
+
+ @ConfigComment("")
+ @ConfigComment("ItemStack that represents current level. Will be used as icon in GUIs.")
+ @Expose
+ private ItemStack icon = new ItemStack(Material.BOOK);
+
+ @ConfigComment("")
+ @ConfigComment("World that this level applies in. String.")
+ @Expose
+ private String world = "";
+
+ @ConfigComment("")
+ @ConfigComment("The ordering of the level, lowest to highest")
+ @Expose
+ private int order;
+
+ @ConfigComment("")
+ @ConfigComment("The number of undone challenges that can be left on this level before")
+ @ConfigComment("unlocking next level.")
+ @Expose
+ private int waiverAmount = 1;
+
+ @ConfigComment("")
+ @ConfigComment("The message shown when unlocking this level. Single line string.")
+ @Expose
+ private String unlockMessage = "";
+
+ @ConfigComment("")
+ @ConfigComment("")
+ @ConfigComment("If this is blank, the reward text will be auto-generated, otherwise")
+ @ConfigComment("this will be used.")
+ @Expose
+ private String rewardText = "";
+
+
+ @ConfigComment("")
+ @ConfigComment("List of items the player will receive on completing level.")
+ @ConfigComment("ItemStack List.")
+ @Expose
+ private List rewardItems = new ArrayList<>();
+
+ @ConfigComment("")
+ @ConfigComment("Experience point reward on completing level.")
+ @Expose
+ private int rewardExperience = 0;
+
+ @ConfigComment("")
+ @ConfigComment("Money reward. Economy plugin or addon required for this option.")
+ @Expose
+ private int rewardMoney = 0;
+
+ @ConfigComment("")
+ @ConfigComment("Commands to run when the player completes all challenges in current")
+ @ConfigComment("level. String List")
+ @Expose
+ private List rewardCommands = new ArrayList<>();
+
+ @ConfigComment("")
+ @ConfigComment("Set of all challenges that is linked with current level.")
+ @ConfigComment("String Set")
+ @Expose
+ private Set challenges = new HashSet<>();
+
+
+// ---------------------------------------------------------------------
+// Section: Getters
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method returns the uniqueId value.
+ * @return the value of uniqueId.
+ * @see DataObject#getUniqueId()
+ */
+ @Override
+ public String getUniqueId()
+ {
+ return uniqueId;
+ }
+
+
+ /**
+ * This method returns the friendlyName value.
+ * @return the value of friendlyName.
+ */
+ public String getFriendlyName()
+ {
+ return friendlyName;
+ }
+
+
+ /**
+ * This method returns the icon value.
+ * @return the value of icon.
+ */
+ public ItemStack getIcon()
+ {
+ return icon.clone();
+ }
+
+
+ /**
+ * This method returns the world value.
+ * @return the value of world.
+ */
+ public String getWorld()
+ {
+ return world;
+ }
+
+
+ /**
+ * This method returns the order value.
+ * @return the value of order.
+ */
+ public int getOrder()
+ {
+ return order;
+ }
+
+
+ /**
+ * This method returns the waiverAmount value.
+ * @return the value of waiverAmount.
+ */
+ public int getWaiverAmount()
+ {
+ return waiverAmount;
+ }
+
+
+ /**
+ * This method returns the unlockMessage value.
+ * @return the value of unlockMessage.
+ */
+ public String getUnlockMessage()
+ {
+ return unlockMessage;
+ }
+
+
+ /**
+ * This method returns the rewardText value.
+ * @return the value of rewardText.
+ */
+ public String getRewardText()
+ {
+ return rewardText;
+ }
+
+
+ /**
+ * This method returns the rewardItems value.
+ * @return the value of rewardItems.
+ */
+ public List getRewardItems()
+ {
+ return rewardItems;
+ }
+
+
+ /**
+ * This method returns the rewardExperience value.
+ * @return the value of rewardExperience.
+ */
+ public int getRewardExperience()
+ {
+ return rewardExperience;
+ }
+
+
+ /**
+ * This method returns the rewardMoney value.
+ * @return the value of rewardMoney.
+ */
+ public int getRewardMoney()
+ {
+ return rewardMoney;
+ }
+
+
+ /**
+ * This method returns the rewardCommands value.
+ * @return the value of rewardCommands.
+ */
+ public List getRewardCommands()
+ {
+ return rewardCommands;
+ }
+
+
+ /**
+ * This method returns the challenges value.
+ * @return the value of challenges.
+ */
+ public Set getChallenges()
+ {
+ return challenges;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Setters
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method sets the uniqueId value.
+ * @param uniqueId the uniqueId new value.
+ *
+ * @see DataObject#setUniqueId(String)
+ */
+ @Override
+ public void setUniqueId(String uniqueId)
+ {
+ this.uniqueId = uniqueId;
+ }
+
+
+ /**
+ * This method sets the friendlyName value.
+ * @param friendlyName the friendlyName new value.
+ *
+ */
+ public void setFriendlyName(String friendlyName)
+ {
+ this.friendlyName = friendlyName;
+ }
+
+
+ /**
+ * This method sets the icon value.
+ * @param icon the icon new value.
+ *
+ */
+ public void setIcon(ItemStack icon)
+ {
+ this.icon = icon;
+ }
+
+
+ /**
+ * This method sets the world value.
+ * @param world the world new value.
+ *
+ */
+ public void setWorld(String world)
+ {
+ this.world = world;
+ }
+
+
+ /**
+ * This method sets the order value.
+ * @param order the order new value.
+ *
+ */
+ public void setOrder(int order)
+ {
+ this.order = order;
+ }
+
+
+ /**
+ * This method sets the waiverAmount value.
+ * @param waiverAmount the waiverAmount new value.
+ *
+ */
+ public void setWaiverAmount(int waiverAmount)
+ {
+ this.waiverAmount = waiverAmount;
+ }
+
+
+ /**
+ * This method sets the unlockMessage value.
+ * @param unlockMessage the unlockMessage new value.
+ *
+ */
+ public void setUnlockMessage(String unlockMessage)
+ {
+ this.unlockMessage = unlockMessage;
+ }
+
+
+ /**
+ * This method sets the rewardText value.
+ * @param rewardText the rewardText new value.
+ *
+ */
+ public void setRewardText(String rewardText)
+ {
+ this.rewardText = rewardText;
+ }
+
+
+ /**
+ * This method sets the rewardItems value.
+ * @param rewardItems the rewardItems new value.
+ *
+ */
+ public void setRewardItems(List rewardItems)
+ {
+ this.rewardItems = rewardItems;
+ }
+
+
+ /**
+ * This method sets the rewardExperience value.
+ * @param rewardExperience the rewardExperience new value.
+ *
+ */
+ public void setRewardExperience(int rewardExperience)
+ {
+ this.rewardExperience = rewardExperience;
+ }
+
+
+ /**
+ * This method sets the rewardMoney value.
+ * @param rewardMoney the rewardMoney new value.
+ *
+ */
+ public void setRewardMoney(int rewardMoney)
+ {
+ this.rewardMoney = rewardMoney;
+ }
+
+
+ /**
+ * This method sets the rewardCommands value.
+ * @param rewardCommands the rewardCommands new value.
+ *
+ */
+ public void setRewardCommands(List rewardCommands)
+ {
+ this.rewardCommands = rewardCommands;
+ }
+
+
+ /**
+ * This method sets the challenges value.
+ * @param challenges the challenges new value.
+ *
+ */
+ public void setChallenges(Set challenges)
+ {
+ this.challenges = challenges;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Other methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compareTo(ChallengeLevel o)
+ {
+ if (this.equals(o))
+ {
+ return 0;
+ }
+ else
+ {
+ if (this.getWorld().equals(o.getWorld()))
+ {
+ if (this.order == o.getOrder())
+ {
+ return this.getUniqueId().compareTo(o.getUniqueId());
+ }
+ else
+ {
+ return Integer.compare(this.order, o.getOrder());
+ }
+ }
+ else
+ {
+ return this.getWorld().compareTo(o.getWorld());
+ }
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode());
+ return result;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof ChallengeLevel))
+ {
+ return false;
+ }
+
+ ChallengeLevel other = (ChallengeLevel) obj;
+
+ if (uniqueId == null)
+ {
+ return other.uniqueId == null;
+ }
+ else
+ {
+ return uniqueId.equals(other.uniqueId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/challenges/database/object/ChallengeLevels.java b/src/main/java/world/bentobox/challenges/database/object/ChallengeLevels.java
deleted file mode 100644
index 7f77fd8..0000000
--- a/src/main/java/world/bentobox/challenges/database/object/ChallengeLevels.java
+++ /dev/null
@@ -1,225 +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
- *
- */
-public class ChallengeLevels implements DataObject, Comparable {
-
- 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 worlds = new ArrayList<>();
-
- @ConfigComment("Commands to run when this level is completed")
- private List 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 rewardItems;
-
- @ConfigComment("Unlock experience reward")
- private int expReward;
-
- @ConfigComment("Unlock money reward")
- private int moneyReward;
-
- public String getFriendlyName() {
- return friendlyName;
- }
-
- public List 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 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 getRewardItems() {
- return rewardItems;
- }
-
- /**
- * @param rewardItems the rewardItems to set
- */
- public void setRewardItems(List 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 getWorlds() {
- return worlds;
- }
-
- /**
- * @param worlds the worlds to set
- */
- public void setWorlds(List 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;
- }
-
-}
diff --git a/src/main/java/world/bentobox/challenges/database/object/Challenges.java b/src/main/java/world/bentobox/challenges/database/object/Challenges.java
deleted file mode 100644
index c494516..0000000
--- a/src/main/java/world/bentobox/challenges/database/object/Challenges.java
+++ /dev/null
@@ -1,633 +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
- *
- */
-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 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 environment = new ArrayList<>();
- @ConfigComment("The required permissions to see this challenge. String list.")
- private Set 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 requiredBlocks = new EnumMap<>(Material.class);
- @ConfigComment("The items that must be in the inventory to complete the challenge. ItemStack List.")
- private List requiredItems = new ArrayList<>();
- @ConfigComment("Any entities that must be in the area for ISLAND type challenges. Map EntityType, Number")
- private Map 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 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 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 repeatItemReward = new ArrayList<>();
- @ConfigComment("Repeat money award")
- private int repeatMoneyReward;
- @ConfigComment("Commands to run when challenge is repeated. String List.")
- private List 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 getDescription() {
- return description;
- }
-
- /**
- * @param description the description to set
- */
- public void setDescription(List 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 getRepeatItemReward() {
- return repeatItemReward;
- }
-
- /**
- * @param repeatItemReward the repeatItemReward to set
- */
- public void setRepeatItemReward(List 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 getRepeatRewardCommands() {
- return repeatRewardCommands;
- }
-
- /**
- * @param repeatRewardCommands the repeatRewardCommands to set
- */
- public void setRepeatRewardCommands(List 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 getReqPerms() {
- return reqPerms;
- }
-
- /**
- * @param reqPerms the reqPerms to set
- */
- public void setReqPerms(Set reqPerms) {
- this.reqPerms = reqPerms;
- }
-
- /**
- * @return the requiredItems
- */
- public List getRequiredItems() {
- return requiredItems;
- }
-
- /**
- * @param requiredItems the requiredItems to set
- */
- public void setRequiredItems(List requiredItems) {
- this.requiredItems = requiredItems;
- }
-
- /**
- * @return requiredEntities
- */
- public Map getRequiredEntities() {
- return requiredEntities;
- }
-
- /**
- * @param requiredEntities the requiredEntities to set
- */
- public void setRequiredEntities(Map requiredEntities) {
- this.requiredEntities = requiredEntities;
- }
-
- /**
- * @return the requiredBlocks
- */
- public Map getRequiredBlocks() {
- return requiredBlocks;
- }
-
- /**
- * @param map the requiredBlocks to set
- */
- public void setRequiredBlocks(Map map) {
- this.requiredBlocks = map;
- }
-
- /**
- * @return the rewardCommands
- */
- public List getRewardCommands() {
- return rewardCommands;
- }
-
- /**
- * @param rewardCommands the rewardCommands to set
- */
- public void setRewardCommands(List rewardCommands) {
- this.rewardCommands = rewardCommands;
- }
-
- /**
- * @return the itemReward
- */
- public List getRewardItems() {
- return rewardItems;
- }
-
- /**
- * @param itemReward the itemReward to set
- */
- public void setRewardItems(List 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 getEnvironment() {
- return environment;
- }
-
- /**
- * @param environment the environment to set
- */
- public void setEnvironment(List 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;
- }
-}
diff --git a/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java b/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java
index fd62f9f..9907099 100644
--- a/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java
+++ b/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java
@@ -1,17 +1,13 @@
-/**
- *
- */
package world.bentobox.challenges.database.object;
+
+import com.google.gson.annotations.Expose;
+import org.bukkit.World;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import org.bukkit.World;
-
-import com.google.gson.annotations.Expose;
-
import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.bentobox.util.Util;
@@ -20,173 +16,286 @@ import world.bentobox.bentobox.util.Util;
* @author tastybento
*
*/
-public class ChallengesPlayerData implements DataObject {
+public class ChallengesPlayerData implements DataObject
+{
+ /**
+ * Constructor ChallengesPlayerData creates a new ChallengesPlayerData instance.
+ */
+ public ChallengesPlayerData()
+ {
+ }
- @Expose
- private String uniqueId = "";
- /**
- * Challenge map, where key = unique challenge name and Value = number of times completed
- */
- @Expose
- private Map challengeStatus = new HashMap<>();
- @Expose
- private Map challengesTimestamp = new HashMap<>();
- @Expose
- private Set levelsDone = new HashSet<>();
- // Required for bean instantiation
- public ChallengesPlayerData() {}
+ /**
+ * Creates a player data entry
+ *
+ * @param uniqueId - the player's UUID in string format
+ */
+ public ChallengesPlayerData(String uniqueId)
+ {
+ this.uniqueId = uniqueId;
+ }
- /**
- * Mark a challenge as having been completed. Will increment the number of times and timestamp
- * @param world - world of challenge
- * @param challengeName - unique challenge name
- */
- public void setChallengeDone(World world, String challengeName) {
- String name = Util.getWorld(world).getName() + challengeName;
- int times = challengeStatus.getOrDefault(name, 0) + 1;
- challengeStatus.put(name, times);
- challengesTimestamp.put(name, System.currentTimeMillis());
- }
- /**
- * Set the number of times a challenge has been done
- * @param world - world of challenge
- * @param challengeName - unique challenge name
- * @param times - the number of times to set
- *
- */
- public void setChallengeTimes(World world, String challengeName, int times) {
- String name = Util.getWorld(world).getName() + challengeName;
- challengeStatus.put(name, times);
- challengesTimestamp.put(name, System.currentTimeMillis());
- }
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
- /**
- * Check if a challenge has been done
- * @param challengeName - unique challenge name
- * @return true if done at least once
- */
- public boolean isChallengeDone(World world, String challengeName) {
- return getTimes(world, challengeName) > 0;
- }
- /**
- * Check how many times a challenge has been done
- * @param challengeName - unique challenge name
- * @return - number of times
- */
- public int getTimes(World world, String challengeName) {
- return challengeStatus.getOrDefault(Util.getWorld(world).getName() + challengeName, 0);
- }
+ /**
+ * This variable stores each player UUID as string.
+ */
+ @Expose
+ private String uniqueId = "";
- /**
- * Creates a player data entry
- * @param uniqueId - the player's UUID in string format
- */
- public ChallengesPlayerData(String uniqueId) {
- this.uniqueId = uniqueId;
- }
+ /**
+ * Challenge map, where key = unique challenge name and Value = number of times
+ * completed
+ */
+ @Expose
+ private Map challengeStatus = new HashMap<>();
- /* (non-Javadoc)
- * @see world.bentobox.bbox.database.objects.DataObject#getUniqueId()
- */
- @Override
- public String getUniqueId() {
- return uniqueId;
- }
+ /**
+ * Map of challenges completion time where key is challenges unique id and value is
+ * timestamp when challenge was completed last time.
+ */
+ @Expose
+ private Map challengesTimestamp = new HashMap<>();
- /* (non-Javadoc)
- * @see world.bentobox.bbox.database.objects.DataObject#setUniqueId(java.lang.String)
- */
- @Override
- public void setUniqueId(String uniqueId) {
- this.uniqueId = uniqueId;
- }
+ /**
+ * Set of Strings that contains all challenge levels that are completed.
+ */
+ @Expose
+ private Set levelsDone = new HashSet<>();
- /**
- * @return the challengeStatus
- */
- public Map getChallengeStatus() {
- return challengeStatus;
- }
- /**
- * @param challengeStatus the challengeStatus to set
- */
- public void setChallengeStatus(Map challengeStatus) {
- this.challengeStatus = challengeStatus;
- }
- /**
- * @return the challengesTimestamp
- */
- public Map getChallengesTimestamp() {
- return challengesTimestamp;
- }
- /**
- * @param challengesTimestamp the challengesTimestamp to set
- */
- public void setChallengesTimestamp(Map challengesTimestamp) {
- this.challengesTimestamp = challengesTimestamp;
- }
- /**
- * @return the levelsDone
- */
- public Set getLevelsDone() {
- return levelsDone;
- }
- /**
- * @param levelsDone the levelsDone to set
- */
- public void setLevelsDone(Set levelsDone) {
- this.levelsDone = levelsDone;
- }
+// ---------------------------------------------------------------------
+// Section: Getters
+// ---------------------------------------------------------------------
- /* (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 ChallengesPlayerData)) {
- return false;
- }
- ChallengesPlayerData other = (ChallengesPlayerData) obj;
- if (uniqueId == null) {
- if (other.uniqueId != null) {
- return false;
- }
- } else if (!uniqueId.equals(other.uniqueId)) {
- return false;
- }
- return true;
- }
+ /**
+ * @return uniqueID
+ * @see DataObject#getUniqueId()
+ */
+ @Override
+ public String getUniqueId()
+ {
+ return uniqueId;
+ }
- /**
- * Resets all challenges and levels in world for this player
- * @param world
- */
- public void reset(World world) {
- String worldName = Util.getWorld(world).getName();
- challengeStatus.keySet().removeIf(n -> n.startsWith(worldName));
- challengesTimestamp.keySet().removeIf(n -> n.startsWith(worldName));
- levelsDone.removeIf(n -> n.startsWith(worldName));
- }
-}
+ /**
+ * This method returns the challengeStatus value.
+ * @return the value of challengeStatus.
+ */
+ public Map getChallengeStatus()
+ {
+ return challengeStatus;
+ }
+
+
+ /**
+ * This method returns the challengesTimestamp value.
+ * @return the value of challengesTimestamp.
+ */
+ public Map getChallengesTimestamp()
+ {
+ return challengesTimestamp;
+ }
+
+
+ /**
+ * This method returns the levelsDone value.
+ * @return the value of levelsDone.
+ */
+ public Set getLevelsDone()
+ {
+ return levelsDone;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Setters
+// ---------------------------------------------------------------------
+
+
+ /**
+ * @param uniqueId - unique ID the uniqueId to set
+ * @see DataObject#setUniqueId(String)
+ */
+ @Override
+ public void setUniqueId(String uniqueId)
+ {
+ this.uniqueId = uniqueId;
+ }
+
+
+ /**
+ * This method sets the challengeStatus value.
+ * @param challengeStatus the challengeStatus new value.
+ *
+ */
+ public void setChallengeStatus(Map challengeStatus)
+ {
+ this.challengeStatus = challengeStatus;
+ }
+
+
+ /**
+ * This method sets the challengesTimestamp value.
+ * @param challengesTimestamp the challengesTimestamp new value.
+ *
+ */
+ public void setChallengesTimestamp(Map challengesTimestamp)
+ {
+ this.challengesTimestamp = challengesTimestamp;
+ }
+
+
+ /**
+ * This method sets the levelsDone value.
+ * @param levelsDone the levelsDone new value.
+ *
+ */
+ public void setLevelsDone(Set levelsDone)
+ {
+ this.levelsDone = levelsDone;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Other Methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Resets all challenges and levels in world for this player
+ *
+ * @param world world which challenges must be reset.
+ */
+ public void reset(World world)
+ {
+ String worldName = Util.getWorld(world).getName();
+ challengeStatus.keySet().removeIf(n -> n.startsWith(worldName));
+ challengesTimestamp.keySet().removeIf(n -> n.startsWith(worldName));
+ levelsDone.removeIf(n -> n.startsWith(worldName));
+ }
+
+
+ /**
+ * Mark a challenge as having been completed. Will increment the number of times and
+ * timestamp
+ *
+ * @param challengeName - unique challenge name
+ */
+ public void setChallengeDone(String challengeName)
+ {
+ int times = challengeStatus.getOrDefault(challengeName, 0) + 1;
+ challengeStatus.put(challengeName, times);
+ challengesTimestamp.put(challengeName, System.currentTimeMillis());
+ }
+
+
+ /**
+ * Set the number of times a challenge has been done
+ *
+ * @param challengeName - unique challenge name
+ * @param times - the number of times to set
+ */
+ public void setChallengeTimes(String challengeName, int times)
+ {
+ challengeStatus.put(challengeName, times);
+ challengesTimestamp.put(challengeName, System.currentTimeMillis());
+ }
+
+
+ /**
+ * Check if a challenge has been done
+ *
+ * @param challengeName - unique challenge name
+ * @return true if done at least once
+ */
+ public boolean isChallengeDone(String challengeName)
+ {
+ return this.getTimes(challengeName) > 0;
+ }
+
+
+ /**
+ * Check how many times a challenge has been done
+ *
+ * @param challengeName - unique challenge name
+ * @return - number of times
+ */
+ public int getTimes(String challengeName)
+ {
+ return challengeStatus.getOrDefault(challengeName, 0);
+ }
+
+
+ /**
+ * This method adds given level id to completed level set.
+ * @param uniqueId from ChallengeLevel object.
+ */
+ public void addCompletedLevel(String uniqueId)
+ {
+ this.levelsDone.add(uniqueId);
+ }
+
+
+ /**
+ * This method returns if given level is done.
+ * @param uniqueId of ChallengeLevel object.
+ * @return true
if level is completed, otherwise false
+ */
+ public boolean isLevelDone(String uniqueId)
+ {
+ return !this.levelsDone.isEmpty() && this.levelsDone.contains(uniqueId);
+ }
+
+
+ /**
+ * @see Object#hashCode()
+ * @return object hashCode value.
+ */
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode());
+ return result;
+ }
+
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ * @param obj Other object.
+ * @return boolean that indicate if objects are equals.
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof ChallengesPlayerData))
+ {
+ return false;
+ }
+
+ ChallengesPlayerData other = (ChallengesPlayerData) obj;
+
+ if (uniqueId == null)
+ {
+ return other.uniqueId == null;
+ }
+ else
+ {
+ return uniqueId.equals(other.uniqueId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/challenges/listeners/ResetListener.java b/src/main/java/world/bentobox/challenges/listeners/ResetListener.java
index 74c2339..4ee56a9 100644
--- a/src/main/java/world/bentobox/challenges/listeners/ResetListener.java
+++ b/src/main/java/world/bentobox/challenges/listeners/ResetListener.java
@@ -7,6 +7,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
+import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
@@ -26,8 +27,8 @@ public class ResetListener implements Listener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onIslandReset(IslandEvent e) {
- if (e.getReason().equals(Reason.CREATED) || (addon.getConfig().getBoolean("resetchallenges") && e.getReason().equals(Reason.RESETTED))) {
- addon.getChallengesManager().resetAllChallenges(e.getOwner(), e.getLocation().getWorld());
+ if (e.getReason().equals(Reason.CREATED) || (addon.getChallengesSettings().isResetChallenges() && e.getReason().equals(Reason.RESETTED))) {
+ addon.getChallengesManager().resetAllChallenges(User.getInstance(e.getOwner()), e.getLocation().getWorld());
}
}
}
diff --git a/src/main/java/world/bentobox/challenges/listeners/SaveListener.java b/src/main/java/world/bentobox/challenges/listeners/SaveListener.java
index 5f411ed..313d2ba 100644
--- a/src/main/java/world/bentobox/challenges/listeners/SaveListener.java
+++ b/src/main/java/world/bentobox/challenges/listeners/SaveListener.java
@@ -23,7 +23,7 @@ public class SaveListener implements Listener
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onWorldSave(WorldSaveEvent e)
{
- if (!this.addon.getChallengesManager().getAllChallengesList(e.getWorld()).isEmpty())
+ if (!this.addon.getChallengesManager().getAllChallenges(e.getWorld()).isEmpty())
{
this.addon.getChallengesManager().save();
}
diff --git a/src/main/java/world/bentobox/challenges/panel/AdminEditGUI.java b/src/main/java/world/bentobox/challenges/panel/AdminEditGUI.java
index 49bc3f5..2b3fd09 100644
--- a/src/main/java/world/bentobox/challenges/panel/AdminEditGUI.java
+++ b/src/main/java/world/bentobox/challenges/panel/AdminEditGUI.java
@@ -6,18 +6,23 @@ import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
import world.bentobox.challenges.ChallengesAddon;
-import world.bentobox.challenges.database.object.Challenges;
+import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem.ClickHandler;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
+
+/**
+ * @deprecated All panels are reworked.
+ */
+@Deprecated
public class AdminEditGUI implements ClickHandler {
private ChallengesAddon addon;
private User requester;
- private Challenges challenge;
+ private Challenge challenge;
private World world;
private String permPrefix;
private String label;
@@ -33,7 +38,7 @@ public class AdminEditGUI implements ClickHandler {
* @param permPrefix permission prefix for world
* @param label command label
*/
- public AdminEditGUI(ChallengesAddon addon, User requester, User target, Challenges challenge, World world,
+ public AdminEditGUI(ChallengesAddon addon, User requester, User target, Challenge challenge, World world,
String permPrefix, String label) {
super();
this.addon = addon;
diff --git a/src/main/java/world/bentobox/challenges/panel/AdminGUI.java b/src/main/java/world/bentobox/challenges/panel/AdminGUI.java
index 2cd9940..2382d84 100644
--- a/src/main/java/world/bentobox/challenges/panel/AdminGUI.java
+++ b/src/main/java/world/bentobox/challenges/panel/AdminGUI.java
@@ -6,18 +6,23 @@ import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
import world.bentobox.challenges.ChallengesAddon;
-import world.bentobox.challenges.database.object.Challenges;
+import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem.ClickHandler;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
+
+/**
+ * @deprecated All panels are reworked.
+ */
+@Deprecated
public class AdminGUI implements ClickHandler {
private ChallengesAddon addon;
private User player;
- private Challenges challenge;
+ private Challenge challenge;
private World world;
private String permPrefix;
private String label;
@@ -31,7 +36,7 @@ public class AdminGUI implements ClickHandler {
* @param permPrefix
* @param label
*/
- public AdminGUI(ChallengesAddon addon, User player, Challenges challenge, World world,
+ public AdminGUI(ChallengesAddon addon, User player, Challenge challenge, World world,
String permPrefix, String label) {
super();
this.addon = addon;
diff --git a/src/main/java/world/bentobox/challenges/panel/ChallengesPanels.java b/src/main/java/world/bentobox/challenges/panel/ChallengesPanels.java
index 85e9c68..c3d8f35 100644
--- a/src/main/java/world/bentobox/challenges/panel/ChallengesPanels.java
+++ b/src/main/java/world/bentobox/challenges/panel/ChallengesPanels.java
@@ -11,10 +11,12 @@ import org.bukkit.inventory.ItemStack;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.ChallengesManager;
-import world.bentobox.challenges.LevelStatus;
+import world.bentobox.challenges.database.object.ChallengeLevel;
+import world.bentobox.challenges.utils.GuiUtils;
+import world.bentobox.challenges.utils.LevelStatus;
import world.bentobox.challenges.commands.ChallengesCommand;
-import world.bentobox.challenges.database.object.Challenges;
-import world.bentobox.challenges.database.object.Challenges.ChallengeType;
+import world.bentobox.challenges.database.object.Challenge;
+import world.bentobox.challenges.database.object.Challenge.ChallengeType;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
@@ -22,11 +24,15 @@ import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
+/**
+ * @deprecated All panels are reworked.
+ */
+@Deprecated
public class ChallengesPanels {
private ChallengesAddon addon;
private ChallengesManager manager;
private User user;
- private String level;
+ private ChallengeLevel level;
private World world;
private String permPrefix;
private String label;
@@ -39,17 +45,17 @@ public class ChallengesPanels {
this.permPrefix = permPrefix;
this.label = label;
- if (manager.getChallengeList().isEmpty()) {
+ if (manager.getAllChallenges(world).isEmpty()) {
addon.getLogger().severe("There are no challenges set up!");
user.sendMessage("general.errors.general");
return;
}
if (level.isEmpty()) {
- level = manager.getChallengeList().keySet().iterator().next().getUniqueId();
+ level = manager.getLevels(world).iterator().next().getUniqueId();
}
- this.level = level;
+ this.level = this.manager.getLevel(level);
// Check if level is valid
- if (!manager.isLevelUnlocked(user, level, world)) {
+ if (!manager.isLevelUnlocked(user, world, this.level)) {
return;
}
PanelBuilder panelBuilder = new PanelBuilder()
@@ -65,15 +71,15 @@ public class ChallengesPanels {
}
private void addChallengeItems(PanelBuilder panelBuilder) {
- Set levelChallenges = manager.getChallenges(level, world);
+ List levelChallenges = manager.getLevelChallenges(level);
// Only show a control panel for the level requested.
- for (Challenges challenge : levelChallenges) {
+ for (Challenge challenge : levelChallenges) {
createItem(panelBuilder, challenge);
}
}
private void addFreeChallanges(PanelBuilder panelBuilder) {
- manager.getChallenges(ChallengesManager.FREE, world).forEach(challenge -> createItem(panelBuilder, challenge));
+ manager.getFreeChallenges(world).forEach(challenge -> createItem(panelBuilder, challenge));
}
@@ -81,11 +87,10 @@ public class ChallengesPanels {
* Creates a panel item for challenge if appropriate and adds it to panelBuilder
* @param panelBuilder
* @param challenge
- * @param user
*/
- private void createItem(PanelBuilder panelBuilder, Challenges challenge) {
+ private void createItem(PanelBuilder panelBuilder, Challenge challenge) {
// Check completion
- boolean completed = manager.isChallengeComplete(user, challenge.getUniqueId(), world);
+ boolean completed = manager.isChallengeComplete(user, challenge);
// If challenge is removed after completion, remove it
if (completed && challenge.isRemoveWhenCompleted()) {
return;
@@ -96,16 +101,13 @@ public class ChallengesPanels {
.description(challengeDescription(challenge))
.glow(completed)
.clickHandler((panel, player, c, s) -> {
- if (!challenge.getChallengeType().equals(ChallengeType.ICON)) {
- new TryToComplete(addon).user(player).manager(manager).challenge(challenge)
+ new TryToComplete(addon).user(player).manager(manager).challenge(challenge)
.world(world).permPrefix(permPrefix).label(label).build();
- //new TryToComplete(addon, player, manager, challenge, world, permPrefix, label);
- }
return true;
})
.build();
- if (challenge.getSlot() >= 0) {
- panelBuilder.item(challenge.getSlot(),item);
+ if (challenge.getOrder() >= 0) {
+ panelBuilder.item(challenge.getOrder(),item);
} else {
panelBuilder.item(item);
}
@@ -130,7 +132,7 @@ public class ChallengesPanels {
PanelItem item = new PanelItemBuilder()
.icon(new ItemStack(Material.ENCHANTED_BOOK))
.name(name)
- .description(manager.stringSplit(user.getTranslation("challenges.navigation","[level]",name)))
+ .description(GuiUtils.stringSplit(user.getTranslation("challenges.navigation","[level]",name)))
.clickHandler((p, u, c, s) -> {
u.closeInventory();
u.performCommand(label + " " + ChallengesCommand.CHALLENGE_COMMAND + " " + status.getLevel().getUniqueId());
@@ -144,7 +146,7 @@ public class ChallengesPanels {
PanelItem item = new PanelItemBuilder()
.icon(new ItemStack(Material.BOOK))
.name(name)
- .description(manager.stringSplit(user.getTranslation("challenges.to-complete", "[challengesToDo]",String.valueOf(previousStatus != null ? previousStatus.getNumberOfChallengesStillToDo() : ""), "[thisLevel]", previousLevelName)))
+ .description(GuiUtils.stringSplit(user.getTranslation("challenges.to-complete", "[challengesToDo]",String.valueOf(previousStatus != null ? previousStatus.getNumberOfChallengesStillToDo() : ""), "[thisLevel]", previousLevelName)))
.build();
panelBuilder.item(item);
}
@@ -157,10 +159,9 @@ public class ChallengesPanels {
* Creates the challenge description for the "item" in the inventory
*
* @param challenge
- * @param player
* @return List of strings splitting challenge string into 25 chars long
*/
- private List challengeDescription(Challenges challenge) {
+ private List challengeDescription(Challenge challenge) {
List result = new ArrayList();
String level = challenge.getLevel();
if (!level.isEmpty()) {
@@ -168,9 +169,9 @@ public class ChallengesPanels {
}
// Check if completed or not
- boolean complete = addon.getChallengesManager().isChallengeComplete(user, challenge.getUniqueId(), world);
+ boolean complete = addon.getChallengesManager().isChallengeComplete(user, challenge);
int maxTimes = challenge.getMaxTimes();
- long doneTimes = addon.getChallengesManager().checkChallengeTimes(user, challenge, world);
+ long doneTimes = addon.getChallengesManager().getChallengeTimes(user, challenge);
if (complete) {
result.add(user.getTranslation("challenges.complete"));
}
@@ -206,7 +207,7 @@ public class ChallengesPanels {
// First time
moneyReward = challenge.getRewardMoney();
rewardText = challenge.getRewardText();
- expReward = challenge.getRewardExp();
+ expReward = challenge.getRewardExperience();
if (!rewardText.isEmpty()) {
result.addAll(splitTrans(user, "challenges.first-time-rewards"));
}
@@ -214,7 +215,7 @@ public class ChallengesPanels {
// Repeat challenge
moneyReward = challenge.getRepeatMoneyReward();
rewardText = challenge.getRepeatRewardText();
- expReward = challenge.getRepeatExpReward();
+ expReward = challenge.getRepeatExperienceReward();
if (!rewardText.isEmpty()) {
result.addAll(splitTrans(user, "challenges.repeat-rewards"));
}
@@ -235,6 +236,6 @@ public class ChallengesPanels {
}
private Collection extends String> splitTrans(User user, String string, String...strings) {
- return addon.getChallengesManager().stringSplit(user.getTranslation(string, strings));
+ return GuiUtils.stringSplit(user.getTranslation(string, strings));
}
}
diff --git a/src/main/java/world/bentobox/challenges/panel/ChallengesPanels2.java b/src/main/java/world/bentobox/challenges/panel/ChallengesPanels2.java
index 22ee2c3..2006f46 100644
--- a/src/main/java/world/bentobox/challenges/panel/ChallengesPanels2.java
+++ b/src/main/java/world/bentobox/challenges/panel/ChallengesPanels2.java
@@ -1,26 +1,32 @@
package world.bentobox.challenges.panel;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.inventory.ItemStack;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
-import world.bentobox.challenges.ChallengesAddon;
-import world.bentobox.challenges.ChallengesManager;
-import world.bentobox.challenges.LevelStatus;
-import world.bentobox.challenges.commands.ChallengesCommand;
-import world.bentobox.challenges.database.object.Challenges;
-import world.bentobox.challenges.database.object.Challenges.ChallengeType;
import world.bentobox.bentobox.api.panels.Panel;
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.ChallengesManager;
+import world.bentobox.challenges.commands.ChallengesCommand;
+import world.bentobox.challenges.database.object.Challenge;
+import world.bentobox.challenges.database.object.Challenge.ChallengeType;
+import world.bentobox.challenges.database.object.ChallengeLevel;
+import world.bentobox.challenges.utils.GuiUtils;
+import world.bentobox.challenges.utils.LevelStatus;
+/**
+ * @deprecated All panels are reworked.
+ */
+@Deprecated
public class ChallengesPanels2 {
public enum Mode {
@@ -31,7 +37,7 @@ public class ChallengesPanels2 {
private ChallengesAddon addon;
private ChallengesManager manager;
private User requester;
- private String level;
+ private ChallengeLevel level;
private World world;
private String permPrefix;
private String label;
@@ -48,18 +54,18 @@ public class ChallengesPanels2 {
this.label = label;
this.mode = mode;
- if (manager.getChallengeList().isEmpty()) {
+ if (manager.getAllChallenges(world).isEmpty()) {
addon.getLogger().severe("There are no challenges set up!");
requester.sendMessage("general.errors.general");
return;
}
if (level.isEmpty()) {
// TODO: open the farthest challenge panel
- level = manager.getChallengeList().keySet().iterator().next().getUniqueId();
+ level = manager.getLevels(world).iterator().next().getUniqueId();
}
- this.level = level;
+ this.level = manager.getLevel(level);
// Check if level is valid
- if (mode.equals(Mode.PLAYER) && !manager.isLevelUnlocked(requester, level, world)) {
+ if (mode.equals(Mode.PLAYER) && !manager.isLevelUnlocked(requester, world, this.level)) {
return;
}
PanelBuilder panelBuilder = new PanelBuilder();
@@ -89,13 +95,13 @@ public class ChallengesPanels2 {
private void addChallengeItems(PanelBuilder panelBuilder) {
// Only show a control panel for the level requested.
- for (Challenges challenge : manager.getChallenges(level, world)) {
+ for (Challenge challenge : manager.getLevelChallenges(level)) {
createItem(panelBuilder, challenge);
}
}
private void addFreeChallanges(PanelBuilder panelBuilder) {
- manager.getChallenges(ChallengesManager.FREE, world).forEach(challenge -> createItem(panelBuilder, challenge));
+ manager.getFreeChallenges(world).forEach(challenge -> createItem(panelBuilder, challenge));
}
@@ -103,9 +109,8 @@ public class ChallengesPanels2 {
* Creates a panel item for challenge if appropriate and adds it to panelBuilder
* @param panelBuilder
* @param challenge
- * @param requester
*/
- private void createItem(PanelBuilder panelBuilder, Challenges challenge) {
+ private void createItem(PanelBuilder panelBuilder, Challenge challenge) {
// For admin, glow means activated. For user, glow means done
boolean glow = false;
switch (mode) {
@@ -113,10 +118,10 @@ public class ChallengesPanels2 {
glow = challenge.isDeployed();
break;
case EDIT:
- glow = manager.isChallengeComplete(requester, challenge.getUniqueId(), world);
+ glow = manager.isChallengeComplete(requester, challenge);
break;
case PLAYER:
- glow = manager.isChallengeComplete(requester, challenge.getUniqueId(), world);
+ glow = manager.isChallengeComplete(requester, challenge);
break;
default:
break;
@@ -134,33 +139,27 @@ public class ChallengesPanels2 {
if (mode.equals(Mode.ADMIN)) {
// Admin click
itemBuilder.clickHandler((panel, player, c, s) -> {
- if (!challenge.getChallengeType().equals(ChallengeType.ICON)) {
- new AdminGUI(addon, player, challenge, world, permPrefix, label);
- }
+ new AdminGUI(addon, player, challenge, world, permPrefix, label);
return true;
});
} else if (mode.equals(Mode.EDIT)) {
// Admin edit click
itemBuilder.clickHandler((panel, player, c, s) -> {
- if (!challenge.getChallengeType().equals(ChallengeType.ICON)) {
- new AdminEditGUI(addon, player, target, challenge, world, permPrefix, label);
- }
+ new AdminEditGUI(addon, player, target, challenge, world, permPrefix, label);
return true;
});
} else {
// Player click
itemBuilder.clickHandler((panel, player, c, s) -> {
- if (!challenge.getChallengeType().equals(ChallengeType.ICON)) {
- new TryToComplete(addon, player, manager, challenge, world, permPrefix, label);
- }
+ new TryToComplete(addon, player, challenge, world, label, permPrefix);
return true;
});
}
// If the challenge has a specific slot allocated, use it
- if (challenge.getSlot() >= 0) {
- panelBuilder.item(challenge.getSlot(),itemBuilder.build());
+ if (challenge.getOrder() >= 0) {
+ panelBuilder.item(challenge.getOrder(),itemBuilder.build());
} else {
panelBuilder.item(itemBuilder.build());
}
@@ -172,7 +171,7 @@ public class ChallengesPanels2 {
// Add navigation to other levels
for (LevelStatus status: manager.getChallengeLevelStatus(requester, world)) {
- if (status.getLevel().getUniqueId().equalsIgnoreCase(level)) {
+ if (status.getLevel().getUniqueId().equalsIgnoreCase(level.getUniqueId())) {
// Skip if this is the current level
previousStatus = status;
continue;
@@ -185,7 +184,7 @@ public class ChallengesPanels2 {
PanelItem item = new PanelItemBuilder()
.icon(new ItemStack(Material.ENCHANTED_BOOK))
.name(name)
- .description(manager.stringSplit(requester.getTranslation("challenges.navigation","[level]",name)))
+ .description(GuiUtils.stringSplit(requester.getTranslation("challenges.navigation","[level]",name)))
.clickHandler((p, u, c, s) -> {
u.closeInventory();
u.performCommand(label + " " + ChallengesCommand.CHALLENGE_COMMAND + " " + status.getLevel().getUniqueId());
@@ -199,7 +198,7 @@ public class ChallengesPanels2 {
PanelItem item = new PanelItemBuilder()
.icon(new ItemStack(Material.BOOK))
.name(name)
- .description(manager.stringSplit(requester.getTranslation("challenges.to-complete", "[challengesToDo]",String.valueOf(previousStatus != null ? previousStatus.getNumberOfChallengesStillToDo() : ""), "[thisLevel]", previousLevelName)))
+ .description(GuiUtils.stringSplit(requester.getTranslation("challenges.to-complete", "[challengesToDo]",String.valueOf(previousStatus != null ? previousStatus.getNumberOfChallengesStillToDo() : ""), "[thisLevel]", previousLevelName)))
.build();
panelBuilder.item(item);
}
@@ -212,10 +211,9 @@ public class ChallengesPanels2 {
* Creates the challenge description for the "item" in the inventory
*
* @param challenge
- * @param player
* @return List of strings splitting challenge string into 25 chars long
*/
- private List challengeDescription(Challenges challenge) {
+ private List challengeDescription(Challenge challenge) {
List result = new ArrayList();
String level = challenge.getLevel();
if (!level.isEmpty()) {
@@ -234,9 +232,9 @@ public class ChallengesPanels2 {
result.addAll(addRewards(challenge, true, true));
} else {
// Check if completed or not
- boolean complete = addon.getChallengesManager().isChallengeComplete(requester, challenge.getUniqueId(), world);
+ boolean complete = addon.getChallengesManager().isChallengeComplete(requester, challenge);
int maxTimes = challenge.getMaxTimes();
- long doneTimes = addon.getChallengesManager().checkChallengeTimes(requester, challenge, world);
+ long doneTimes = addon.getChallengesManager().getChallengeTimes(requester, challenge);
if (complete) {
result.add(requester.getTranslation("challenges.complete"));
}
@@ -274,7 +272,7 @@ public class ChallengesPanels2 {
return result;
}
- private List addRewards(Challenges challenge, boolean complete, boolean admin) {
+ private List addRewards(Challenge challenge, boolean complete, boolean admin) {
List result = new ArrayList<>();
double moneyReward = 0;
int expReward = 0;
@@ -283,7 +281,7 @@ public class ChallengesPanels2 {
// First time
moneyReward = challenge.getRewardMoney();
rewardText = challenge.getRewardText();
- expReward = challenge.getRewardExp();
+ expReward = challenge.getRewardExperience();
if (!rewardText.isEmpty()) {
result.addAll(splitTrans(requester, "challenges.first-time-rewards"));
}
@@ -292,7 +290,7 @@ public class ChallengesPanels2 {
// Repeat challenge
moneyReward = challenge.getRepeatMoneyReward();
rewardText = challenge.getRepeatRewardText();
- expReward = challenge.getRepeatExpReward();
+ expReward = challenge.getRepeatExperienceReward();
if (!rewardText.isEmpty()) {
result.addAll(splitTrans(requester, "challenges.repeat-rewards"));
}
@@ -311,6 +309,6 @@ public class ChallengesPanels2 {
}
private Collection extends String> splitTrans(User user, String string, String...strings) {
- return addon.getChallengesManager().stringSplit(user.getTranslation(string, strings));
+ return GuiUtils.stringSplit(user.getTranslation(string, strings));
}
}
diff --git a/src/main/java/world/bentobox/challenges/panel/CommonGUI.java b/src/main/java/world/bentobox/challenges/panel/CommonGUI.java
new file mode 100644
index 0000000..5e08cbe
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/CommonGUI.java
@@ -0,0 +1,245 @@
+package world.bentobox.challenges.panel;
+
+
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.inventory.ItemStack;
+import java.util.Collections;
+import java.util.List;
+
+import world.bentobox.bentobox.api.panels.PanelItem;
+import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
+import world.bentobox.bentobox.api.user.User;
+import world.bentobox.challenges.ChallengesAddon;
+
+
+/**
+ * This class contains common methods that will be used over all GUIs. It also allows
+ * easier navigation between different GUIs.
+ */
+public abstract class CommonGUI
+{
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ /**
+ * This variable stores parent gui.
+ */
+ private CommonGUI parentGUI;
+
+ /**
+ * Variable stores Challenges addon.
+ */
+ protected ChallengesAddon addon;
+
+ /**
+ * Variable stores world in which panel is referred to.
+ */
+ protected World world;
+
+ /**
+ * Variable stores user who created this panel.
+ */
+ protected User user;
+
+ /**
+ * Variable stores top label of command from which panel was called.
+ */
+ protected String topLabel;
+
+ /**
+ * Variable stores permission prefix of command from which panel was called.
+ */
+ protected String permissionPrefix;
+
+ /**
+ * Variable stores any value.
+ */
+ protected Object valueObject;
+
+ /**
+ * This object holds current page index.
+ */
+ protected int pageIndex;
+
+ /**
+ * This object holds PanelItem that allows to return to previous panel.
+ */
+ protected PanelItem returnButton;
+
+
+ /**
+ * This enum contains buttons that is offten used in multiple GUIs.
+ */
+ protected enum CommonButtons
+ {
+ NEXT,
+ PREVIOUS,
+ RETURN
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Constants
+// ---------------------------------------------------------------------
+
+
+ protected static final String ADMIN = "admin";
+
+ protected static final String CHALLENGES = "challenges";
+
+ protected static final String IMPORT = "import";
+
+ protected static final String SETTINGS = "settings";
+
+ protected static final String DELETE = "delete";
+
+ protected static final String EDIT = "edit";
+
+ protected static final String ADD = "add";
+
+ protected static final String RESET = "reset";
+
+ protected static final String COMPLETE = "complete";
+
+
+// ---------------------------------------------------------------------
+// Section: Constructors
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Default constructor that inits panels with minimal requirements, without parent panel.
+ *
+ * @param addon Addon where panel operates.
+ * @param world World from which panel was created.
+ * @param user User who created panel.
+ * @param topLabel Command top label which creates panel (f.e. island or ai)
+ * @param permissionPrefix Command permission prefix (f.e. bskyblock.)
+ */
+ public CommonGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ String topLabel,
+ String permissionPrefix)
+ {
+ this(addon, world, user, topLabel, permissionPrefix, null);
+ }
+
+
+ /**
+ * Default constructor that inits panels with minimal requirements.
+ *
+ * @param addon Addon where panel operates.
+ * @param world World from which panel was created.
+ * @param user User who created panel.
+ * @param topLabel Command top label which creates panel (f.e. island or ai)
+ * @param permissionPrefix Command permission prefix (f.e. bskyblock.)
+ * @param parentGUI Parent panel for current panel.
+ */
+ public CommonGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ String topLabel,
+ String permissionPrefix,
+ CommonGUI parentGUI)
+ {
+ this.addon = addon;
+ this.world = world;
+ this.user = user;
+
+ this.topLabel = topLabel;
+ this.permissionPrefix = permissionPrefix;
+
+ this.parentGUI = parentGUI;
+
+ this.pageIndex = 0;
+
+ this.returnButton = new PanelItemBuilder().
+ name(this.user.getTranslation("challenges.gui.buttons.back")).
+ icon(Material.OAK_DOOR).
+ clickHandler((panel, user1, clickType, i) -> {
+ if (this.parentGUI == null)
+ {
+ this.user.closeInventory();
+ return true;
+ }
+
+ this.parentGUI.build();
+ return true;
+ }).build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Common methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method builds all necessary elements in GUI panel.
+ */
+ public abstract void build();
+
+
+ /**
+ * This method returns PanelItem that represents given Button.
+ * @param button Button that must be returned.
+ * @return PanelItem with requested functionality.
+ */
+ protected PanelItem getButton(CommonButtons button)
+ {
+ ItemStack icon;
+ String name;
+ List description;
+ PanelItem.ClickHandler clickHandler;
+
+ switch (button)
+ {
+ case NEXT:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.next");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.SIGN);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.pageIndex++;
+ this.build();
+ return true;
+ };
+
+ break;
+ }
+ case PREVIOUS:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.previous");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.SIGN);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.pageIndex--;
+ this.build();
+ return true;
+ };
+
+ break;
+ }
+ case RETURN:
+ return this.returnButton;
+ default:
+ return null;
+ }
+
+ return new PanelItem(icon, name, description, false, clickHandler, false);
+ }
+
+
+ /**
+ * This method sets new value to ValueObject variable.
+ * @param value new Value of valueObject.
+ */
+ public void setValue(Object value)
+ {
+ this.valueObject = value;
+ }
+}
+
diff --git a/src/main/java/world/bentobox/challenges/panel/CreateChallengeListener.java b/src/main/java/world/bentobox/challenges/panel/CreateChallengeListener.java
index feb0621..d0b63ee 100644
--- a/src/main/java/world/bentobox/challenges/panel/CreateChallengeListener.java
+++ b/src/main/java/world/bentobox/challenges/panel/CreateChallengeListener.java
@@ -7,6 +7,11 @@ import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.bentobox.api.panels.PanelListener;
import world.bentobox.bentobox.api.user.User;
+
+/**
+ * @deprecated All panels are reworked.
+ */
+@Deprecated
public class CreateChallengeListener implements PanelListener {
private ChallengesAddon addon;
@@ -24,7 +29,7 @@ public class CreateChallengeListener implements PanelListener {
@Override
public void onInventoryClose(InventoryCloseEvent event) {
- addon.getChallengesManager().createInvChallenge(user, event.getInventory());
+ addon.getChallengesManager().createChallenge("uniqueID");
}
@Override
diff --git a/src/main/java/world/bentobox/challenges/panel/CreateChallengePanel.java b/src/main/java/world/bentobox/challenges/panel/CreateChallengePanel.java
index 93d8bb3..1c7473a 100644
--- a/src/main/java/world/bentobox/challenges/panel/CreateChallengePanel.java
+++ b/src/main/java/world/bentobox/challenges/panel/CreateChallengePanel.java
@@ -4,6 +4,11 @@ import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.user.User;
+
+/**
+ * @deprecated All panels are reworked.
+ */
+@Deprecated
public class CreateChallengePanel {
public CreateChallengePanel(ChallengesAddon addon, User user) {
diff --git a/src/main/java/world/bentobox/challenges/panel/RequiredPanel.java b/src/main/java/world/bentobox/challenges/panel/RequiredPanel.java
index 13affcb..76ff526 100644
--- a/src/main/java/world/bentobox/challenges/panel/RequiredPanel.java
+++ b/src/main/java/world/bentobox/challenges/panel/RequiredPanel.java
@@ -12,7 +12,7 @@ import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.ItemStack;
-import world.bentobox.challenges.database.object.Challenges;
+import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem.ClickHandler;
import world.bentobox.bentobox.api.panels.PanelListener;
@@ -25,11 +25,12 @@ import world.bentobox.bentobox.util.Util;
* Handles the requirements for a challenge
* Items, blocks, entities
* @author tastybento
- *
+ * @deprecated All panels are reworked.
*/
+@Deprecated
public class RequiredPanel implements ClickHandler, PanelListener {
private static final int CONTROL_NUMBER = 4;
- private Challenges challenge;
+ private Challenge challenge;
private User user;
private Panel panel;
private Panel referringPanel;
@@ -38,7 +39,7 @@ public class RequiredPanel implements ClickHandler, PanelListener {
* @param challenge
* @param user
*/
- public RequiredPanel(Challenges challenge, User user, Panel referringPanel) {
+ public RequiredPanel(Challenge challenge, User user, Panel referringPanel) {
this.challenge = challenge;
this.user = user;
this.panel = openPanel();
@@ -72,7 +73,7 @@ public class RequiredPanel implements ClickHandler, PanelListener {
.clickHandler(this)
.build()).forEach(pb::item);
return pb.user(user).build();
- case LEVEL:
+ case OTHER:
break;
default:
@@ -136,8 +137,6 @@ public class RequiredPanel implements ClickHandler, PanelListener {
}
// Save changes
switch (challenge.getChallengeType()) {
- case ICON:
- break;
case INVENTORY:
List reqItems = new ArrayList<>();
// Skip first item
@@ -153,7 +152,7 @@ public class RequiredPanel implements ClickHandler, PanelListener {
break;
case ISLAND:
break;
- case LEVEL:
+ case OTHER:
break;
default:
break;
diff --git a/src/main/java/world/bentobox/challenges/panel/TryToComplete.java b/src/main/java/world/bentobox/challenges/panel/TryToComplete.java
index 2fa22ff..3e32318 100644
--- a/src/main/java/world/bentobox/challenges/panel/TryToComplete.java
+++ b/src/main/java/world/bentobox/challenges/panel/TryToComplete.java
@@ -3,387 +3,624 @@
*/
package world.bentobox.challenges.panel;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.EnumMap;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Collectors;
import org.bukkit.Material;
import org.bukkit.World;
+import org.bukkit.block.Block;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
+import java.util.*;
+import java.util.stream.Collectors;
-import world.bentobox.challenges.ChallengesAddon;
-import world.bentobox.challenges.ChallengesManager;
-import world.bentobox.challenges.commands.ChallengesCommand;
-import world.bentobox.challenges.database.object.Challenges;
-import world.bentobox.challenges.database.object.Challenges.ChallengeType;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
-import world.bentobox.bentobox.hooks.VaultHook;
import world.bentobox.bentobox.util.Util;
-import world.bentobox.level.Level;
+import world.bentobox.challenges.ChallengesAddon;
+import world.bentobox.challenges.ChallengesManager;
+import world.bentobox.challenges.database.object.Challenge;
+import world.bentobox.challenges.database.object.Challenge.ChallengeType;
+import world.bentobox.challenges.database.object.ChallengeLevel;
+
/**
* Run when a user tries to complete a challenge
* @author tastybento
*
*/
-public class TryToComplete {
+public class TryToComplete
+{
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+ /**
+ * Challenges addon variable.
+ */
private ChallengesAddon addon;
- private World world;
- private String permPrefix;
- private User user;
- private ChallengesManager manager;
- private Challenges challenge;
- private String label;
- public TryToComplete label(String label) {
- this.label = label;
+ /**
+ * Challenges manager for addon.
+ */
+ private ChallengesManager manager;
+
+ /**
+ * World where all checks are necessary.
+ */
+ private World world;
+
+ /**
+ * User who is completing challenge.
+ */
+ private User user;
+
+ /**
+ * Permission prefix string.
+ */
+ private String permissionPrefix;
+
+ /**
+ * Top command first label.
+ */
+ private String topLabel;
+
+ /**
+ * Challenge that should be completed.
+ */
+ private Challenge challenge;
+
+ /**
+ * Variable that will be used to avoid multiple empty object generation.
+ */
+ private final ChallengeResult EMPTY_RESULT = new ChallengeResult();
+
+// ---------------------------------------------------------------------
+// Section: Builder
+// ---------------------------------------------------------------------
+
+ @Deprecated
+ public TryToComplete label(String label)
+ {
+ this.topLabel = label;
return this;
}
- public TryToComplete user(User user) {
+
+ @Deprecated
+ public TryToComplete user(User user)
+ {
this.user = user;
return this;
}
- public TryToComplete manager(ChallengesManager manager) {
+
+ @Deprecated
+ public TryToComplete manager(ChallengesManager manager)
+ {
this.manager = manager;
return this;
}
- public TryToComplete challenge(Challenges challenge) {
+
+ @Deprecated
+ public TryToComplete challenge(Challenge challenge)
+ {
this.challenge = challenge;
return this;
}
- public TryToComplete world(World world) {
+
+ @Deprecated
+ public TryToComplete world(World world)
+ {
this.world = world;
return this;
}
- public TryToComplete permPrefix(String prefix) {
- this.permPrefix = prefix;
+
+ @Deprecated
+ public TryToComplete permPrefix(String prefix)
+ {
+ this.permissionPrefix = prefix;
return this;
}
- public TryToComplete(ChallengesAddon addon) {
+
+ @Deprecated
+ public TryToComplete(ChallengesAddon addon)
+ {
this.addon = addon;
}
- public ChallengeResult build() {
+
+// ---------------------------------------------------------------------
+// Section: Constructor
+// ---------------------------------------------------------------------
+
+
+ /**
+ * @param addon - Challenges Addon.
+ * @param user - User who performs challenge.
+ * @param challenge - Challenge that should be completed.
+ * @param world - World where completion may occur.
+ * @param topLabel - Label of the top command.
+ * @param permissionPrefix - Permission prefix for GameMode addon.
+ */
+ public TryToComplete(ChallengesAddon addon,
+ User user,
+ Challenge challenge,
+ World world,
+ String topLabel,
+ String permissionPrefix)
+ {
+ this.addon = addon;
+ this.world = world;
+ this.permissionPrefix = permissionPrefix;
+ this.user = user;
+ this.manager = addon.getChallengesManager();
+ this.challenge = challenge;
+ this.topLabel = topLabel;
+
+ this.build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method checks if challenge can be done, and complete it, if it is possible.
+ * @return ChallengeResult object, that contains completion status.
+ */
+ public ChallengeResult build()
+ {
// Check if can complete challenge
- ChallengeResult result = checkIfCanCompleteChallenge();
- if (!result.meetsRequirements) {
+ ChallengeResult result = this.checkIfCanCompleteChallenge();
+
+ if (!result.meetsRequirements)
+ {
return result;
}
- if (!result.repeat) {
- // Give rewards
- for (ItemStack reward : challenge.getRewardItems()) {
- user.getInventory().addItem(reward).forEach((k,v) -> user.getWorld().dropItem(user.getLocation(), v));
+
+ if (!result.repeat)
+ {
+ // Item rewards
+ for (ItemStack reward : this.challenge.getRewardItems())
+ {
+ this.user.getInventory().addItem(reward).forEach((k, v) ->
+ this.user.getWorld().dropItem(this.user.getLocation(), v));
}
- // Give money
- this.addon.getPlugin().getVault().ifPresent(
- vaultHook -> vaultHook.deposit(this.user, this.challenge.getRewardMoney()));
+ // Money Reward
+ if (this.addon.isEconomyProvided())
+ {
+ this.addon.getEconomyProvider().deposit(this.user, this.challenge.getRewardMoney());
+ }
+
+ // Experience Reward
+ this.user.getPlayer().giveExp(this.challenge.getRewardExperience());
- // Give exp
- user.getPlayer().giveExp(challenge.getRewardExp());
// Run commands
- runCommands(challenge.getRewardCommands());
- user.sendMessage("challenges.you-completed", "[challenge]", challenge.getFriendlyName());
- if (addon.getConfig().getBoolean("broadcastmessages", false)) {
- for (Player p : addon.getServer().getOnlinePlayers()) {
+ this.runCommands(this.challenge.getRewardCommands());
+
+ this.user.sendMessage("challenges.you-completed", "[challenge]", this.challenge.getFriendlyName());
+
+ if (this.addon.getChallengesSettings().isBroadcastMessages())
+ {
+ for (Player p : this.addon.getServer().getOnlinePlayers())
+ {
User.getInstance(p).sendMessage("challenges.name-has-completed",
- "[name]", user.getName(), "[challenge]", challenge.getFriendlyName());
+ "[name]", this.user.getName(), "[challenge]", this.challenge.getFriendlyName());
}
}
- } else {
- // Give rewards
- for (ItemStack reward : challenge.getRepeatItemReward()) {
- user.getInventory().addItem(reward).forEach((k,v) -> user.getWorld().dropItem(user.getLocation(), v));
+ }
+ else
+ {
+ // Item Repeat Rewards
+ for (ItemStack reward : this.challenge.getRepeatItemReward())
+ {
+ this.user.getInventory().addItem(reward).forEach((k, v) ->
+ this.user.getWorld().dropItem(this.user.getLocation(), v));
}
- // Give money
- this.addon.getPlugin().getVault().ifPresent(
- vaultHook -> vaultHook.deposit(this.user, this.challenge.getRepeatMoneyReward()));
+ // Money Repeat Reward
+ if (this.addon.isEconomyProvided())
+ {
+ this.addon.getEconomyProvider().deposit(this.user, this.challenge.getRepeatMoneyReward());
+ }
+
+ // Experience Repeat Reward
+ this.user.getPlayer().giveExp(this.challenge.getRepeatExperienceReward());
- // Give exp
- user.getPlayer().giveExp(challenge.getRepeatExpReward());
// Run commands
- runCommands(challenge.getRepeatRewardCommands());
- user.sendMessage("challenges.you-repeated", "[challenge]", challenge.getFriendlyName());
+ this.runCommands(this.challenge.getRepeatRewardCommands());
+
+ this.user.sendMessage("challenges.you-repeated", "[challenge]", this.challenge.getFriendlyName());
}
+
// Mark as complete
- manager.setChallengeComplete(user, challenge.getUniqueId(), world);
- user.closeInventory();
- user.getPlayer().performCommand(label + " " + ChallengesCommand.CHALLENGE_COMMAND + " " + challenge.getLevel());
+ this.manager.setChallengeComplete(this.user, this.challenge);
+
+ if (!result.repeat)
+ {
+ ChallengeLevel level = this.manager.getLevel(this.challenge);
+
+ if (!this.manager.isLevelCompleted(this.user, level))
+ {
+ if (this.manager.validateLevelCompletion(this.user, level))
+ {
+ // Item rewards
+ for (ItemStack reward : level.getRewardItems())
+ {
+ this.user.getInventory().addItem(reward).forEach((k, v) ->
+ this.user.getWorld().dropItem(this.user.getLocation(), v));
+ }
+
+ // Money Reward
+ if (this.addon.isEconomyProvided())
+ {
+ this.addon.getEconomyProvider().deposit(this.user, level.getRewardMoney());
+ }
+
+ // Experience Reward
+ this.user.getPlayer().giveExp(level.getRewardExperience());
+
+ // Run commands
+ this.runCommands(level.getRewardCommands());
+
+ this.user.sendMessage("challenges.you-completed-level", "[level]", level.getFriendlyName());
+
+ if (this.addon.getChallengesSettings().isBroadcastMessages())
+ {
+ for (Player p : this.addon.getServer().getOnlinePlayers())
+ {
+ User.getInstance(p).sendMessage("challenges.name-has-completed-level",
+ "[name]", this.user.getName(), "[level]", level.getFriendlyName());
+ }
+ }
+
+ this.manager.setLevelComplete(this.user, level);
+ }
+ }
+ }
+
return result;
}
- /**
- * @param addon
- * @param user
- * @param manager
- * @param challenge
- * @param world
- * @param permPrefix
- */
- public TryToComplete(ChallengesAddon addon, User user, ChallengesManager manager, Challenges challenge, World world, String permPrefix, String label) {
- this.addon = addon;
- this.world = world;
- this.permPrefix = permPrefix;
- this.user = user;
- this.manager = manager;
- this.challenge = challenge;
-
- // Check if can complete challenge
- ChallengeResult result = checkIfCanCompleteChallenge();
- if (!result.meetsRequirements) {
- return;
- }
- if (!result.repeat) {
- // Give rewards
- for (ItemStack reward : challenge.getRewardItems()) {
- user.getInventory().addItem(reward).forEach((k,v) -> user.getWorld().dropItem(user.getLocation(), v));
- }
-
- // Give money
- this.addon.getPlugin().getVault().ifPresent(
- vaultHook -> vaultHook.deposit(this.user, this.challenge.getRewardMoney()));
-
- // Give exp
- user.getPlayer().giveExp(challenge.getRewardExp());
- // Run commands
- runCommands(challenge.getRewardCommands());
- user.sendMessage("challenges.you-completed", "[challenge]", challenge.getFriendlyName());
- if (addon.getConfig().getBoolean("broadcastmessages", false)) {
- for (Player p : addon.getServer().getOnlinePlayers()) {
- User.getInstance(p).sendMessage("challenges.name-has-completed",
- "[name]", user.getName(), "[challenge]", challenge.getFriendlyName());
- }
- }
- } else {
- // Give rewards
- for (ItemStack reward : challenge.getRepeatItemReward()) {
- user.getInventory().addItem(reward).forEach((k,v) -> user.getWorld().dropItem(user.getLocation(), v));
- }
-
- // Give money
- this.addon.getPlugin().getVault().ifPresent(
- vaultHook -> vaultHook.deposit(this.user, this.challenge.getRepeatMoneyReward()));
-
- // Give exp
- user.getPlayer().giveExp(challenge.getRepeatExpReward());
- // Run commands
- runCommands(challenge.getRepeatRewardCommands());
- user.sendMessage("challenges.you-repeated", "[challenge]", challenge.getFriendlyName());
- }
- // Mark as complete
- manager.setChallengeComplete(user, challenge.getUniqueId(), world);
- user.closeInventory();
- user.getPlayer().performCommand(label + " " + ChallengesCommand.CHALLENGE_COMMAND + " " + challenge.getLevel());
- }
/**
* Checks if a challenge can be completed or not
+ * It returns ChallengeResult.
*/
- private ChallengeResult checkIfCanCompleteChallenge() {
+ private ChallengeResult checkIfCanCompleteChallenge()
+ {
+ ChallengeResult result;
+
+ ChallengeType type = this.challenge.getChallengeType();
+
// Check the world
- if (!Util.getWorld(user.getWorld()).getName().equalsIgnoreCase(challenge.getWorld())) {
- user.sendMessage("general.errors.wrong-world");
- return new ChallengeResult();
+ if (!this.challenge.isDeployed())
+ {
+ this.user.sendMessage("challenges.error.not-deployed");
+ result = EMPTY_RESULT;
}
- // Check if user has the
- if (!challenge.getLevel().equals(ChallengesManager.FREE) && !manager.isLevelUnlocked(user, challenge.getLevel(), world)) {
- user.sendMessage("challenges.errors.challenge-level-not-available");
- return new ChallengeResult();
+ else if (Util.getWorld(this.world) != Util.getWorld(this.user.getWorld()) ||
+ !this.challenge.getUniqueId().startsWith(Util.getWorld(this.world).getName()))
+ {
+ this.user.sendMessage("general.errors.wrong-world");
+ result = EMPTY_RESULT;
+ }
+ // Player is not on island
+ else if (!this.addon.getIslands().userIsOnIsland(this.user.getWorld(), this.user))
+ {
+ this.user.sendMessage("challenges.error.not-on-island");
+ result = EMPTY_RESULT;
+ }
+ // Check if user has unlocked challenges level.
+ else if (!this.challenge.getLevel().equals(ChallengesManager.FREE) &&
+ !this.manager.isLevelUnlocked(this.user, this.world, this.manager.getLevel(this.challenge.getLevel())))
+ {
+ this.user.sendMessage("challenges.errors.challenge-level-not-available");
+ result = EMPTY_RESULT;
}
// Check max times
- if (challenge.isRepeatable() && challenge.getMaxTimes() > 0 && manager.checkChallengeTimes(user, challenge, world) >= challenge.getMaxTimes()) {
- user.sendMessage("challenges.not-repeatable");
- return new ChallengeResult();
+ else if (this.challenge.isRepeatable() && this.challenge.getMaxTimes() > 0 &&
+ this.manager.getChallengeTimes(this.user, this.challenge) >= this.challenge.getMaxTimes())
+ {
+ this.user.sendMessage("challenges.not-repeatable");
+ result = EMPTY_RESULT;
}
// Check repeatability
- if (manager.isChallengeComplete(user, challenge.getUniqueId(), world)
- && (!challenge.isRepeatable() || challenge.getChallengeType().equals(ChallengeType.LEVEL)
- || challenge.getChallengeType().equals(ChallengeType.ISLAND))) {
- user.sendMessage("challenges.not-repeatable");
- return new ChallengeResult();
- }
-
- // Check money
- Optional vaultHook = this.addon.getPlugin().getVault();
-
- if (vaultHook.isPresent())
+ else if (!this.challenge.isRepeatable() && this.manager.isChallengeComplete(this.user, this.challenge))
{
- if (!vaultHook.get().has(this.user, this.challenge.getReqMoney()))
- {
- this.user.sendMessage("challenges.not-enough-money", "[money]", Integer.toString(this.challenge.getReqMoney()));
- return new ChallengeResult();
- }
+ this.user.sendMessage("challenges.not-repeatable");
+ result = EMPTY_RESULT;
}
-
- // Check exp
- if (this.user.getPlayer().getTotalExperience() < this.challenge.getReqExp())
+ // Check environment
+ else if (!this.challenge.getEnvironment().isEmpty() &&
+ !this.challenge.getEnvironment().contains(this.user.getWorld().getEnvironment()))
{
- this.user.sendMessage("challenges.not-enough-exp", "[xp]", Integer.toString(this.challenge.getReqExp()));
- return new ChallengeResult();
+ this.user.sendMessage("challenges.errors.wrong-environment");
+ result = EMPTY_RESULT;
+ }
+ // Check permission
+ else if (!this.checkPermissions())
+ {
+ this.user.sendMessage("general.errors.no-permission");
+ result = EMPTY_RESULT;
+ }
+ else if (type.equals(ChallengeType.INVENTORY))
+ {
+ result = this.checkInventory();
+ }
+ else if (type.equals(ChallengeType.ISLAND))
+ {
+ result = this.checkSurrounding();
+ }
+ else if (type.equals(ChallengeType.OTHER))
+ {
+ result = this.checkOthers();
+ }
+ else
+ {
+ result = EMPTY_RESULT;
}
- switch (challenge.getChallengeType()) {
- case INVENTORY:
- return checkInventory();
- case LEVEL:
- return checkLevel();
- case ISLAND:
- return checkSurrounding();
- default:
- return new ChallengeResult();
- }
- }
-
- private ChallengeResult checkInventory() {
- // Run through inventory
- List required = new ArrayList<>(challenge.getRequiredItems());
- for (ItemStack req : required) {
- // Check for FIREWORK_ROCKET, ENCHANTED_BOOK, WRITTEN_BOOK, POTION and FILLED_MAP because these have unique meta when created
- switch (req.getType()) {
- case FIREWORK_ROCKET:
- case ENCHANTED_BOOK:
- case WRITTEN_BOOK:
- case FILLED_MAP:
- // Get how many items are in the inventory. Item stacks amounts need to be summed
- int numInInventory = Arrays.stream(user.getInventory().getContents()).filter(Objects::nonNull).filter(i -> i.getType().equals(req.getType())).mapToInt(i -> i.getAmount()).sum();
- if (numInInventory < req.getAmount()) {
- user.sendMessage("challenges.error.not-enough-items", "[items]", Util.prettifyText(req.getType().toString()));
- return new ChallengeResult();
- }
- break;
- default:
- // General checking
- if (!user.getInventory().containsAtLeast(req, req.getAmount())) {
- user.sendMessage("challenges.error.not-enough-items", "[items]", Util.prettifyText(req.getType().toString()));
- return new ChallengeResult();
- }
- }
-
- }
- // If remove items, then remove them
- if (challenge.isTakeItems()) {
- removeItems(required);
-
- }
-
- // process money removal
- this.removeMoney();
-
- // Return the result
- return new ChallengeResult().setMeetsRequirements().setRepeat(manager.isChallengeComplete(user, challenge.getUniqueId(), world));
+ // Everything fails till this point.
+ return result;
}
/**
- * This method withdraw user money, if challenge Required Money is larger then 0, and
- * it is set to removal.
- * This works only if vaultHook is enabled.
- */
- private void removeMoney()
+ * This method checks if user has all required permissions.
+ * @return true if user has all required permissions, otherwise false.
+ */
+ private boolean checkPermissions()
{
- Optional vaultHook = this.addon.getPlugin().getVault();
+ return this.challenge.getRequiredPermissions().isEmpty() ||
+ this.challenge.getRequiredPermissions().stream().allMatch(s -> this.user.hasPermission(s));
+ }
- if (vaultHook.isPresent() &&
- this.challenge.isTakeMoney() &&
- this.challenge.getReqMoney() > 0)
+ /**
+ * This method runs all commands from command list.
+ * @param commands List of commands that must be performed.
+ */
+ private void runCommands(List commands)
+ {
+ // Ignore commands with this perm
+ if (user.hasPermission(this.permissionPrefix + "command.challengeexempt") && !user.isOp())
{
- vaultHook.get().withdraw(this.user, this.challenge.getReqMoney());
+ return;
}
+ for (String cmd : commands)
+ {
+ if (cmd.startsWith("[SELF]"))
+ {
+ String alert = "Running command '" + cmd + "' as " + this.user.getName();
+ this.addon.getLogger().info(alert);
+ cmd = cmd.substring(6, cmd.length()).replace("[player]", this.user.getName()).trim();
+ try
+ {
+ if (!user.performCommand(cmd))
+ {
+ this.showError(cmd);
+ }
+ }
+ catch (Exception e)
+ {
+ this.showError(cmd);
+ }
+
+ continue;
+ }
+ // Substitute in any references to player
+ try
+ {
+ if (!this.addon.getServer().dispatchCommand(this.addon.getServer().getConsoleSender(),
+ cmd.replace("[player]", this.user.getName())))
+ {
+ this.showError(cmd);
+ }
+ }
+ catch (Exception e)
+ {
+ this.showError(cmd);
+ }
+ }
+ }
+
+
+ /**
+ * Throws error message.
+ * @param cmd Error message that appear after failing some command.
+ */
+ private void showError(final String cmd)
+ {
+ this.addon.getLogger().severe("Problem executing command executed by player - skipping!");
+ this.addon.getLogger().severe(() -> "Command was : " + cmd);
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Inventory Challenge
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Checks if a inventory challenge can be completed or not
+ * It returns ChallengeResult.
+ */
+ private ChallengeResult checkInventory()
+ {
+ // Run through inventory
+ List required = new ArrayList<>(this.challenge.getRequiredItems());
+ for (ItemStack req : required)
+ {
+ // Check for FIREWORK_ROCKET, ENCHANTED_BOOK, WRITTEN_BOOK, POTION and FILLED_MAP because these have unique meta when created
+ switch (req.getType())
+ {
+ case FIREWORK_ROCKET:
+ case ENCHANTED_BOOK:
+ case WRITTEN_BOOK:
+ case FILLED_MAP:
+ // Get how many items are in the inventory. Item stacks amounts need to be summed
+ int numInInventory =
+ Arrays.stream(this.user.getInventory().getContents()).filter(Objects::nonNull).
+ filter(i -> i.getType().equals(req.getType())).
+ mapToInt(ItemStack::getAmount).
+ sum();
+
+ if (numInInventory < req.getAmount())
+ {
+ this.user.sendMessage("challenges.error.not-enough-items",
+ "[items]",
+ Util.prettifyText(req.getType().toString()));
+ return EMPTY_RESULT;
+ }
+ break;
+ default:
+ // General checking
+ if (!this.user.getInventory().containsAtLeast(req, req.getAmount()))
+ {
+ this.user.sendMessage("challenges.error.not-enough-items",
+ "[items]",
+ Util.prettifyText(req.getType().toString()));
+ return EMPTY_RESULT;
+ }
+ }
+ }
+
+ // If remove items, then remove them
+
+ if (this.challenge.isTakeItems())
+ {
+ this.removeItems(required);
+ }
+
+
+ // Return the result
+ return new ChallengeResult().setMeetsRequirements().setRepeat(
+ this.manager.isChallengeComplete(this.user, this.challenge));
}
/**
* Removes items from a user's inventory
* @param required - a list of item stacks to be removed
- * @return Map of item type and quantity that were successfully removed from the user's inventory
*/
- public Map removeItems(List required) {
+ Map removeItems(List required)
+ {
Map removed = new HashMap<>();
- for (ItemStack req : required) {
+
+ for (ItemStack req : required)
+ {
int amountToBeRemoved = req.getAmount();
- List itemsInInv = Arrays.stream(user.getInventory().getContents()).filter(Objects::nonNull).filter(i -> i.getType().equals(req.getType())).collect(Collectors.toList());
- for (ItemStack i : itemsInInv) {
- if (amountToBeRemoved > 0) {
+ List itemsInInv = Arrays.stream(user.getInventory().getContents()).
+ filter(Objects::nonNull).
+ filter(i -> i.getType().equals(req.getType())).
+ collect(Collectors.toList());
+
+ for (ItemStack i : itemsInInv)
+ {
+ if (amountToBeRemoved > 0)
+ {
// Remove either the full amount or the remaining amount
- if (i.getAmount() >= amountToBeRemoved) {
+ if (i.getAmount() >= amountToBeRemoved)
+ {
i.setAmount(i.getAmount() - amountToBeRemoved);
removed.merge(i.getType(), amountToBeRemoved, Integer::sum);
amountToBeRemoved = 0;
- } else {
+ }
+ else
+ {
removed.merge(i.getType(), i.getAmount(), Integer::sum);
amountToBeRemoved -= i.getAmount();
i.setAmount(0);
-
}
}
}
- if (amountToBeRemoved > 0) {
- addon.logError("Could not remove " + amountToBeRemoved + " of " + req.getType() + " from player's inventory!");
+
+ if (amountToBeRemoved > 0)
+ {
+ this.addon.logError("Could not remove " + amountToBeRemoved + " of " + req.getType() +
+ " from player's inventory!");
}
}
+
return removed;
}
- private ChallengeResult checkLevel() {
- // Check if the level addon is installed or not
- long level = addon.getAddonByName("Level")
- .map(l -> ((Level)l).getIslandLevel(world, user.getUniqueId())).orElse(0L);
- if (level >= challenge.getReqIslandlevel()) {
- // process money removal
- this.removeMoney();
- return new ChallengeResult().setMeetsRequirements();
- } else {
- user.sendMessage("challenges.error.island-level", TextVariables.NUMBER, String.valueOf(challenge.getReqIslandlevel()));
- return new ChallengeResult();
- }
- }
- private ChallengeResult checkSurrounding() {
- if (!addon.getIslands().userIsOnIsland(world, user)) {
- // Player is not on island
- user.sendMessage("challenges.error.not-on-island");
- return new ChallengeResult();
- }
- // Check for items or entities in the area
- ChallengeResult result = searchForEntities(challenge.getRequiredEntities(), challenge.getSearchRadius());
- if (result.meetsRequirements && !challenge.getRequiredBlocks().isEmpty()) {
- // Search for items only if entities found
- result = searchForBlocks(challenge.getRequiredBlocks(), challenge.getSearchRadius());
- }
+// ---------------------------------------------------------------------
+// Section: Island Challenge
+// ---------------------------------------------------------------------
- if (result.meetsRequirements && this.challenge.isTakeMoney())
+
+ /**
+ * Checks if a island challenge can be completed or not
+ * It returns ChallengeResult.
+ */
+ private ChallengeResult checkSurrounding()
+ {
+ ChallengeResult result;
+
+ if (!this.addon.getIslands().userIsOnIsland(this.user.getWorld(), this.user))
{
- // process money removal
- this.removeMoney();
+ // Player is not on island
+ this.user.sendMessage("challenges.error.not-on-island");
+ result = EMPTY_RESULT;
+ }
+ else
+ {
+ // Check for items or entities in the area
+
+ result = this.searchForEntities(this.challenge.getRequiredEntities(), this.challenge.getSearchRadius());
+
+ if (result.meetsRequirements && !this.challenge.getRequiredBlocks().isEmpty())
+ {
+ // Search for items only if entities found
+ result = this.searchForBlocks(this.challenge.getRequiredBlocks(), this.challenge.getSearchRadius());
+ }
+
+ if (result.meetsRequirements &&
+ this.challenge.isRemoveEntities() &&
+ !this.challenge.getRequiredEntities().isEmpty())
+ {
+ this.removeEntities();
+ }
+
+ if (result.meetsRequirements &&
+ this.challenge.isRemoveBlocks() &&
+ !this.challenge.getRequiredBlocks().isEmpty())
+ {
+ this.removeBlocks();
+ }
}
return result;
}
- private ChallengeResult searchForBlocks(Map map, int searchRadius) {
+
+ /**
+ * This method search required blocks in given radius from user position.
+ * @param map RequiredBlock Map.
+ * @param searchRadius Search distance
+ * @return ChallengeResult
+ */
+ private ChallengeResult searchForBlocks(Map map, int searchRadius)
+ {
Map blocks = new EnumMap<>(map);
- for (int x = -searchRadius; x <= searchRadius; x++) {
- for (int y = -searchRadius; y <= searchRadius; y++) {
- for (int z = -searchRadius; z <= searchRadius; z++) {
- Material mat = user.getWorld().getBlockAt(user.getLocation().add(new Vector(x,y,z))).getType();
+
+ for (int x = -searchRadius; x <= searchRadius; x++)
+ {
+ for (int y = -searchRadius; y <= searchRadius; y++)
+ {
+ for (int z = -searchRadius; z <= searchRadius; z++)
+ {
+ Material mat = this.user.getWorld().getBlockAt(this.user.getLocation().add(new Vector(x, y, z))).getType();
// Remove one
blocks.computeIfPresent(mat, (b, amount) -> amount - 1);
// Remove any that have an amount of 0
@@ -391,93 +628,189 @@ public class TryToComplete {
}
}
}
- if (blocks.isEmpty()) {
+
+ if (blocks.isEmpty())
+ {
return new ChallengeResult().setMeetsRequirements();
}
- user.sendMessage("challenges.error.not-close-enough", "[number]", String.valueOf(searchRadius));
- blocks.forEach((k,v) -> user.sendMessage("challenges.error.you-still-need",
- "[amount]", String.valueOf(v),
- "[item]", Util.prettifyText(k.toString())));
- return new ChallengeResult();
- }
+ this.user.sendMessage("challenges.error.not-close-enough", "[number]", String.valueOf(searchRadius));
- private ChallengeResult searchForEntities(Map map, int searchRadius) {
- Map entities = map.isEmpty() ? new EnumMap<>(EntityType.class) : new EnumMap<>(map);
- user.getPlayer().getNearbyEntities(searchRadius, searchRadius, searchRadius).forEach(entity -> {
- // Look through all the nearby Entities, filtering by type
- entities.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount - 1);
- entities.entrySet().removeIf(e -> e.getValue() == 0);
- });
- if (entities.isEmpty()) {
- return new ChallengeResult().setMeetsRequirements();
- }
- entities.forEach((reqEnt, amount) -> user.sendMessage("challenges.error.you-still-need",
- "[amount]", String.valueOf(amount),
- "[item]", Util.prettifyText(reqEnt.toString())));
- return new ChallengeResult();
+ blocks.forEach((k, v) -> user.sendMessage("challenges.error.you-still-need",
+ "[amount]", String.valueOf(v),
+ "[item]", Util.prettifyText(k.toString())));
+
+ return EMPTY_RESULT;
}
/**
- * Contains flags on completion of challenge
- * @author tastybento
- *
+ * This method search required entities in given radius from user position.
+ * @param map RequiredEntities Map.
+ * @param searchRadius Search distance
+ * @return ChallengeResult
*/
- public class ChallengeResult {
+ private ChallengeResult searchForEntities(Map map, int searchRadius)
+ {
+ Map entities = map.isEmpty() ? new EnumMap<>(EntityType.class) : new EnumMap<>(map);
+
+ this.user.getPlayer().getNearbyEntities(searchRadius, searchRadius, searchRadius).forEach(entity -> {
+ // Look through all the nearby Entities, filtering by type
+ entities.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount - 1);
+ entities.entrySet().removeIf(e -> e.getValue() == 0);
+ });
+
+ if (entities.isEmpty())
+ {
+ return new ChallengeResult().setMeetsRequirements();
+ }
+
+ entities.forEach((reqEnt, amount) -> this.user.sendMessage("challenges.error.you-still-need",
+ "[amount]", String.valueOf(amount),
+ "[item]", Util.prettifyText(reqEnt.toString())));
+
+ return EMPTY_RESULT;
+ }
+
+
+ /**
+ * This method removes required block and set air instead of it.
+ */
+ private void removeBlocks()
+ {
+ Map blocks = new EnumMap<>(this.challenge.getRequiredBlocks());
+ int searchRadius = this.challenge.getSearchRadius();
+
+ for (int x = -searchRadius; x <= searchRadius; x++)
+ {
+ for (int y = -searchRadius; y <= searchRadius; y++)
+ {
+ for (int z = -searchRadius; z <= searchRadius; z++)
+ {
+ Block block = this.user.getWorld().getBlockAt(this.user.getLocation().add(new Vector(x, y, z)));
+
+ if (blocks.containsKey(block.getType()))
+ {
+ blocks.computeIfPresent(block.getType(), (b, amount) -> amount - 1);
+ blocks.entrySet().removeIf(en -> en.getValue() <= 0);
+
+ block.setType(Material.AIR);
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This method removes required entities.
+ */
+ private void removeEntities()
+ {
+ Map entities = this.challenge.getRequiredEntities().isEmpty() ?
+ new EnumMap<>(EntityType.class) : new EnumMap<>(this.challenge.getRequiredEntities());
+
+ int searchRadius = this.challenge.getSearchRadius();
+
+ this.user.getPlayer().getNearbyEntities(searchRadius, searchRadius, searchRadius).forEach(entity -> {
+ // Look through all the nearby Entities, filtering by type
+
+ if (entities.containsKey(entity.getType()))
+ {
+ entities.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount - 1);
+ entities.entrySet().removeIf(e -> e.getValue() == 0);
+ entity.remove();
+ }
+ });
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Other challenge
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Checks if a other challenge can be completed or not
+ * It returns ChallengeResult.
+ */
+ private ChallengeResult checkOthers()
+ {
+ if (!this.addon.isEconomyProvided() ||
+ this.challenge.getRequiredMoney() <= 0 ||
+ !this.addon.getEconomyProvider().has(this.user, this.challenge.getRequiredMoney()))
+ {
+ this.user.sendMessage("challenges.not-enough-money",
+ "[money]",
+ Integer.toString(this.challenge.getRequiredMoney()));
+ }
+ else if (this.challenge.getRequiredExperience() <= 0 ||
+ this.user.getPlayer().getTotalExperience() < this.challenge.getRequiredExperience())
+ {
+ this.user.sendMessage("challenges.not-enough-exp",
+ "[xp]",
+ Integer.toString(this.challenge.getRequiredExperience()));
+ }
+ else if (!this.addon.isLevelProvided() ||
+ this.addon.getLevelAddon().getIslandLevel(this.world, this.user.getUniqueId()) < this.challenge.getRequiredIslandLevel())
+ {
+ this.user.sendMessage("challenges.error.island-level",
+ TextVariables.NUMBER,
+ String.valueOf(this.challenge.getRequiredIslandLevel()));
+ }
+ else
+ {
+ if (this.addon.isEconomyProvided() && this.challenge.isTakeMoney())
+ {
+ this.addon.getEconomyProvider().withdraw(this.user, this.challenge.getRequiredMoney());
+ }
+
+ if (this.challenge.isTakeExperience())
+ {
+ this.user.getPlayer().setTotalExperience(
+ this.user.getPlayer().getTotalExperience() - this.challenge.getRequiredExperience());
+ }
+
+ return new ChallengeResult().setMeetsRequirements();
+ }
+
+ return EMPTY_RESULT;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Private classes
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Contains flags on completion of challenge
+ *
+ * @author tastybento
+ */
+ private class ChallengeResult
+ {
private boolean meetsRequirements;
+
private boolean repeat;
+
+
/**
- * @param meetsRequirements the meetsRequirements to set
*/
- public ChallengeResult setMeetsRequirements() {
+ ChallengeResult setMeetsRequirements()
+ {
this.meetsRequirements = true;
return this;
}
+
+
/**
* @param repeat the repeat to set
*/
- public ChallengeResult setRepeat(boolean repeat) {
+ ChallengeResult setRepeat(boolean repeat)
+ {
this.repeat = repeat;
return this;
}
-
- }
-
- private void runCommands(List commands) {
- // Ignore commands with this perm
- if (user.hasPermission(permPrefix + "command.challengeexempt") && !user.isOp()) {
- return;
- }
- for (String cmd : commands) {
- if (cmd.startsWith("[SELF]")) {
- String alert = "Running command '" + cmd + "' as " + user.getName();
- addon.getLogger().info(alert);
- cmd = cmd.substring(6,cmd.length()).replace("[player]", user.getName()).trim();
- try {
- if (!user.performCommand(cmd)) {
- showError(cmd);
- }
- } catch (Exception e) {
- showError(cmd);
- }
-
- continue;
- }
- // Substitute in any references to player
- try {
- if (!addon.getServer().dispatchCommand(addon.getServer().getConsoleSender(), cmd.replace("[player]", user.getName()))) {
- showError(cmd);
- }
- } catch (Exception e) {
- showError(cmd);
- }
- }
- }
-
- private void showError(final String cmd) {
- addon.getLogger().severe("Problem executing command executed by player - skipping!");
- addon.getLogger().severe(() -> "Command was : " + cmd);
-
}
}
diff --git a/src/main/java/world/bentobox/challenges/panel/admin/AdminGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/AdminGUI.java
new file mode 100644
index 0000000..644e0d0
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/admin/AdminGUI.java
@@ -0,0 +1,414 @@
+package world.bentobox.challenges.panel.admin;
+
+
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.inventory.ItemStack;
+import java.util.Collections;
+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.user.User;
+import world.bentobox.bentobox.util.Util;
+import world.bentobox.challenges.ChallengesAddon;
+import world.bentobox.challenges.panel.CommonGUI;
+import world.bentobox.challenges.utils.GuiUtils;
+
+
+/**
+ * This class contains Main
+ */
+public class AdminGUI extends CommonGUI
+{
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ /**
+ * This boolean holds if import should overwrite existing challenges.
+ */
+ private boolean overwriteMode;
+
+ /**
+ * This indicate if Reset Challenges must work as reset all.
+ */
+ private boolean resetAllMode;
+
+
+// ---------------------------------------------------------------------
+// Section: Enums
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This enum contains all button variations. Just for cleaner code.
+ */
+ private enum Button
+ {
+ COMPLETE_USER_CHALLENGES,
+ RESET_USER_CHALLENGES,
+ ADD_CHALLENGE,
+ ADD_LEVEL,
+ EDIT_CHALLENGE,
+ EDIT_LEVEL,
+ DELETE_CHALLENGE,
+ DELETE_LEVEL,
+ IMPORT_CHALLENGES,
+ EDIT_SETTINGS
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Constructor
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public AdminGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ String topLabel,
+ String permissionPrefix)
+ {
+ super(addon, world, user, topLabel, permissionPrefix);
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).name(
+ this.user.getTranslation("challenges.admin.gui-title"));
+
+ GuiUtils.fillBorder(panelBuilder);
+
+ panelBuilder.item(10, this.createButton(Button.COMPLETE_USER_CHALLENGES));
+ panelBuilder.item(19, this.createButton(Button.RESET_USER_CHALLENGES));
+
+ // Add Challenges
+ panelBuilder.item(12, this.createButton(Button.ADD_CHALLENGE));
+ panelBuilder.item(13, this.createButton(Button.ADD_LEVEL));
+
+ // Edit Challenges
+ panelBuilder.item(21, this.createButton(Button.EDIT_CHALLENGE));
+ panelBuilder.item(22, this.createButton(Button.EDIT_LEVEL));
+
+ // Remove Challenges
+ panelBuilder.item(30, this.createButton(Button.DELETE_CHALLENGE));
+ panelBuilder.item(31, this.createButton(Button.DELETE_LEVEL));
+
+
+ // Import Challenges
+ panelBuilder.item(15, this.createButton(Button.IMPORT_CHALLENGES));
+
+ // Edit Addon Settings
+ panelBuilder.item(16, this.createButton(Button.EDIT_SETTINGS));
+
+ panelBuilder.item(44, this.returnButton);
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method is used to create PanelItem for each button type.
+ * @param button Button which must be created.
+ * @return PanelItem with necessary functionality.
+ */
+ private PanelItem createButton(Button button)
+ {
+ ItemStack icon;
+ String name;
+ List description;
+ boolean glow;
+ PanelItem.ClickHandler clickHandler;
+
+ String permissionSuffix;
+
+ switch (button)
+ {
+ case COMPLETE_USER_CHALLENGES:
+ permissionSuffix = COMPLETE;
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.complete");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.WRITTEN_BOOK);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new ListUsersGUI(this.addon,
+ this.world,
+ this.user,
+ ListUsersGUI.Mode.COMPLETE,
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+
+ return true;
+ };
+ glow = false;
+
+ break;
+ case RESET_USER_CHALLENGES:
+ permissionSuffix = RESET;
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.reset");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.WRITABLE_BOOK);
+
+ glow = this.resetAllMode;
+
+ clickHandler = (panel, user, clickType, slot) -> {
+ if (clickType.isRightClick())
+ {
+ this.resetAllMode = !this.resetAllMode;
+ this.build();
+ }
+ else
+ {
+ new ListUsersGUI(this.addon,
+ this.world,
+ this.user,
+ this.resetAllMode ? ListUsersGUI.Mode.RESET_ALL : ListUsersGUI.Mode.RESET,
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+ }
+
+ return true;
+ };
+
+ break;
+ case ADD_CHALLENGE:
+ permissionSuffix = ADD;
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.add-challenge");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.BOOK);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new AnvilGUI(this.addon.getPlugin(),
+ this.user.getPlayer(),
+ "unique_id",
+ (player, reply) -> {
+ String newName = Util.getWorld(this.world).getName() + "_" + reply;
+
+ if (!this.addon.getChallengesManager().containsChallenge(newName))
+ {
+ new EditChallengeGUI(this.addon,
+ this.world,
+ this.user,
+ this.addon.getChallengesManager().createChallenge(newName),
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+ }
+ else
+ {
+ this.user.sendMessage("challenges.errors.unique-id", "[id]", reply);
+ }
+
+ return reply;
+ });
+
+ return true;
+ };
+ glow = false;
+
+ break;
+ case ADD_LEVEL:
+ permissionSuffix = ADD;
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.add-level");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.BOOK);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new AnvilGUI(this.addon.getPlugin(),
+ this.user.getPlayer(),
+ "unique_id",
+ (player, reply) -> {
+ String newName = Util.getWorld(this.world).getName() + "_" + reply;
+
+ if (!this.addon.getChallengesManager().containsLevel(newName))
+ {
+ new EditLevelGUI(this.addon,
+ this.world,
+ this.user,
+ this.addon.getChallengesManager().createLevel(newName),
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+ }
+ else
+ {
+ this.user.sendMessage("challenges.errors.unique-id", "[id]", reply);
+ }
+
+ return reply;
+ });
+
+ return true;
+ };
+ glow = false;
+
+ break;
+ case EDIT_CHALLENGE:
+ permissionSuffix = EDIT;
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.edit-challenge");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.ANVIL);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new ListChallengesGUI(this.addon,
+ this.world,
+ this.user,
+ ListChallengesGUI.Mode.EDIT,
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+
+ return true;
+ };
+ glow = false;
+
+ break;
+ case EDIT_LEVEL:
+ {
+ permissionSuffix = EDIT;
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.edit-level");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.ANVIL);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new ListLevelsGUI(this.addon,
+ this.world,
+ this.user,
+ ListLevelsGUI.Mode.EDIT,
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+
+ return true;
+ };
+ glow = false;
+
+ break;
+ }
+ case DELETE_CHALLENGE:
+ {
+ permissionSuffix = DELETE;
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.delete-challenge");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.LAVA_BUCKET);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new ListChallengesGUI(this.addon,
+ this.world,
+ this.user,
+ ListChallengesGUI.Mode.DELETE,
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+
+ return true;
+ };
+ glow = false;
+
+ break;
+ }
+ case DELETE_LEVEL:
+ {
+ permissionSuffix = DELETE;
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.delete-level");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.LAVA_BUCKET);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new ListLevelsGUI(this.addon,
+ this.world,
+ this.user,
+ ListLevelsGUI.Mode.DELETE,
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+
+ return true;
+ };
+ glow = false;
+
+ break;
+ }
+ case IMPORT_CHALLENGES:
+ {
+ permissionSuffix = IMPORT;
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.import");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.HOPPER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ if (clickType.isRightClick())
+ {
+ this.overwriteMode = !this.overwriteMode;
+ this.build();
+ }
+ else
+ {
+ // Run import command.
+ this.user.performCommand(this.topLabel + " " + CHALLENGES + " " + IMPORT +
+ (this.overwriteMode ? " overwrite" : ""));
+ }
+ return true;
+ };
+ glow = this.overwriteMode;
+
+ break;
+ }
+ case EDIT_SETTINGS:
+ {
+ permissionSuffix = SETTINGS;
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.settings");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.CRAFTING_TABLE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new EditSettingsGUI(this.addon,
+ this.world,
+ this.user,
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+
+ return true;
+ };
+ glow = false;
+
+ break;
+ }
+ default:
+ // This should never happen.
+ return null;
+ }
+
+ // If user does not have permission to run command, then change icon and clickHandler.
+ final String actionPermission = this.permissionPrefix + ADMIN + "." + CHALLENGES + "." + permissionSuffix;
+
+ if (!this.user.hasPermission(actionPermission))
+ {
+ icon = new ItemStack(Material.BARRIER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.user.sendMessage("general.errors.no-permission", "[permission]", actionPermission);
+ return true;
+ };
+ }
+
+ return new PanelItem(icon, name, description, glow, clickHandler, false);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/challenges/panel/admin/EditChallengeGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/EditChallengeGUI.java
new file mode 100644
index 0000000..812b58f
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/admin/EditChallengeGUI.java
@@ -0,0 +1,1292 @@
+package world.bentobox.challenges.panel.admin;
+
+
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.entity.EntityType;
+import org.bukkit.inventory.ItemStack;
+import java.util.*;
+
+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.user.User;
+import world.bentobox.challenges.ChallengesAddon;
+import world.bentobox.challenges.database.object.Challenge;
+import world.bentobox.challenges.panel.CommonGUI;
+import world.bentobox.challenges.panel.util.ItemSwitchGUI;
+import world.bentobox.challenges.panel.util.NumberGUI;
+import world.bentobox.challenges.panel.util.SelectEnvironmentGUI;
+import world.bentobox.challenges.panel.util.StringListGUI;
+import world.bentobox.challenges.utils.GuiUtils;
+
+
+/**
+ * This class contains all necessary methods that creates GUI and allow to edit challenges
+ * properties.
+ * TODO: ISLAND is not repeatable.
+ */
+public class EditChallengeGUI extends CommonGUI
+{
+// ---------------------------------------------------------------------
+// Section: Constructors
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ * @param challenge challenge that needs editing.
+ */
+ public EditChallengeGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ Challenge challenge,
+ String topLabel,
+ String permissionPrefix)
+ {
+ this(addon, world, user, challenge, topLabel, permissionPrefix, null);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ * @param challenge challenge that needs editing.
+ */
+ public EditChallengeGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ Challenge challenge,
+ String topLabel,
+ String permissionPrefix,
+ CommonGUI parentGUI)
+ {
+ super(addon, world, user, topLabel, permissionPrefix, parentGUI);
+ this.challenge = challenge;
+
+ // Default panel should be Properties.
+ this.currentMenuType = MenuType.PROPERTIES;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Panel Creation related methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).name(
+ this.user.getTranslation("challenges.gui.admin.edit-challenge-title"));
+
+ GuiUtils.fillBorder(panelBuilder);
+
+ panelBuilder.item(2, this.createMenuButton(MenuType.PROPERTIES));
+ panelBuilder.item(4, this.createMenuButton(MenuType.REQUIREMENTS));
+ panelBuilder.item(6, this.createMenuButton(MenuType.REWARDS));
+
+ if (this.currentMenuType.equals(MenuType.PROPERTIES))
+ {
+ this.buildMainPropertiesPanel(panelBuilder);
+ }
+ else if (this.currentMenuType.equals(MenuType.REQUIREMENTS))
+ {
+ switch (this.challenge.getChallengeType())
+ {
+ case INVENTORY:
+ this.buildInventoryRequirementsPanel(panelBuilder);
+ break;
+ case ISLAND:
+ this.buildIslandRequirementsPanel(panelBuilder);
+ break;
+ case OTHER:
+ this.buildOtherRequirementsPanel(panelBuilder);
+ break;
+ }
+ }
+ else if (this.currentMenuType.equals(MenuType.REWARDS))
+ {
+ this.buildRewardsPanel(panelBuilder);
+ }
+
+ panelBuilder.item(44, this.returnButton);
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This class populate ChallengesEditGUI with main challenge settings.
+ * @param panelBuilder PanelBuilder where icons must be added.
+ */
+ private void buildMainPropertiesPanel(PanelBuilder panelBuilder)
+ {
+ panelBuilder.item(10, this.createButton(Button.NAME));
+ panelBuilder.item(13, this.createButton(Button.TYPE));
+ panelBuilder.item(16, this.createButton(Button.DEPLOYED));
+
+ panelBuilder.item(19, this.createButton(Button.ICON));
+ panelBuilder.item(22, this.createButton(Button.DESCRIPTION));
+ panelBuilder.item(25, this.createButton(Button.ORDER));
+
+ panelBuilder.item(28, this.createButton(Button.ENVIRONMENT));
+ panelBuilder.item(31, this.createButton(Button.REMOVE_ON_COMPLETE));
+ }
+
+
+ /**
+ * This class populates ChallengesEditGUI with island challenges requirement elements.
+ * @param panelBuilder PanelBuilder where icons must be added.
+ */
+ private void buildIslandRequirementsPanel(PanelBuilder panelBuilder)
+ {
+ panelBuilder.item(19, this.createButton(Button.REQUIRED_ENTITIES));
+ panelBuilder.item(28, this.createButton(Button.REMOVE_ENTITIES));
+
+ panelBuilder.item(21, this.createButton(Button.REQUIRED_BLOCKS));
+ panelBuilder.item(30, this.createButton(Button.REMOVE_BLOCKS));
+
+ panelBuilder.item(23, this.createButton(Button.SEARCH_RADIUS));
+ panelBuilder.item(25, this.createButton(Button.REQUIRED_PERMISSIONS));
+ }
+
+
+ /**
+ * This class populates ChallengesEditGUI with inventory challenges requirement elements.
+ * @param panelBuilder PanelBuilder where icons must be added.
+ */
+ private void buildInventoryRequirementsPanel(PanelBuilder panelBuilder)
+ {
+ panelBuilder.item(10, this.createButton(Button.REQUIRED_ITEMS));
+ panelBuilder.item(19, this.createButton(Button.REMOVE_ITEMS));
+
+ panelBuilder.item(25, this.createButton(Button.REQUIRED_PERMISSIONS));
+ }
+
+
+ /**
+ * This class populates ChallengesEditGUI with other challenges requirement elements.
+ * @param panelBuilder PanelBuilder where icons must be added.
+ */
+ private void buildOtherRequirementsPanel(PanelBuilder panelBuilder)
+ {
+ panelBuilder.item(10, this.createButton(Button.REQUIRED_EXPERIENCE));
+ panelBuilder.item(19, this.createButton(Button.REMOVE_EXPERIENCE));
+
+ panelBuilder.item(12, this.createButton(Button.REQUIRED_MONEY));
+ panelBuilder.item(21, this.createButton(Button.REMOVE_MONEY));
+
+ panelBuilder.item(23, this.createButton(Button.REQUIRED_LEVEL));
+
+ panelBuilder.item(25, this.createButton(Button.REQUIRED_PERMISSIONS));
+ }
+
+
+ /**
+ * This class populates ChallengesEditGUI with challenges reward elements.
+ * @param panelBuilder PanelBuilder where icons must be added.
+ */
+ private void buildRewardsPanel(PanelBuilder panelBuilder)
+ {
+ panelBuilder.item(10, this.createButton(Button.REWARD_TEXT));
+ panelBuilder.item(19, this.createButton(Button.REWARD_COMMANDS));
+
+ panelBuilder.item(11, this.createButton(Button.REWARD_ITEM));
+ panelBuilder.item(20, this.createButton(Button.REWARD_EXPERIENCE));
+ panelBuilder.item(29, this.createButton(Button.REWARD_MONEY));
+
+ panelBuilder.item(22, this.createButton(Button.REPEATABLE));
+
+ if (this.challenge.isRepeatable())
+ {
+ panelBuilder.item(31, this.createButton(Button.REPEAT_COUNT));
+
+ panelBuilder.item(15, this.createButton(Button.REPEAT_REWARD_TEXT));
+ panelBuilder.item(24, this.createButton(Button.REPEAT_REWARD_COMMANDS));
+
+ panelBuilder.item(16, this.createButton(Button.REPEAT_REWARD_ITEM));
+ panelBuilder.item(25, this.createButton(Button.REPEAT_REWARD_EXPERIENCE));
+ panelBuilder.item(34, this.createButton(Button.REPEAT_REWARD_MONEY));
+ }
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Other methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method creates top menu buttons, that allows to switch "tabs".
+ * @param menuType Menu Type which button must be constructed.
+ * @return PanelItem that represents given menu type.
+ */
+ private PanelItem createMenuButton(MenuType menuType)
+ {
+ ItemStack icon;
+ String name;
+ List description;
+ boolean glow;
+ PanelItem.ClickHandler clickHandler;
+
+ switch (menuType)
+ {
+ case PROPERTIES:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.properties");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.CRAFTING_TABLE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.currentMenuType = MenuType.PROPERTIES;
+ this.build();
+
+ return true;
+ };
+ glow = this.currentMenuType.equals(MenuType.PROPERTIES);
+ break;
+ }
+ case REQUIREMENTS:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.requirements");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.HOPPER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.currentMenuType = MenuType.REQUIREMENTS;
+ this.build();
+
+ return true;
+ };
+ glow = this.currentMenuType.equals(MenuType.REQUIREMENTS);
+ break;
+ }
+ case REWARDS:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.rewards");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.DROPPER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.currentMenuType = MenuType.REWARDS;
+ this.build();
+
+ return true;
+ };
+ glow = this.currentMenuType.equals(MenuType.REWARDS);
+ break;
+ }
+ default:
+ return null;
+ }
+
+ return new PanelItem(icon, name, GuiUtils.stringSplit(description), glow, clickHandler, false);
+ }
+
+
+ /**
+ * This method creates buttons for default main menu.
+ * @param button Button which panel item must be created.
+ * @return PanelItem that represetns given button.
+ */
+ private PanelItem createButton(Button button)
+ {
+ ItemStack icon;
+ String name;
+ List description;
+ boolean glow;
+ PanelItem.ClickHandler clickHandler;
+
+ switch (button)
+ {
+ case TYPE:
+ {
+ List values = new ArrayList<>(Challenge.ChallengeType.values().length);
+
+ for (Challenge.ChallengeType type : Challenge.ChallengeType.values())
+ {
+ values.add((this.challenge.getChallengeType().equals(type) ? "&2" : "&c") +
+ this.user.getTranslation("challenges.gui.admin.descriptions." + type.name().toLowerCase()));
+ }
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.type",
+ "[value]", this.challenge.getChallengeType().name());
+ description = values;
+
+ if (this.challenge.getChallengeType().equals(Challenge.ChallengeType.ISLAND))
+ {
+ icon = new ItemStack(Material.GRASS_BLOCK);
+ }
+ else if (this.challenge.getChallengeType().equals(Challenge.ChallengeType.INVENTORY))
+ {
+ icon = new ItemStack(Material.CHEST);
+ }
+ else if (this.challenge.getChallengeType().equals(Challenge.ChallengeType.OTHER))
+ {
+ icon = new ItemStack(Material.EXPERIENCE_BOTTLE);
+ }
+ else
+ {
+ icon = this.challenge.getIcon();
+ }
+
+ clickHandler = (panel, user, clickType, slot) -> {
+ if (clickType.isRightClick())
+ {
+ this.challenge.setChallengeType(
+ this.getPreviousType(this.challenge.getChallengeType()));
+ }
+ else
+ {
+ this.challenge.setChallengeType(
+ this.getNextType(this.challenge.getChallengeType()));
+ }
+
+ this.build();
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case DEPLOYED:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.deployed");
+
+ if (this.challenge.isDeployed())
+ {
+ description = Collections.singletonList(this.user.getTranslation("challenges.gui.admin.descriptions.enabled"));
+ }
+ else
+ {
+ description = Collections.singletonList(this.user.getTranslation("challenges.gui.admin.descriptions.disabled"));
+ }
+
+ icon = new ItemStack(Material.LEVER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.challenge.setDeployed(!this.challenge.isDeployed());
+
+ this.build();
+ return true;
+ };
+ glow = this.challenge.isDeployed();
+ break;
+ }
+ case ICON:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.icon");
+ description = Collections.emptyList();
+ icon = this.challenge.getIcon();
+ clickHandler = (panel, user, clickType, slot) -> {
+ new AnvilGUI(this.addon.getPlugin(),
+ this.user.getPlayer(),
+ this.challenge.getIcon().getType().name(),
+ (player, reply) -> {
+ Material material = Material.getMaterial(reply);
+
+ if (material != null)
+ {
+ this.challenge.setIcon(new ItemStack(material));
+ this.build();
+ }
+ else
+ {
+ this.user.sendMessage("challenges.errors.wrong-icon", "[value]", reply);
+ }
+
+ return reply;
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case DESCRIPTION:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.description");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.WRITTEN_BOOK);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new StringListGUI(this.user, this.challenge.getDescription(), (status, value) -> {
+ if (status)
+ {
+ this.challenge.setDescription(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case ORDER:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.order");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.order",
+ "[value]",
+ Integer.toString(this.challenge.getOrder())));
+ icon = new ItemStack(Material.DROPPER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new NumberGUI(this.user, this.challenge.getOrder(), -1, 54, (status, value) -> {
+ if (status)
+ {
+ this.challenge.setOrder(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case ENVIRONMENT:
+ {
+ List values = new ArrayList<>(World.Environment.values().length);
+
+ for (World.Environment environment : World.Environment.values())
+ {
+ values.add((this.challenge.getEnvironment().contains(environment.name()) ? "&2" : "&c") +
+ this.user.getTranslation("challenges.gui.admin.descriptions." + environment.name().toLowerCase()));
+ }
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.environment");
+ description = values;
+ icon = new ItemStack(Material.DROPPER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new SelectEnvironmentGUI(this.user, this.challenge.getEnvironment(), (status, value) -> {
+ if (status)
+ {
+ this.challenge.setEnvironment(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REMOVE_ON_COMPLETE:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.remove-on-complete");
+ description = Collections.emptyList();
+
+ if (this.challenge.isRemoveWhenCompleted())
+ {
+ icon = new ItemStack(Material.LAVA_BUCKET);
+ }
+ else
+ {
+ icon = new ItemStack(Material.BUCKET);
+ }
+
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.challenge.setRemoveWhenCompleted(!this.challenge.isRemoveWhenCompleted());
+ this.build();
+
+ return true;
+ };
+ glow = this.challenge.isRemoveWhenCompleted();
+ break;
+ }
+ case NAME:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.name");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.DROPPER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new AnvilGUI(this.addon.getPlugin(),
+ this.user.getPlayer(),
+ this.challenge.getFriendlyName(),
+ (player, reply) -> {
+ this.challenge.setFriendlyName(reply);
+ this.build();
+ return reply;
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+
+ case REQUIRED_ENTITIES:
+ {
+ List values = new ArrayList<>(this.challenge.getRequiredEntities().size());
+
+ for (Map.Entry entry : this.challenge.getRequiredEntities().entrySet())
+ {
+ values.add(entry.getKey().name() + " " + entry.getValue());
+ }
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.entities");
+ description = values;
+ icon = new ItemStack(Material.CREEPER_HEAD);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new ManageEntitiesGUI(this.addon,
+ this.world,
+ this.user,
+ this.challenge.getRequiredEntities(),
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REMOVE_ENTITIES:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.remove-entities");
+
+ if (this.challenge.isRemoveEntities())
+ {
+ description = Collections.singletonList(this.user.getTranslation("challenges.gui.admin.descriptions.enabled"));
+ }
+ else
+ {
+ description = Collections.singletonList(this.user.getTranslation("challenges.gui.admin.descriptions.disabled"));
+ }
+
+ icon = new ItemStack(Material.LEVER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.challenge.setRemoveEntities(!this.challenge.isRemoveEntities());
+
+ this.build();
+ return true;
+ };
+ glow = this.challenge.isRemoveEntities();
+ break;
+ }
+ case REQUIRED_BLOCKS:
+ {
+ List values = new ArrayList<>(this.challenge.getRequiredBlocks().size());
+
+ for (Map.Entry entry : this.challenge.getRequiredBlocks().entrySet())
+ {
+ values.add(entry.getKey().name() + " " + entry.getValue());
+ }
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.blocks");
+ description = values;
+ icon = new ItemStack(Material.STONE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new ManageBlocksGUI(this.addon,
+ this.world,
+ this.user,
+ this.challenge.getRequiredBlocks(),
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REMOVE_BLOCKS:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.remove-blocks");
+
+ if (this.challenge.isRemoveBlocks())
+ {
+ description = Collections.singletonList(this.user.getTranslation("challenges.gui.admin.descriptions.enabled"));
+ }
+ else
+ {
+ description = Collections.singletonList(this.user.getTranslation("challenges.gui.admin.descriptions.disabled"));
+ }
+
+ icon = new ItemStack(Material.LEVER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.challenge.setRemoveBlocks(!this.challenge.isRemoveBlocks());
+
+ this.build();
+ return true;
+ };
+ glow = this.challenge.isRemoveBlocks();
+ break;
+ }
+ case SEARCH_RADIUS:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.search-radius");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.search-radius",
+ "[value]",
+ Integer.toString(this.challenge.getSearchRadius())));
+ icon = new ItemStack(Material.COBBLESTONE_WALL);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new NumberGUI(this.user, this.challenge.getSearchRadius(), 0, (status, value) -> {
+ if (status)
+ {
+ this.challenge.setSearchRadius(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REQUIRED_PERMISSIONS:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.permissions");
+ description = new ArrayList<>(this.challenge.getRequiredPermissions());
+ icon = new ItemStack(Material.REDSTONE_LAMP);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new StringListGUI(this.user, this.challenge.getRequiredPermissions(), (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRequiredPermissions(new HashSet<>(value));
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REQUIRED_ITEMS:
+ {
+ List values = new ArrayList<>(this.challenge.getRequiredItems().size());
+
+ for (ItemStack itemStack : this.challenge.getRequiredItems())
+ {
+ values.add(itemStack.getType().name() + " " + itemStack.getAmount());
+ }
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.required-items");
+ description = values;
+ icon = new ItemStack(Material.CHEST);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new ItemSwitchGUI(this.user, this.challenge.getRequiredItems(), (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRequiredItems(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REMOVE_ITEMS:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.remove-items");
+
+ if (this.challenge.isTakeItems())
+ {
+ description = Collections.singletonList(this.user.getTranslation("challenges.gui.admin.descriptions.enabled"));
+ }
+ else
+ {
+ description = Collections.singletonList(this.user.getTranslation("challenges.gui.admin.descriptions.disabled"));
+ }
+
+ icon = new ItemStack(Material.LEVER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.challenge.setTakeItems(!this.challenge.isTakeItems());
+
+ this.build();
+ return true;
+ };
+ glow = this.challenge.isTakeItems();
+ break;
+ }
+ case REQUIRED_EXPERIENCE:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.required-exp");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.required-exp",
+ "[value]",
+ Integer.toString(this.challenge.getRequiredExperience())));
+ icon = new ItemStack(Material.EXPERIENCE_BOTTLE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new NumberGUI(this.user, this.challenge.getRequiredExperience(), 0, (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRequiredExperience(value);
+ }
+
+ this.build();
+ });
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REMOVE_EXPERIENCE:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.remove-exp");
+
+ if (this.challenge.isTakeExperience())
+ {
+ description = Collections.singletonList(this.user.getTranslation("challenges.gui.admin.descriptions.enabled"));
+ }
+ else
+ {
+ description = Collections.singletonList(this.user.getTranslation("challenges.gui.admin.descriptions.disabled"));
+ }
+
+ icon = new ItemStack(Material.LEVER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.challenge.setTakeExperience(!this.challenge.isTakeExperience());
+
+ this.build();
+ return true;
+ };
+ glow = this.challenge.isTakeExperience();
+ break;
+ }
+ case REQUIRED_LEVEL:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.required-level");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.required-level",
+ "[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(), (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRequiredIslandLevel(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ }
+ else
+ {
+ icon = new ItemStack(Material.BARRIER);
+ clickHandler = null;
+ }
+
+ glow = false;
+ break;
+ }
+ case REQUIRED_MONEY:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.required-money");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.required-money",
+ "[value]",
+ Integer.toString(this.challenge.getRequiredMoney())));
+
+ if (this.addon.isEconomyProvided())
+ {
+ icon = new ItemStack(Material.GOLD_INGOT);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new NumberGUI(this.user, this.challenge.getRequiredMoney(), 0, (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRequiredMoney(value);
+ }
+
+ this.build();
+ });
+ return true;
+ };
+ }
+ else
+ {
+ icon = new ItemStack(Material.BARRIER);
+ clickHandler = null;
+ }
+
+ glow = false;
+ break;
+ }
+ case REMOVE_MONEY:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.remove-money");
+
+ if (this.challenge.isTakeMoney())
+ {
+ description = Collections.singletonList(this.user
+ .getTranslation("challenges.gui.admin.descriptions.enabled"));
+ }
+ else
+ {
+ description = Collections.singletonList(this.user
+ .getTranslation("challenges.gui.admin.descriptions.disabled"));
+ }
+
+ if (this.addon.isEconomyProvided())
+ {
+ icon = new ItemStack(Material.LEVER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.challenge.setTakeMoney(!this.challenge.isTakeMoney());
+
+ this.build();
+ return true;
+ };
+ }
+ else
+ {
+ icon = new ItemStack(Material.BARRIER);
+ clickHandler = null;
+ }
+
+ glow = this.challenge.isTakeMoney();
+ break;
+ }
+
+ case REWARD_TEXT:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.reward-text");
+ description = Collections.singletonList(this.challenge.getRewardText());
+ 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;
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REWARD_ITEM:
+ {
+ List values = new ArrayList<>(this.challenge.getRewardItems().size());
+
+ for (ItemStack itemStack : this.challenge.getRewardItems())
+ {
+ values.add(itemStack.getType().name() + " " + itemStack.getAmount());
+ }
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.reward-items");
+ description = values;
+ icon = new ItemStack(Material.CHEST);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new ItemSwitchGUI(this.user, this.challenge.getRewardItems(), (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRewardItems(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REWARD_EXPERIENCE:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.reward-exp");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.reward-exp",
+ "[value]",
+ Integer.toString(this.challenge.getRewardExperience())));
+ icon = new ItemStack(Material.EXPERIENCE_BOTTLE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new NumberGUI(this.user, this.challenge.getRewardExperience(), 0, (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRewardExperience(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REWARD_MONEY:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.reward-money");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.reward-money",
+ "[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, (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRewardMoney(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ }
+ else
+ {
+ icon = new ItemStack(Material.BARRIER);
+ clickHandler = null;
+ }
+
+ glow = false;
+ break;
+ }
+ case REWARD_COMMANDS:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.reward-command");
+ description = this.challenge.getRewardCommands();
+ icon = new ItemStack(Material.COMMAND_BLOCK);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new StringListGUI(this.user, this.challenge.getRewardCommands(), (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRewardCommands(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+
+ case REPEATABLE:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.repeatable");
+
+ if (this.challenge.isRepeatable())
+ {
+ description = Collections.singletonList(this.user.getTranslation("challenges.gui.admin.descriptions.enabled"));
+ }
+ else
+ {
+ description = Collections.singletonList(this.user.getTranslation("challenges.gui.admin.descriptions.disabled"));
+ }
+
+ icon = new ItemStack(Material.LEVER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.challenge.setRepeatable(!this.challenge.isRepeatable());
+
+ this.build();
+ return true;
+ };
+ glow = this.challenge.isRepeatable();
+ break;
+ }
+ case REPEAT_COUNT:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.repeat-count");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.repeat-count",
+ "[value]",
+ Integer.toString(this.challenge.getMaxTimes())));
+ icon = new ItemStack(Material.COBBLESTONE_WALL);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new NumberGUI(this.user, this.challenge.getMaxTimes(), 0, (status, value) -> {
+ if (status)
+ {
+ this.challenge.setMaxTimes(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+
+ case REPEAT_REWARD_TEXT:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.repeat-reward-text");
+ description = Collections.singletonList(this.challenge.getRepeatRewardText());
+ 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;
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REPEAT_REWARD_ITEM:
+ {
+ List values = new ArrayList<>(this.challenge.getRepeatItemReward().size());
+
+ for (ItemStack itemStack : this.challenge.getRepeatItemReward())
+ {
+ values.add(itemStack.getType().name() + " " + itemStack.getAmount());
+ }
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.repeat-reward-items");
+ description = values;
+ icon = new ItemStack(Material.TRAPPED_CHEST);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new ItemSwitchGUI(this.user, this.challenge.getRepeatItemReward(), (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRepeatItemReward(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REPEAT_REWARD_EXPERIENCE:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.repeat-reward-exp");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.repeat-reward-exp",
+ "[value]",
+ Integer.toString(this.challenge.getRepeatExperienceReward())));
+ icon = new ItemStack(Material.GLASS_BOTTLE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new NumberGUI(this.user, this.challenge.getRepeatExperienceReward(), 0, (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRepeatExperienceReward(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REPEAT_REWARD_MONEY:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.repeat-reward-money");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.repeat-reward-money",
+ "[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,
+ (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRepeatMoneyReward(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ }
+ else
+ {
+ icon = new ItemStack(Material.BARRIER);
+ clickHandler = null;
+ }
+
+ glow = false;
+ break;
+ }
+ case REPEAT_REWARD_COMMANDS:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.repeat-reward-command");
+ description = this.challenge.getRepeatRewardCommands();
+ icon = new ItemStack(Material.COMMAND_BLOCK);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new StringListGUI(this.user, this.challenge.getRepeatRewardCommands(), (status, value) -> {
+ if (status)
+ {
+ this.challenge.setRepeatRewardCommands(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ default:
+ return null;
+ }
+
+ return new PanelItem(icon, name, GuiUtils.stringSplit(description), glow, clickHandler, false);
+ }
+
+
+ /**
+ * This method returns next challenge type from given.
+ * @param type Given challenge type.
+ * @return Next Challenge Type.
+ */
+ private Challenge.ChallengeType getNextType(Challenge.ChallengeType type)
+ {
+ Challenge.ChallengeType[] values = Challenge.ChallengeType.values();
+
+ for (int i = 0; i < values.length; i++)
+ {
+ if (values[i].equals(type))
+ {
+ if (i + 1 == values.length)
+ {
+ return values[0];
+ }
+ else
+ {
+ return values[i + 1];
+ }
+ }
+ }
+
+ return type;
+ }
+
+
+ /**
+ * This method returns previous challenge type from given.
+ * @param type Given challenge type.
+ * @return Previous Challenge Type.
+ */
+ private Challenge.ChallengeType getPreviousType(Challenge.ChallengeType type)
+ {
+ Challenge.ChallengeType[] values = Challenge.ChallengeType.values();
+
+ for (int i = 0; i < values.length; i++)
+ {
+ if (values[i].equals(type))
+ {
+ if (i > 0)
+ {
+ return values[i - 1];
+ }
+ else
+ {
+ return values[values.length - 1];
+ }
+ }
+ }
+
+ return type;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Enums
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Represents different types of menus
+ */
+ private enum MenuType
+ {
+ PROPERTIES,
+ REQUIREMENTS,
+ REWARDS
+ }
+
+
+ /**
+ * Represents different buttons that could be in menus.
+ */
+ private enum Button
+ {
+ NAME,
+ TYPE,
+ DEPLOYED,
+ ICON,
+ DESCRIPTION,
+ ORDER,
+ ENVIRONMENT,
+ REMOVE_ON_COMPLETE,
+
+ REQUIRED_ENTITIES,
+ REMOVE_ENTITIES,
+ REQUIRED_BLOCKS,
+ REMOVE_BLOCKS,
+ SEARCH_RADIUS,
+ REQUIRED_PERMISSIONS,
+ REQUIRED_ITEMS,
+ REMOVE_ITEMS,
+ REQUIRED_EXPERIENCE,
+ REMOVE_EXPERIENCE,
+ REQUIRED_LEVEL,
+ REQUIRED_MONEY,
+ REMOVE_MONEY,
+
+ REWARD_TEXT,
+ REWARD_ITEM,
+ REWARD_EXPERIENCE,
+ REWARD_MONEY,
+ REWARD_COMMANDS,
+
+ REPEATABLE,
+ REPEAT_COUNT,
+
+ REPEAT_REWARD_TEXT,
+ REPEAT_REWARD_ITEM,
+ REPEAT_REWARD_EXPERIENCE,
+ REPEAT_REWARD_MONEY,
+ REPEAT_REWARD_COMMANDS,
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Variable holds challenge thats needs editing.
+ */
+ private Challenge challenge;
+
+ /**
+ * Variable holds current active menu.
+ */
+ private MenuType currentMenuType;
+}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/challenges/panel/admin/EditLevelGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/EditLevelGUI.java
new file mode 100644
index 0000000..75c7159
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/admin/EditLevelGUI.java
@@ -0,0 +1,648 @@
+package world.bentobox.challenges.panel.admin;
+
+
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.inventory.ItemStack;
+import java.util.ArrayList;
+import java.util.Collections;
+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;
+import world.bentobox.bentobox.api.user.User;
+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.panel.CommonGUI;
+import world.bentobox.challenges.panel.util.ItemSwitchGUI;
+import world.bentobox.challenges.panel.util.NumberGUI;
+import world.bentobox.challenges.panel.util.SelectChallengeGUI;
+import world.bentobox.challenges.panel.util.StringListGUI;
+import world.bentobox.challenges.utils.GuiUtils;
+
+
+/**
+ * This class contains all necessary elements to create Levels Edit GUI.
+*/
+public class EditLevelGUI extends CommonGUI
+{
+// ---------------------------------------------------------------------
+// Section: Constructors
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ * @param challengeLevel ChallengeLevel that must be edited.
+ */
+ public EditLevelGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ ChallengeLevel challengeLevel,
+ String topLabel,
+ String permissionPrefix)
+ {
+ this(addon, world, user, challengeLevel, topLabel, permissionPrefix, null);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ * @param challengeLevel ChallengeLevel that must be edited.
+ */
+ public EditLevelGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ ChallengeLevel challengeLevel,
+ String topLabel,
+ String permissionPrefix,
+ CommonGUI parentGUI)
+ {
+ super(addon, world, user, topLabel, permissionPrefix, parentGUI);
+ this.challengeLevel = challengeLevel;
+ this.currentMenuType = MenuType.PROPERTIES;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method builds all necessary elements in GUI panel.
+ */
+ @Override
+ public void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).name(
+ this.user.getTranslation("challenges.gui.admin.edit-level-title"));
+
+ GuiUtils.fillBorder(panelBuilder);
+
+ panelBuilder.item(2, this.createMenuButton(MenuType.PROPERTIES));
+ panelBuilder.item(4, this.createMenuButton(MenuType.REWARDS));
+ panelBuilder.item(6, this.createMenuButton(MenuType.CHALLENGES));
+
+ if (this.currentMenuType.equals(MenuType.PROPERTIES))
+ {
+ this.buildMainPropertiesPanel(panelBuilder);
+ }
+ else if (this.currentMenuType.equals(MenuType.CHALLENGES))
+ {
+ this.buildChallengesPanel(panelBuilder);
+ }
+ else if (this.currentMenuType.equals(MenuType.REWARDS))
+ {
+ this.buildRewardsPanel(panelBuilder);
+ }
+
+ panelBuilder.item(44, this.returnButton);
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This class populate LevelsEditGUI with main level settings.
+ * @param panelBuilder PanelBuilder where icons must be added.
+ */
+ private void buildMainPropertiesPanel(PanelBuilder panelBuilder)
+ {
+ panelBuilder.item(10, this.createButton(Button.NAME));
+
+ panelBuilder.item(19, this.createButton(Button.ICON));
+ panelBuilder.item(22, this.createButton(Button.UNLOCK_MESSAGE));
+ panelBuilder.item(25, this.createButton(Button.ORDER));
+
+ panelBuilder.item(31, this.createButton(Button.WAIVER_AMOUNT));
+ }
+
+
+ /**
+ * This class populate LevelsEditGUI with level rewards.
+ * @param panelBuilder PanelBuilder where icons must be added.
+ */
+ private void buildRewardsPanel(PanelBuilder panelBuilder)
+ {
+ panelBuilder.item(12, this.createButton(Button.REWARD_DESCRIPTION));
+ panelBuilder.item(21, this.createButton(Button.REWARD_COMMANDS));
+
+ panelBuilder.item(13, this.createButton(Button.REWARD_ITEM));
+ panelBuilder.item(22, this.createButton(Button.REWARD_EXPERIENCE));
+ panelBuilder.item(31, this.createButton(Button.REWARD_MONEY));
+ }
+
+
+ /**
+ * This class populate LevelsEditGUI with level challenges.
+ * @param panelBuilder PanelBuilder where icons must be added.
+ */
+ private void buildChallengesPanel(PanelBuilder panelBuilder)
+ {
+ List challengeList = this.addon.getChallengesManager().getLevelChallenges(this.challengeLevel);
+
+ final int MAX_ELEMENTS = 21;
+
+ if (this.pageIndex < 0)
+ {
+ this.pageIndex = challengeList.size() / MAX_ELEMENTS;
+ }
+ else if (this.pageIndex > (challengeList.size() / MAX_ELEMENTS))
+ {
+ this.pageIndex = 0;
+ }
+
+ int challengeIndex = MAX_ELEMENTS * this.pageIndex;
+
+ // I want first row to be only for navigation and return button.
+ int index = 10;
+
+ while (challengeIndex < ((this.pageIndex + 1) * MAX_ELEMENTS) &&
+ challengeIndex < challengeList.size() &&
+ index < 36)
+ {
+ if (!panelBuilder.slotOccupied(index))
+ {
+ panelBuilder.item(index, this.createChallengeIcon(challengeList.get(challengeIndex++)));
+ }
+
+ index++;
+ }
+
+ // Navigation buttons only if necessary
+ if (challengeList.size() > MAX_ELEMENTS)
+ {
+ panelBuilder.item(18, this.getButton(CommonButtons.PREVIOUS));
+ panelBuilder.item(26, this.getButton(CommonButtons.NEXT));
+ }
+
+ panelBuilder.item(39, this.createButton(Button.ADD_CHALLENGE));
+ panelBuilder.item(41, this.createButton(Button.REMOVE_CHALLENGE));
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Other methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method creates top menu buttons, that allows to switch "tabs".
+ * @param menuType Menu Type which button must be constructed.
+ * @return PanelItem that represents given menu type.
+ */
+ private PanelItem createMenuButton(MenuType menuType)
+ {
+ ItemStack icon;
+ String name;
+ List description;
+ boolean glow;
+ PanelItem.ClickHandler clickHandler;
+
+ switch (menuType)
+ {
+ case PROPERTIES:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.properties");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.CRAFTING_TABLE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.currentMenuType = MenuType.PROPERTIES;
+ this.build();
+
+ return true;
+ };
+ glow = this.currentMenuType.equals(MenuType.PROPERTIES);
+ break;
+ }
+ case CHALLENGES:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.challenges");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.RAIL);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.currentMenuType = MenuType.CHALLENGES;
+ this.build();
+
+ return true;
+ };
+ glow = this.currentMenuType.equals(MenuType.CHALLENGES);
+ break;
+ }
+ case REWARDS:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.rewards");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.DROPPER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.currentMenuType = MenuType.REWARDS;
+ this.build();
+
+ return true;
+ };
+ glow = this.currentMenuType.equals(MenuType.REWARDS);
+ break;
+ }
+ default:
+ return null;
+ }
+
+ return new PanelItem(icon, name, GuiUtils.stringSplit(description), glow, clickHandler, false);
+ }
+
+
+ /**
+ * This method creates given challenge icon. On click it should open Edit Challenge GUI.
+ * @param challenge Challenge which icon must be created.
+ * @return PanelItem that represents given challenge.
+ */
+ private PanelItem createChallengeIcon(Challenge challenge)
+ {
+ return new PanelItemBuilder().
+ name(challenge.getFriendlyName()).
+ description(GuiUtils.stringSplit(challenge.getDescription())).
+ icon(challenge.getIcon()).
+ clickHandler((panel, user1, clickType, slot) -> {
+ // Open challenges edit screen.
+ new EditChallengeGUI(this.addon,
+ this.world,
+ this.user,
+ challenge,
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+ return true;
+ }).
+ glow(!challenge.isDeployed()).
+ build();
+
+ }
+
+
+ /**
+ * This method creates buttons for default main menu.
+ * @param button Button which panel item must be created.
+ * @return PanelItem that represents given button.
+ */
+ private PanelItem createButton(Button button)
+ {
+ ItemStack icon;
+ String name;
+ List description;
+ boolean glow;
+ PanelItem.ClickHandler clickHandler;
+
+ switch (button)
+ {
+ case NAME:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.name");
+ description = Collections.singletonList(this.challengeLevel.getFriendlyName());
+ icon = new ItemStack(Material.DROPPER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new AnvilGUI(this.addon.getPlugin(),
+ this.user.getPlayer(),
+ this.challengeLevel.getFriendlyName(),
+ (player, reply) -> {
+ this.challengeLevel.setFriendlyName(reply);
+ this.build();
+ return reply;
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case ICON:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.icon");
+ description = Collections.emptyList();
+ icon = this.challengeLevel.getIcon();
+ clickHandler = (panel, user, clickType, slot) -> {
+ new AnvilGUI(this.addon.getPlugin(),
+ this.user.getPlayer(),
+ this.challengeLevel.getIcon().getType().name(),
+ (player, reply) -> {
+ Material material = Material.getMaterial(reply);
+
+ if (material != null)
+ {
+ this.challengeLevel.setIcon(new ItemStack(material));
+ this.build();
+ }
+ else
+ {
+ this.user.sendMessage("challenges.errors.wrong-icon", "[value]", reply);
+ }
+
+ return reply;
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case UNLOCK_MESSAGE:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.description");
+ description = Collections.singletonList(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;
+ });
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case ORDER:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.order");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.order",
+ "[value]",
+ Integer.toString(this.challengeLevel.getOrder())));
+ icon = new ItemStack(Material.DROPPER);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new NumberGUI(this.user, this.challengeLevel.getOrder(), -1, 54, (status, value) -> {
+ if (status)
+ {
+ this.challengeLevel.setOrder(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case WAIVER_AMOUNT:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.waiver-amount");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.waiver-amount",
+ "[value]",
+ Integer.toString(this.challengeLevel.getWaiverAmount())));
+ icon = new ItemStack(Material.REDSTONE_TORCH);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new NumberGUI(this.user, this.challengeLevel.getWaiverAmount(), 0, (status, value) -> {
+ if (status)
+ {
+ this.challengeLevel.setWaiverAmount(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+
+ case REWARD_DESCRIPTION:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.reward-text");
+ description = Collections.singletonList(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;
+ });
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REWARD_ITEM:
+ {
+ List values = new ArrayList<>(this.challengeLevel.getRewardItems().size());
+
+ for (ItemStack itemStack : this.challengeLevel.getRewardItems())
+ {
+ values.add(itemStack.getType().name() + " " + itemStack.getAmount());
+ }
+
+ name = this.user.getTranslation("challenges.gui.admin.buttons.reward-items");
+ description = values;
+ icon = new ItemStack(Material.CHEST);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new ItemSwitchGUI(this.user, this.challengeLevel.getRewardItems(), (status, value) -> {
+ if (status)
+ {
+ this.challengeLevel.setRewardItems(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REWARD_EXPERIENCE:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.reward-exp");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.reward-exp",
+ "[value]",
+ Integer.toString(this.challengeLevel.getRewardExperience())));
+ icon = new ItemStack(Material.EXPERIENCE_BOTTLE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new NumberGUI(this.user, this.challengeLevel.getRewardExperience(), 0, (status, value) -> {
+ if (status)
+ {
+ this.challengeLevel.setRewardExperience(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REWARD_MONEY:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.reward-money");
+ description = Collections.singletonList(
+ this.user.getTranslation("challenges.gui.admin.descriptions.reward-money",
+ "[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, (status, value) -> {
+ if (status)
+ {
+ this.challengeLevel.setRewardMoney(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ }
+ else
+ {
+ icon = new ItemStack(Material.BARRIER);
+ clickHandler = null;
+ }
+
+ glow = false;
+ break;
+ }
+ case REWARD_COMMANDS:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.reward-command");
+ description = this.challengeLevel.getRewardCommands();
+ icon = new ItemStack(Material.COMMAND_BLOCK);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new StringListGUI(this.user, this.challengeLevel.getRewardCommands(), (status, value) -> {
+ if (status)
+ {
+ this.challengeLevel.setRewardCommands(value);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+
+ case ADD_CHALLENGE:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.add-challenge");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.WATER_BUCKET);
+ clickHandler = (panel, user, clickType, slot) -> {
+ ChallengesManager manager = this.addon.getChallengesManager();
+
+ // Get all challenge that is not in current challenge.
+ List challengeList = manager.getAllChallenges(this.world);
+ challengeList.removeAll(manager.getLevelChallenges(this.challengeLevel));
+
+ new SelectChallengeGUI(this.user, challengeList, (status, value) -> {
+ if (status)
+ {
+ manager.addChallengeToLevel(value, this.challengeLevel);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case REMOVE_CHALLENGE:
+ {
+ name = this.user.getTranslation("challenges.gui.admin.buttons.remove-challenge");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.LAVA_BUCKET);
+ clickHandler = (panel, user, clickType, slot) -> {
+ ChallengesManager manager = this.addon.getChallengesManager();
+
+ new SelectChallengeGUI(this.user, manager.getLevelChallenges(this.challengeLevel), (status, value) -> {
+ if (status)
+ {
+ manager.removeChallengeFromLevel(value, this.challengeLevel);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ default:
+ return null;
+ }
+
+ return new PanelItem(icon, name, GuiUtils.stringSplit(description), glow, clickHandler, false);
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Enums
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Represents different buttons that could be in menus.
+ */
+ private enum Button
+ {
+ NAME,
+ ICON,
+ UNLOCK_MESSAGE,
+ ORDER,
+ WAIVER_AMOUNT,
+
+ REWARD_DESCRIPTION,
+ REWARD_ITEM,
+ REWARD_EXPERIENCE,
+ REWARD_MONEY,
+ REWARD_COMMANDS,
+
+ ADD_CHALLENGE,
+ REMOVE_CHALLENGE
+ }
+
+
+ /**
+ * Represents different types of menus
+ */
+ private enum MenuType
+ {
+ PROPERTIES,
+ CHALLENGES,
+ REWARDS
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ /**
+ * This variable holds current challenge level that is in editing GUI.
+ */
+ private ChallengeLevel challengeLevel;
+
+ /**
+ * Variable holds current active menu.
+ */
+ private MenuType currentMenuType;
+}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/challenges/panel/admin/EditSettingsGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/EditSettingsGUI.java
new file mode 100644
index 0000000..984e9ce
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/admin/EditSettingsGUI.java
@@ -0,0 +1,141 @@
+package world.bentobox.challenges.panel.admin;
+
+
+import org.bukkit.Material;
+import org.bukkit.World;
+
+import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
+import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
+import world.bentobox.bentobox.api.user.User;
+import world.bentobox.challenges.ChallengesAddon;
+import world.bentobox.challenges.panel.CommonGUI;
+import world.bentobox.challenges.utils.GuiUtils;
+
+
+/**
+ * This Class creates GUI that allows to change Challenges Addon Settings via in-game
+ * menu.
+ */
+public class EditSettingsGUI extends CommonGUI
+{
+// ---------------------------------------------------------------------
+// Section: Constructors
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public EditSettingsGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ String topLabel,
+ String permissionPrefix)
+ {
+ this(addon, world, user, topLabel, permissionPrefix, null);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public EditSettingsGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ String topLabel,
+ String permissionPrefix,
+ CommonGUI parentGUI)
+ {
+ super(addon, world, user, topLabel, permissionPrefix, parentGUI);
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ @Override
+ public void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).name(
+ this.user.getTranslation("challenges.gui.admin.settings-title"));
+
+ GuiUtils.fillBorder(panelBuilder);
+
+ // resetChallenges
+ panelBuilder.item(19, new PanelItemBuilder().
+ name(this.user.getTranslation("challenges.gui.admin.buttons.reset")).
+ description(GuiUtils.stringSplit(this.user.getTranslation("challenges.gui.admin.descriptions.reset"))).
+ icon(Material.LAVA_BUCKET).
+ clickHandler((panel, user1, clickType, i) -> {
+ this.addon.getChallengesSettings().setResetChallenges(
+ !this.addon.getChallengesSettings().isResetChallenges());
+ this.build();
+ return true;
+ }).
+ glow(this.addon.getChallengesSettings().isResetChallenges()).
+ build());
+
+ // broadcastMessages
+ panelBuilder.item(20, new PanelItemBuilder().
+ name(this.user.getTranslation("challenges.gui.admin.buttons.broadcast")).
+ description(GuiUtils.stringSplit(this.user.getTranslation("challenges.gui.admin.descriptions.broadcast"))).
+ icon(Material.JUKEBOX).
+ clickHandler((panel, user1, clickType, i) -> {
+ this.addon.getChallengesSettings().setBroadcastMessages(
+ !this.addon.getChallengesSettings().isBroadcastMessages());
+ this.build();
+ return true;
+ }).
+ glow(this.addon.getChallengesSettings().isBroadcastMessages()).
+ build());
+
+ // removeCompleteOneTimeChallenges
+ panelBuilder.item(21, new PanelItemBuilder().
+ name(this.user.getTranslation("challenges.gui.admin.buttons.remove-on-complete")).
+ description(GuiUtils.stringSplit(this.user.getTranslation("challenges.gui.admin.descriptions.remove-on-complete"))).
+ icon(Material.MAGMA_BLOCK).
+ clickHandler((panel, user1, clickType, i) -> {
+ this.addon.getChallengesSettings().setRemoveCompleteOneTimeChallenges(
+ !this.addon.getChallengesSettings().isRemoveCompleteOneTimeChallenges());
+ this.build();
+ return true;
+ }).
+ glow(this.addon.getChallengesSettings().isRemoveCompleteOneTimeChallenges()).
+ build());
+
+ // addCompletedGlow
+ panelBuilder.item(22, new PanelItemBuilder().
+ name(this.user.getTranslation("challenges.gui.admin.buttons.glow")).
+ description(GuiUtils.stringSplit(this.user.getTranslation("challenges.gui.admin.descriptions.glow"))).
+ icon(Material.GLOWSTONE).
+ clickHandler((panel, user1, clickType, i) -> {
+ this.addon.getChallengesSettings().setAddCompletedGlow(
+ !this.addon.getChallengesSettings().isAddCompletedGlow());
+ this.build();
+ return true;
+ }).
+ glow(this.addon.getChallengesSettings().isAddCompletedGlow()).
+ build());
+
+ // freeChallengesAtTheTop
+ panelBuilder.item(23, new PanelItemBuilder().
+ name(this.user.getTranslation("challenges.gui.admin.buttons.free-challenges")).
+ description(GuiUtils.stringSplit(this.user.getTranslation("challenges.gui.admin.descriptions.free-challenges"))).
+ icon(Material.FILLED_MAP).
+ clickHandler((panel, user1, clickType, i) -> {
+ this.addon.getChallengesSettings().setFreeChallengesFirst(
+ !this.addon.getChallengesSettings().isFreeChallengesFirst());
+ this.build();
+ return true;
+ }).
+ glow(this.addon.getChallengesSettings().isFreeChallengesFirst()).
+ build());
+
+ // Return Button
+ panelBuilder.item(44, this.returnButton);
+
+ panelBuilder.build();
+ }
+}
diff --git a/src/main/java/world/bentobox/challenges/panel/admin/ListChallengesGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/ListChallengesGUI.java
new file mode 100644
index 0000000..ad76912
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/admin/ListChallengesGUI.java
@@ -0,0 +1,194 @@
+package world.bentobox.challenges.panel.admin;
+
+
+import org.bukkit.Material;
+import org.bukkit.World;
+import java.util.List;
+
+import world.bentobox.bentobox.api.panels.PanelItem;
+import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
+import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
+import world.bentobox.bentobox.api.user.User;
+import world.bentobox.challenges.ChallengesAddon;
+import world.bentobox.challenges.database.object.Challenge;
+import world.bentobox.challenges.panel.CommonGUI;
+import world.bentobox.challenges.panel.util.ConfirmationGUI;
+import world.bentobox.challenges.utils.GuiUtils;
+
+
+/**
+ * This class contains all necessary elements to create GUI that lists all challenges.
+ * It allows to edit them or remove, depending on given input mode.
+ */
+public class ListChallengesGUI extends CommonGUI
+{
+ // ---------------------------------------------------------------------
+// Section: Constructor
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ * @param mode - mode that indicate what should do icon clicking.
+ */
+ public ListChallengesGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ Mode mode,
+ String topLabel,
+ String permissionPrefix)
+ {
+ this(addon, world, user, mode, topLabel, permissionPrefix, null);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ * @param mode - mode that indicate what should do icon clicking.
+ */
+ public ListChallengesGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ Mode mode,
+ String topLabel,
+ String permissionPrefix,
+ CommonGUI parentGUI)
+ {
+ super(addon, world, user, topLabel, permissionPrefix, parentGUI);
+ this.currentMode = mode;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).name(
+ this.user.getTranslation("challenges.gui.admin.choose-challenge-title"));
+
+ if (this.currentMode.equals(Mode.DELETE))
+ {
+ GuiUtils.fillBorder(panelBuilder, Material.RED_STAINED_GLASS_PANE);
+ }
+ else
+ {
+ GuiUtils.fillBorder(panelBuilder);
+ }
+
+ List challengeList = this.addon.getChallengesManager().getAllChallenges(this.world);
+
+ final int MAX_ELEMENTS = 21;
+
+ if (this.pageIndex < 0)
+ {
+ this.pageIndex = challengeList.size() / MAX_ELEMENTS;
+ }
+ else if (this.pageIndex > (challengeList.size() / MAX_ELEMENTS))
+ {
+ this.pageIndex = 0;
+ }
+
+ int challengeIndex = MAX_ELEMENTS * this.pageIndex;
+
+ // I want first row to be only for navigation and return button.
+ int index = 10;
+
+ while (challengeIndex < ((this.pageIndex + 1) * MAX_ELEMENTS) &&
+ challengeIndex < challengeList.size() &&
+ index < 36)
+ {
+ if (!panelBuilder.slotOccupied(index))
+ {
+ panelBuilder.item(index, this.createChallengeIcon(challengeList.get(challengeIndex++)));
+ }
+
+ index++;
+ }
+
+ // Navigation buttons only if necessary
+ if (challengeList.size() > MAX_ELEMENTS)
+ {
+ panelBuilder.item(18, this.getButton(CommonButtons.PREVIOUS));
+ panelBuilder.item(26, this.getButton(CommonButtons.NEXT));
+ }
+
+ panelBuilder.item(44, this.returnButton);
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method creates button for given challenge.
+ * @param challenge Challenge which button must be created.
+ * @return Challenge button.
+ */
+ private PanelItem createChallengeIcon(Challenge challenge)
+ {
+ PanelItemBuilder itemBuilder = new PanelItemBuilder().
+ name(challenge.getFriendlyName()).
+ description(GuiUtils.stringSplit(challenge.getDescription())).
+ icon(challenge.getIcon()).
+ glow(challenge.isDeployed());
+
+ if (this.currentMode.equals(Mode.EDIT))
+ {
+ itemBuilder.clickHandler((panel, user1, clickType, i) -> {
+ new EditChallengeGUI(this.addon,
+ this.world,
+ this.user,
+ challenge,
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+ return true;
+ });
+ }
+ else if (this.currentMode.equals(Mode.DELETE))
+ {
+ itemBuilder.clickHandler((panel, user1, clickType, i) -> {
+ new ConfirmationGUI(this.user, value -> {
+ if (value)
+ {
+ this.addon.getChallengesManager().deleteChallenge(challenge);
+ }
+ });
+ return true;
+ });
+ }
+
+ return itemBuilder.build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Enums
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Mode in which gui icons should processed.
+ */
+ public enum Mode
+ {
+ EDIT,
+ DELETE
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ /**
+ * Current mode in which icons will act.
+ */
+ private Mode currentMode;
+}
diff --git a/src/main/java/world/bentobox/challenges/panel/admin/ListLevelsGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/ListLevelsGUI.java
new file mode 100644
index 0000000..5267d10
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/admin/ListLevelsGUI.java
@@ -0,0 +1,195 @@
+package world.bentobox.challenges.panel.admin;
+
+
+import org.bukkit.Material;
+import org.bukkit.World;
+import java.util.List;
+
+import world.bentobox.bentobox.api.panels.PanelItem;
+import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
+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.ChallengeLevel;
+import world.bentobox.challenges.panel.CommonGUI;
+import world.bentobox.challenges.panel.util.ConfirmationGUI;
+import world.bentobox.challenges.utils.GuiUtils;
+
+
+/**
+ * This class creates GUI that lists all Levels. Clicking on Level icon will be processed
+ * by input mode.
+ */
+public class ListLevelsGUI extends CommonGUI
+{
+// ---------------------------------------------------------------------
+// Section: Constructor
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ * @param mode - mode that indicate what should do icon clicking.
+ */
+ public ListLevelsGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ Mode mode,
+ String topLabel,
+ String permissionPrefix)
+ {
+ this(addon, world, user, mode, topLabel, permissionPrefix, null);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ * @param mode - mode that indicate what should do icon clicking.
+ */
+ public ListLevelsGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ Mode mode,
+ String topLabel,
+ String permissionPrefix,
+ CommonGUI parentGUI)
+ {
+ super(addon, world, user, topLabel, permissionPrefix, parentGUI);
+ this.currentMode = mode;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).name(
+ this.user.getTranslation("challenges.gui.admin.choose-level-title"));
+
+ if (this.currentMode.equals(Mode.DELETE))
+ {
+ GuiUtils.fillBorder(panelBuilder, Material.RED_STAINED_GLASS_PANE);
+ }
+ else
+ {
+ GuiUtils.fillBorder(panelBuilder);
+ }
+
+ List levelList = this.addon.getChallengesManager().getLevels(this.world);
+
+ final int MAX_ELEMENTS = 21;
+
+ if (this.pageIndex < 0)
+ {
+ this.pageIndex = levelList.size() / MAX_ELEMENTS;
+ }
+ else if (this.pageIndex > (levelList.size() / MAX_ELEMENTS))
+ {
+ this.pageIndex = 0;
+ }
+
+ int levelIndex = MAX_ELEMENTS * this.pageIndex;
+
+ // I want first row to be only for navigation and return button.
+ int index = 10;
+
+ while (levelIndex < ((this.pageIndex + 1) * MAX_ELEMENTS) &&
+ levelIndex < levelList.size() &&
+ index < 36)
+ {
+ if (!panelBuilder.slotOccupied(index))
+ {
+ panelBuilder.item(index, this.createLevelIcon(levelList.get(levelIndex++)));
+ }
+
+ index++;
+ }
+
+ // Navigation buttons only if necessary
+ if (levelList.size() > MAX_ELEMENTS)
+ {
+ panelBuilder.item(18, this.getButton(CommonButtons.PREVIOUS));
+ panelBuilder.item(26, this.getButton(CommonButtons.NEXT));
+ }
+
+ panelBuilder.item(44, this.returnButton);
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method creates button for given level
+ * @param challengeLevel Level which button must be created.
+ * @return Level button.
+ */
+ private PanelItem createLevelIcon(ChallengeLevel challengeLevel)
+ {
+ PanelItemBuilder itemBuilder = new PanelItemBuilder().
+ name(challengeLevel.getFriendlyName()).
+ description(GuiUtils.stringSplit(challengeLevel.getUnlockMessage())).
+ icon(challengeLevel.getIcon()).
+ glow(false);
+
+ if (this.currentMode.equals(Mode.EDIT))
+ {
+ itemBuilder.clickHandler((panel, user1, clickType, i) -> {
+ new EditLevelGUI(this.addon,
+ this.world,
+ this.user,
+ challengeLevel,
+ this.topLabel,
+ this.permissionPrefix,
+ this).build();
+ return true;
+ });
+ }
+ else if (this.currentMode.equals(Mode.DELETE))
+ {
+ itemBuilder.clickHandler((panel, user1, clickType, i) -> {
+ new ConfirmationGUI(this.user, value -> {
+ if (value)
+ {
+ this.addon.getChallengesManager().
+ deleteChallengeLevel(challengeLevel);
+ }
+ });
+ return true;
+ });
+ }
+
+ return itemBuilder.build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Enums
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Mode in which gui icons should processed.
+ */
+ public enum Mode
+ {
+ EDIT,
+ DELETE
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ /**
+ * Current mode in which icons will act.
+ */
+ private Mode currentMode;
+}
diff --git a/src/main/java/world/bentobox/challenges/panel/admin/ListUsersGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/ListUsersGUI.java
new file mode 100644
index 0000000..c7c5461
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/admin/ListUsersGUI.java
@@ -0,0 +1,299 @@
+package world.bentobox.challenges.panel.admin;
+
+
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+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.database.objects.Players;
+import world.bentobox.challenges.ChallengesAddon;
+import world.bentobox.challenges.ChallengesManager;
+import world.bentobox.challenges.panel.CommonGUI;
+import world.bentobox.challenges.panel.util.ConfirmationGUI;
+import world.bentobox.challenges.panel.util.SelectChallengeGUI;
+import world.bentobox.challenges.utils.GuiUtils;
+
+
+/**
+ * This class contains methods that allows to select specific user.
+ */
+public class ListUsersGUI extends CommonGUI
+{
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ /**
+ * List with players that should be in GUI.
+ */
+ private List onlineUsers;
+
+ /**
+ * Current operation mode.
+ */
+ private Mode operationMode;
+
+ /**
+ * Current index of view mode
+ */
+ private int modeIndex = 2;
+
+ /**
+ * This allows to switch which users should be in the list.
+ */
+ private enum ViewMode
+ {
+ ONLINE,
+ WITH_ISLAND,
+ IN_WORLD
+ }
+
+ /**
+ * This allows to decide what User Icon should do.
+ */
+ public enum Mode
+ {
+ COMPLETE,
+ RESET,
+ RESET_ALL
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Constructors
+// ---------------------------------------------------------------------
+
+
+ /**
+ * {@inheritDoc}
+ * @param operationMode Indicate what should happen on player icon click.
+ */
+ public ListUsersGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ Mode operationMode,
+ String topLabel,
+ String permissionPrefix)
+ {
+ this(addon, world, user, operationMode, topLabel, permissionPrefix, null);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ * @param operationMode Indicate what should happen on player icon click.
+ */
+ public ListUsersGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ Mode operationMode,
+ String topLabel,
+ String permissionPrefix,
+ CommonGUI parentPanel)
+ {
+ super(addon, world, user, topLabel, permissionPrefix, parentPanel);
+ this.onlineUsers = this.collectUsers(ViewMode.IN_WORLD);
+ this.operationMode = operationMode;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ @Override
+ public void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).name(
+ this.user.getTranslation("challenges.gui.admin.choose-user-title"));
+
+ GuiUtils.fillBorder(panelBuilder);
+
+ final int MAX_ELEMENTS = 21;
+
+ if (this.pageIndex < 0)
+ {
+ this.pageIndex = this.onlineUsers.size() / MAX_ELEMENTS;
+ }
+ else if (this.pageIndex > (this.onlineUsers.size() / MAX_ELEMENTS))
+ {
+ this.pageIndex = 0;
+ }
+
+ int playerIndex = MAX_ELEMENTS * this.pageIndex;
+
+ // I want first row to be only for navigation and return button.
+ int index = 10;
+
+ while (playerIndex < ((this.pageIndex + 1) * MAX_ELEMENTS) &&
+ playerIndex < this.onlineUsers.size() &&
+ index < 36)
+ {
+ if (!panelBuilder.slotOccupied(index))
+ {
+ panelBuilder.item(index, this.createPlayerIcon(this.onlineUsers.get(playerIndex++)));
+ }
+
+ index++;
+ }
+
+ // Add button that allows to toogle different player lists.
+ panelBuilder.item( 4, this.createToggleButton());
+
+ // Navigation buttons only if necessary
+ if (this.onlineUsers.size() > MAX_ELEMENTS)
+ {
+ panelBuilder.item(18, this.getButton(CommonButtons.PREVIOUS));
+ panelBuilder.item(26, this.getButton(CommonButtons.NEXT));
+ }
+
+ panelBuilder.item(44, this.returnButton);
+
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method creates button for given user. If user has island it will add valid click handler.
+ * @param player Player which button must be created.
+ * @return Player button.
+ */
+ private PanelItem createPlayerIcon(Player player)
+ {
+ if (this.addon.getIslands().hasIsland(this.world, player.getUniqueId()))
+ {
+ return new PanelItemBuilder().name(player.getName()).icon(player.getName()).clickHandler(
+ (panel, user1, clickType, slot) -> {
+ ChallengesManager manager = this.addon.getChallengesManager();
+
+ switch (this.operationMode)
+ {
+ case COMPLETE:
+ new SelectChallengeGUI(this.user, manager.getAllChallenges(this.world), (status, value) -> {
+ if (status)
+ {
+ manager.setChallengeComplete(User.getInstance(player), value);
+ }
+
+ this.build();
+ });
+ break;
+ case RESET:
+ new SelectChallengeGUI(this.user, manager.getAllChallenges(this.world), (status, value) -> {
+ if (status)
+ {
+ manager.resetChallenge(User.getInstance(player), value);
+ }
+
+ this.build();
+ });
+ break;
+ case RESET_ALL:
+ new ConfirmationGUI(this.user, status -> {
+ if (status)
+ {
+ manager.resetAllChallenges(this.user, this.world);
+ }
+ });
+ break;
+ }
+
+ return true;
+ }).build();
+ }
+ else
+ {
+ return new PanelItemBuilder().
+ name(player.getName()).
+ icon(Material.BARRIER).
+ description(GuiUtils.stringSplit(this.user.getTranslation("general.errors.player-has-no-island"))).
+ clickHandler((panel, user1, clickType, slot) -> false).
+ build();
+ }
+ }
+
+
+ /**
+ * This method collects users based on view mode.
+ * @param mode Given view mode.
+ * @return List with players in necessary view mode.
+ */
+ private List collectUsers(ViewMode mode)
+ {
+ if (mode.equals(ViewMode.ONLINE))
+ {
+ return new ArrayList<>(Bukkit.getOnlinePlayers());
+ }
+ else if (mode.equals(ViewMode.WITH_ISLAND))
+ {
+ return this.addon.getPlayers().getPlayers().stream().
+ filter(player -> this.addon.getIslands().getIsland(this.world, player.getPlayerUUID()) != null).
+ map(Players::getPlayer).
+ collect(Collectors.toList());
+ }
+ else
+ {
+ return new ArrayList<>(this.world.getPlayers());
+ }
+ }
+
+
+ /**
+ * This method creates Player List view Mode toggle button.
+ * @return Button that toggles through player view mode.
+ */
+ private PanelItem createToggleButton()
+ {
+ List values = new ArrayList<>(ViewMode.values().length);
+
+ for (int i = 0; i < ViewMode.values().length; i++)
+ {
+ values.add((this.modeIndex == i ? "&2" : "&c") +
+ this.user.getTranslation("challenges.gui.admin.descriptions." +
+ ViewMode.values()[i].name().toLowerCase()));
+ }
+
+ return new PanelItemBuilder().
+ name(this.user.getTranslation("challenges.gui.admin.buttons.toggle-users",
+ "[value]",
+ this.user.getTranslation("challenges.gui.admin.descriptions." + ViewMode.values()[this.modeIndex].name().toLowerCase()))).
+ description(GuiUtils.stringSplit(values)).
+ icon(Material.STONE_BUTTON).
+ clickHandler(
+ (panel, user1, clickType, slot) -> {
+ if (clickType.isRightClick())
+ {
+ this.modeIndex--;
+
+ if (this.modeIndex < 0)
+ {
+ this.modeIndex = ViewMode.values().length - 1;
+ }
+ }
+ else
+ {
+ this.modeIndex++;
+
+ if (this.modeIndex >= ViewMode.values().length)
+ {
+ this.modeIndex = 0;
+ }
+ }
+
+ this.onlineUsers = this.collectUsers(ViewMode.values()[this.modeIndex]);
+ this.pageIndex = 0;
+ this.build();
+ return true;
+ }).build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/challenges/panel/admin/ManageBlocksGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/ManageBlocksGUI.java
new file mode 100644
index 0000000..28ec03d
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/admin/ManageBlocksGUI.java
@@ -0,0 +1,225 @@
+package world.bentobox.challenges.panel.admin;
+
+
+import org.apache.commons.lang.WordUtils;
+import org.bukkit.Material;
+import org.bukkit.World;
+import java.util.*;
+
+import world.bentobox.bentobox.api.panels.PanelItem;
+import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
+import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
+import world.bentobox.bentobox.api.user.User;
+import world.bentobox.challenges.ChallengesAddon;
+import world.bentobox.challenges.panel.CommonGUI;
+import world.bentobox.challenges.panel.util.NumberGUI;
+import world.bentobox.challenges.panel.util.SelectBlocksGUI;
+import world.bentobox.challenges.utils.GuiUtils;
+
+
+/**
+ * This class allows to edit material that are in required material map.
+ */
+public class ManageBlocksGUI extends CommonGUI
+{
+ public ManageBlocksGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ Map materialMap,
+ String topLabel,
+ String permissionPrefix,
+ CommonGUI parentGUI)
+ {
+ super(addon, world, user, topLabel, permissionPrefix, parentGUI);
+ this.materialMap = materialMap;
+
+ this.materialList = new ArrayList<>(this.materialMap.keySet());
+
+ // Sort materials by their ordinal value.
+ this.materialList.sort(Comparator.comparing(Enum::ordinal));
+
+ this.selectedMaterials = new HashSet<>();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method builds all necessary elements in GUI panel.
+ */
+ @Override
+ public void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).
+ name(this.user.getTranslation("challenges.gui.admin.manage-blocks"));
+
+ // Create nice border.
+ GuiUtils.fillBorder(panelBuilder);
+
+ panelBuilder.item(3, this.createButton(Button.ADD));
+ panelBuilder.item(5, this.createButton(Button.REMOVE));
+
+ final int MAX_ELEMENTS = 21;
+
+ if (this.pageIndex < 0)
+ {
+ this.pageIndex = this.materialList.size() / MAX_ELEMENTS;
+ }
+ else if (this.pageIndex > (this.materialList.size() / MAX_ELEMENTS))
+ {
+ this.pageIndex = 0;
+ }
+
+ int entitiesIndex = MAX_ELEMENTS * this.pageIndex;
+
+ // I want first row to be only for navigation and return button.
+ int index = 10;
+
+ while (entitiesIndex < ((this.pageIndex + 1) * MAX_ELEMENTS) &&
+ entitiesIndex < this.materialList.size() &&
+ index < 36)
+ {
+ if (!panelBuilder.slotOccupied(index))
+ {
+ panelBuilder.item(index, this.createElementButton(this.materialList.get(entitiesIndex++)));
+ }
+
+ index++;
+ }
+
+ // Navigation buttons only if necessary
+ if (this.materialList.size() > MAX_ELEMENTS)
+ {
+ panelBuilder.item(18, this.getButton(CommonButtons.PREVIOUS));
+ panelBuilder.item(26, this.getButton(CommonButtons.NEXT));
+ }
+
+ // Add return button.
+ panelBuilder.item(44, this.returnButton);
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method creates PanelItem button of requested type.
+ * @param button Button which must be created.
+ * @return new PanelItem with requested functionality.
+ */
+ private PanelItem createButton(Button button)
+ {
+ PanelItemBuilder builder = new PanelItemBuilder();
+
+ switch (button)
+ {
+ case ADD:
+ builder.name(this.user.getTranslation("challenges.gui.button.add"));
+ builder.icon(Material.BUCKET);
+ builder.clickHandler((panel, user1, clickType, slot) -> {
+
+ new SelectBlocksGUI(this.user, new HashSet<>(this.materialList), (status, material) -> {
+ if (status)
+ {
+ this.materialMap.put(material, 1);
+ this.materialList.add(material);
+ }
+
+ this.build();
+ });
+ return true;
+ });
+ break;
+ case REMOVE:
+ builder.name(this.user.getTranslation("challenges.gui.button.remove-selected"));
+ builder.icon(Material.LAVA_BUCKET);
+ builder.clickHandler((panel, user1, clickType, slot) -> {
+ this.materialMap.keySet().removeAll(this.selectedMaterials);
+ this.materialList.removeAll(this.selectedMaterials);
+ this.build();
+ return true;
+ });
+ break;
+ }
+
+ return builder.build();
+ }
+
+
+ /**
+ * This method creates button for given material.
+ * @param material material which button must be created.
+ * @return new Button for material.
+ */
+ private PanelItem createElementButton(Material material)
+ {
+ return new PanelItemBuilder().
+ name(WordUtils.capitalize(material.name().toLowerCase().replace("_", " "))).
+ icon(GuiUtils.getMaterialItem(material, this.materialMap.get(material))).
+ clickHandler((panel, user1, clickType, slot) -> {
+ // On right click change which entities are selected for deletion.
+ if (clickType.isRightClick())
+ {
+ if (!this.selectedMaterials.add(material))
+ {
+ // Remove material if it is already selected
+ this.selectedMaterials.remove(material);
+ }
+
+ this.build();
+ }
+ else
+ {
+ new NumberGUI(this.user, this.materialMap.get(material), 1, (status, value) -> {
+ if (status)
+ {
+ // Update value only when something changes.
+ this.materialMap.put(material, value);
+ }
+
+ this.build();
+ });
+ }
+ return true;
+ }).
+ glow(this.selectedMaterials.contains(material)).
+ build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Enums
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Functional buttons in current GUI.
+ */
+ private enum Button
+ {
+ ADD,
+ REMOVE
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ /**
+ * Contains selected materials.
+ */
+ private Set selectedMaterials;
+
+ /**
+ * List of materials to avoid order issues.
+ */
+ private List materialList;
+
+ /**
+ * List of required materials.
+ */
+ private Map materialMap;
+}
diff --git a/src/main/java/world/bentobox/challenges/panel/admin/ManageEntitiesGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/ManageEntitiesGUI.java
new file mode 100644
index 0000000..d2b4d71
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/admin/ManageEntitiesGUI.java
@@ -0,0 +1,234 @@
+package world.bentobox.challenges.panel.admin;
+
+
+import org.apache.commons.lang.WordUtils;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.entity.EntityType;
+import org.bukkit.inventory.ItemStack;
+import java.util.*;
+
+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.panel.CommonGUI;
+import world.bentobox.challenges.panel.util.NumberGUI;
+import world.bentobox.challenges.panel.util.SelectEntityGUI;
+import world.bentobox.challenges.utils.GuiUtils;
+
+
+/**
+ * This class allows to edit entities that are in required entities map.
+ */
+public class ManageEntitiesGUI extends CommonGUI
+{
+ public ManageEntitiesGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ Map requiredEntities,
+ String topLabel,
+ String permissionPrefix,
+ CommonGUI parentGUI)
+ {
+ super(addon, world, user, topLabel, permissionPrefix, parentGUI);
+ this.requiredEntities = requiredEntities;
+
+ this.entityList = new ArrayList<>(this.requiredEntities.keySet());
+ this.entityList.sort(Comparator.comparing(Enum::name));
+
+ this.selectedEntities = new HashSet<>(EntityType.values().length);
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method builds all necessary elements in GUI panel.
+ */
+ @Override
+ public void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).
+ name(this.user.getTranslation("challenges.gui.admin.edit-entities"));
+
+ // create border
+ GuiUtils.fillBorder(panelBuilder);
+
+ panelBuilder.item(3, this.createButton(Button.ADD));
+ panelBuilder.item(5, this.createButton(Button.REMOVE));
+
+ final int MAX_ELEMENTS = 21;
+
+ if (this.pageIndex < 0)
+ {
+ this.pageIndex = this.entityList.size() / MAX_ELEMENTS;
+ }
+ else if (this.pageIndex > (this.entityList.size() / MAX_ELEMENTS))
+ {
+ this.pageIndex = 0;
+ }
+
+ int entitiesIndex = MAX_ELEMENTS * this.pageIndex;
+
+ // I want first row to be only for navigation and return button.
+ int index = 10;
+
+ while (entitiesIndex < ((this.pageIndex + 1) * MAX_ELEMENTS) &&
+ entitiesIndex < this.entityList.size() &&
+ index < 26)
+ {
+ if (!panelBuilder.slotOccupied(index))
+ {
+ panelBuilder.item(index, this.createEntityButton(this.entityList.get(entitiesIndex++)));
+ }
+
+ index++;
+ }
+
+ // Navigation buttons only if necessary
+ if (this.entityList.size() > MAX_ELEMENTS)
+ {
+ panelBuilder.item(18, this.getButton(CommonButtons.PREVIOUS));
+ panelBuilder.item(26, this.getButton(CommonButtons.NEXT));
+ }
+
+ // Add return button.
+ panelBuilder.item(44, this.returnButton);
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method creates PanelItem button of requested type.
+ * @param button Button which must be created.
+ * @return new PanelItem with requested functionality.
+ */
+ private PanelItem createButton(Button button)
+ {
+ PanelItemBuilder builder = new PanelItemBuilder();
+
+ switch (button)
+ {
+ case ADD:
+ builder.name(this.user.getTranslation("challenges.gui.button.add"));
+ builder.icon(Material.BUCKET);
+ builder.clickHandler((panel, user1, clickType, slot) -> {
+ new SelectEntityGUI(this.user, (status, entity) -> {
+ if (status)
+ {
+ if (!this.requiredEntities.containsKey(entity))
+ {
+ this.requiredEntities.put(entity, 1);
+ this.entityList.add(entity);
+ }
+ }
+
+ this.build();
+ });
+ return true;
+ });
+ break;
+ case REMOVE:
+ builder.name(this.user.getTranslation("challenges.gui.button.remove-selected"));
+ builder.icon(Material.LAVA_BUCKET);
+ builder.clickHandler((panel, user1, clickType, slot) -> {
+ this.requiredEntities.keySet().removeAll(this.selectedEntities);
+ this.entityList.removeAll(this.selectedEntities);
+ this.build();
+ return true;
+ });
+ break;
+ }
+
+ return builder.build();
+ }
+
+
+ /**
+ * This method creates button for given entity.
+ * @param entity Entity which button must be created.
+ * @return new Button for entity.
+ */
+ private PanelItem createEntityButton(EntityType entity)
+ {
+ return new PanelItemBuilder().
+ name(WordUtils.capitalize(entity.name().toLowerCase().replace("_", " "))).
+ icon(this.asEggs ?
+ GuiUtils.getEntityEgg(entity, this.requiredEntities.get(entity)) :
+ GuiUtils.getEntityHead(entity, this.requiredEntities.get(entity))).
+ clickHandler((panel, user1, clickType, slot) -> {
+ // On right click change which entities are selected for deletion.
+ if (clickType.isRightClick())
+ {
+ if (!this.selectedEntities.add(entity))
+ {
+ // Remove entity if it is already selected
+ this.selectedEntities.remove(entity);
+ }
+
+ this.build();
+ }
+ else
+ {
+ new NumberGUI(this.user, this.requiredEntities.get(entity), 1, (status, value) -> {
+ if (status)
+ {
+ // Update value only when something changes.
+ this.requiredEntities.put(entity, value);
+ }
+
+ this.build();
+ });
+ }
+ return true;
+ }).
+ glow(this.selectedEntities.contains(entity)).
+ build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Enums
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Functional buttons in current GUI.
+ */
+ private enum Button
+ {
+ ADD,
+ REMOVE
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ /**
+ * List with entities to avoid list irregularities.
+ */
+ private List entityList;
+
+ /**
+ * Set with entities that are selected.
+ */
+ private Set selectedEntities;
+
+ /**
+ * Map that contains all entities and their cound.
+ */
+ private Map requiredEntities;
+
+ /**
+ * Boolean indicate if entities should be displayed as eggs or mob heads.
+ */
+ private boolean asEggs;
+}
diff --git a/src/main/java/world/bentobox/challenges/panel/user/ChallengesGUI.java b/src/main/java/world/bentobox/challenges/panel/user/ChallengesGUI.java
new file mode 100644
index 0000000..a1913f5
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/user/ChallengesGUI.java
@@ -0,0 +1,557 @@
+package world.bentobox.challenges.panel.user;
+
+
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.inventory.ItemStack;
+import java.util.ArrayList;
+import java.util.List;
+
+import world.bentobox.bentobox.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.ChallengesManager;
+import world.bentobox.challenges.database.object.Challenge;
+import world.bentobox.challenges.panel.CommonGUI;
+import world.bentobox.challenges.panel.TryToComplete;
+import world.bentobox.challenges.utils.GuiUtils;
+import world.bentobox.challenges.utils.LevelStatus;
+
+
+/**
+ * This is UserGUI class. It contains everything necessary for user to use it.
+ */
+public class ChallengesGUI extends CommonGUI
+{
+// ---------------------------------------------------------------------
+// Section: Constructors
+// ---------------------------------------------------------------------
+
+ /**
+ * Default constructor that inits panels with minimal requirements, without parent panel.
+ *
+ * @param addon Addon where panel operates.
+ * @param world World from which panel was created.
+ * @param user User who created panel.
+ * @param topLabel Command top label which creates panel (f.e. island or ai)
+ * @param permissionPrefix Command permission prefix (f.e. bskyblock.)
+ */
+ public ChallengesGUI(ChallengesAddon addon,
+ World world,
+ User user,
+ String topLabel,
+ String permissionPrefix)
+ {
+ super(addon, world, user, topLabel, permissionPrefix);
+ this.challengesManager = this.addon.getChallengesManager();
+
+ this.levelStatusList = this.challengesManager.getChallengeLevelStatus(this.user, this.world);
+
+ for (LevelStatus levelStatus : this.levelStatusList)
+ {
+ if (levelStatus.isUnlocked())
+ {
+ this.lastSelectedLevel = levelStatus;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method builds all necessary elements in GUI panel.
+ */
+ @Override
+ public void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).
+ name(this.user.getTranslation("challenges.gui.title"));
+
+ // TODO: get last completed level.
+
+ if (this.addon.getChallengesSettings().isFreeChallengesFirst())
+ {
+ this.addFreeChallenges(panelBuilder);
+
+ // Start new row for challenges.
+ while (panelBuilder.nextSlot() % 9 != 0)
+ {
+ panelBuilder.item(
+ new PanelItemBuilder().icon(Material.LIGHT_GRAY_STAINED_GLASS_PANE).name(" ").build());
+ }
+ }
+
+ this.addChallenges(panelBuilder);
+
+ // Start new row for levels.
+ while (panelBuilder.nextSlot() % 9 != 0)
+ {
+ panelBuilder.item(
+ new PanelItemBuilder().icon(Material.LIGHT_GRAY_STAINED_GLASS_PANE).name(" ").build());
+ }
+
+ this.addChallengeLevels(panelBuilder);
+
+ if (!this.addon.getChallengesSettings().isFreeChallengesFirst())
+ {
+ // Start new row for free challenges.
+ while (panelBuilder.nextSlot() % 9 != 0)
+ {
+ panelBuilder.item(
+ new PanelItemBuilder().icon(Material.LIGHT_GRAY_STAINED_GLASS_PANE).name(" ").build());
+ }
+
+ this.addFreeChallenges(panelBuilder);
+ }
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method adds free challenges to panelBuilder.
+ * @param panelBuilder where free challenges must be added.
+ */
+ private void addFreeChallenges(PanelBuilder panelBuilder)
+ {
+ List freeChallenges = this.challengesManager.getFreeChallenges(this.world);
+ final int freeChallengesCount = freeChallenges.size();
+
+ if (freeChallengesCount > 18)
+ {
+ int firstIndex = panelBuilder.nextSlot();
+
+ if (this.freeChallengeIndex > 0)
+ {
+ panelBuilder.item(new PanelItemBuilder().
+ icon(Material.SIGN).
+ name(this.user.getTranslation("challenges.gui.buttons.previous")).
+ clickHandler((panel, user1, clickType, slot) -> {
+ this.freeChallengeIndex--;
+ this.build();
+ return true;
+ }).build());
+ }
+
+ int currentIndex = this.freeChallengeIndex;
+
+ while (panelBuilder.nextSlot() != firstIndex + 18 && currentIndex < freeChallengesCount)
+ {
+ panelBuilder.item(this.getChallengeButton(freeChallenges.get(currentIndex++)));
+ }
+
+ // Check if one challenge is left
+ if (currentIndex + 1 == freeChallengesCount)
+ {
+ panelBuilder.item(this.getChallengeButton(freeChallenges.get(currentIndex)));
+ }
+ else if (currentIndex < freeChallengesCount)
+ {
+ panelBuilder.item(new PanelItemBuilder().
+ icon(Material.SIGN).
+ name(this.user.getTranslation("challenges.gui.buttons.next")).
+ clickHandler((panel, user1, clickType, slot) -> {
+ this.freeChallengeIndex++;
+ this.build();
+ return true;
+ }).build());
+ }
+ }
+ else
+ {
+ for (Challenge challenge : freeChallenges)
+ {
+ // there are no limitations. Just bunch insert.
+ panelBuilder.item(this.getChallengeButton(challenge));
+ }
+ }
+ }
+
+
+ /**
+ * This method adds last selected level challenges to panelBuilder.
+ * @param panelBuilder where last selected level challenges must be added.
+ */
+ private void addChallenges(PanelBuilder panelBuilder)
+ {
+ if (this.lastSelectedLevel != null)
+ {
+ List challenges = this.challengesManager.getLevelChallenges(this.lastSelectedLevel.getLevel());
+ final int challengesCount = challenges.size();
+
+ if (challengesCount > 18)
+ {
+ int firstIndex = panelBuilder.nextSlot();
+
+ if (this.pageIndex > 0)
+ {
+ panelBuilder.item(new PanelItemBuilder().
+ icon(Material.SIGN).
+ name(this.user.getTranslation("challenges.gui.buttons.previous")).
+ clickHandler((panel, user1, clickType, slot) -> {
+ this.pageIndex--;
+ this.build();
+ return true;
+ }).build());
+ }
+
+ int currentIndex = this.pageIndex;
+
+ while (panelBuilder.nextSlot() != firstIndex + 18 && currentIndex < challengesCount)
+ {
+ panelBuilder.item(this.getChallengeButton(challenges.get(currentIndex++)));
+ }
+
+ // Check if one challenge is left
+ if (currentIndex + 1 == challengesCount)
+ {
+ panelBuilder.item(this.getChallengeButton(challenges.get(currentIndex)));
+ }
+ else if (currentIndex < challengesCount)
+ {
+ panelBuilder.item(new PanelItemBuilder().
+ icon(Material.SIGN).
+ name(this.user.getTranslation("challenges.gui.buttons.next")).
+ clickHandler((panel, user1, clickType, slot) -> {
+ this.pageIndex++;
+ this.build();
+ return true;
+ }).build());
+ }
+ }
+ else
+ {
+ for (Challenge challenge : challenges)
+ {
+ // there are no limitations. Just bunch insert.
+ panelBuilder.item(this.getChallengeButton(challenge));
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This method adds challenge levels to panelBuilder.
+ * @param panelBuilder where challenge levels must be added.
+ */
+ private void addChallengeLevels(PanelBuilder panelBuilder)
+ {
+ // Clone to avoid creating new level on each build.
+ List leftLevels = new ArrayList<>(this.levelStatusList);
+ leftLevels.remove(this.lastSelectedLevel);
+
+ // TODO: Focusing on middle should be awsome.
+
+ final int levelCounts = leftLevels.size();
+
+ if (levelCounts > 9)
+ {
+ int firstIndex = panelBuilder.nextSlot();
+
+ if (this.levelIndex > 0)
+ {
+ panelBuilder.item(new PanelItemBuilder().
+ icon(Material.SIGN).
+ name(this.user.getTranslation("challenges.gui.buttons.previous")).
+ clickHandler((panel, user1, clickType, slot) -> {
+ this.levelIndex--;
+ this.build();
+ return true;
+ }).build());
+ }
+
+ int currentIndex = this.levelIndex;
+
+ while (panelBuilder.nextSlot() != firstIndex + 9 && currentIndex < levelCounts)
+ {
+ panelBuilder.item(this.getLevelButton(leftLevels.get(currentIndex++)));
+ }
+
+ // Check if one challenge is left
+ if (currentIndex + 1 == levelCounts)
+ {
+ panelBuilder.item(this.getLevelButton(leftLevels.get(currentIndex)));
+ }
+ else if (currentIndex < levelCounts)
+ {
+ panelBuilder.item(new PanelItemBuilder().
+ icon(Material.SIGN).
+ name(this.user.getTranslation("challenges.gui.buttons.next")).
+ clickHandler((panel, user1, clickType, slot) -> {
+ this.levelIndex++;
+ this.build();
+ return true;
+ }).build());
+ }
+ }
+ else
+ {
+ for (LevelStatus level : leftLevels)
+ {
+ // there are no limitations. Just bunch insert.
+ panelBuilder.item(this.getLevelButton(level));
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Icon building
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method creates given challenges icon that on press tries to complete it.
+ * @param challenge which icon must be constructed.
+ * @return PanelItem icon for challenge.
+ */
+ private PanelItem getChallengeButton(Challenge challenge)
+ {
+ return new PanelItemBuilder().
+ icon(challenge.getIcon()).
+ name(challenge.getFriendlyName().isEmpty() ? challenge.getUniqueId() : challenge.getFriendlyName()).
+ description(GuiUtils.stringSplit(this.createChallengeDescription(challenge))).
+ clickHandler((panel, user1, clickType, slot) -> {
+ new TryToComplete(this.addon,
+ this.user,
+ challenge,
+ this.world,
+ this.topLabel,
+ this.permissionPrefix);
+ return true;
+ }).
+ glow(this.challengesManager.isChallengeComplete(this.user, challenge)).
+ build();
+ }
+
+
+ /**
+ * This method creates challenges description by adding all information that is necessary for this challenge.
+ * @param challenge Which information must be retrieved.
+ * @return List with strings that contains information about given challenge.
+ */
+ private List createChallengeDescription(Challenge challenge)
+ {
+ List result = new ArrayList<>();
+
+ result.add(this.user.getTranslation("challenges.level",
+ "[level]", this.challengesManager.getLevel(challenge).getFriendlyName()));
+
+ boolean completed = this.challengesManager.isChallengeComplete(this.user, challenge);
+
+ if (completed)
+ {
+ result.add(this.user.getTranslation("challenges.complete"));
+ }
+
+ if (challenge.isRepeatable())
+ {
+ int maxTimes = challenge.getMaxTimes();
+ long doneTimes = this.challengesManager.getChallengeTimes(this.user, challenge);
+
+ if (maxTimes > 0)
+ {
+ if (doneTimes < maxTimes)
+ {
+ result.add(this.user.getTranslation("challenges.completed-times",
+ "[donetimes]", String.valueOf(doneTimes),
+ "[maxtimes]", String.valueOf(maxTimes)));
+
+ // Change value to false, as max count not reached.
+ completed = false;
+ }
+ else
+ {
+ result.add(this.user.getTranslation("challenges.maxed-reached",
+ "[donetimes]", String.valueOf(doneTimes),
+ "[maxtimes]", String.valueOf(maxTimes)));
+ }
+ }
+ else
+ {
+ result.add(this.user.getTranslation("challenges.completed-times",
+ "[donetimes]", String.valueOf(doneTimes)));
+
+ // Change value to false, as max count not reached.
+ completed = false;
+ }
+ }
+
+ if (!completed)
+ {
+ result.addAll(challenge.getDescription());
+
+ if (challenge.getChallengeType().equals(Challenge.ChallengeType.INVENTORY))
+ {
+ if (challenge.isTakeItems())
+ {
+ result.add(this.user.getTranslation("challenges.item-take-warning"));
+ }
+ }
+ else if (challenge.getChallengeType().equals(Challenge.ChallengeType.ISLAND))
+ {
+ result.add(this.user.getTranslation("challenges.items-closeby"));
+
+ if (challenge.isRemoveEntities() && !challenge.getRequiredEntities().isEmpty())
+ {
+ result.add(this.user.getTranslation("challenges.entities-kill-warning"));
+ }
+
+ if (challenge.isRemoveBlocks() && !challenge.getRequiredBlocks().isEmpty())
+ {
+ result.add(this.user.getTranslation("challenges.blocks-take-warning"));
+ }
+ }
+ }
+
+ if (completed)
+ {
+ result.add(this.user.getTranslation("challenges.not-repeatable"));
+ }
+ else
+ {
+ result.addAll(this.challengeRewards(challenge));
+ }
+
+ result.replaceAll(x -> x.replace("[label]", this.topLabel));
+
+ return result;
+ }
+
+
+ /**
+ * This method returns list of strings that contains basic information about challenge rewards.
+ * @param challenge which reward message must be created.
+ * @return list of strings that contains rewards message.
+ */
+ private List challengeRewards(Challenge challenge)
+ {
+ String rewardText;
+ double rewardMoney;
+ int rewardExperience;
+
+ if (!this.challengesManager.isChallengeComplete(this.user, challenge))
+ {
+ rewardText = challenge.getRewardText();
+ rewardMoney = challenge.getRewardMoney();
+ rewardExperience = challenge.getRewardExperience();
+ }
+ else
+ {
+ rewardText = challenge.getRepeatRewardText();
+ rewardMoney = challenge.getRepeatMoneyReward();
+ rewardExperience = challenge.getRepeatExperienceReward();
+ }
+
+ List result = new ArrayList<>();
+
+ // Add reward text
+ result.add(rewardText);
+
+ // Add message about reward XP
+ if (rewardExperience > 0)
+ {
+ result.add(this.user.getTranslation("challenges.exp-reward",
+ "[reward]", Integer.toString(rewardExperience)));
+ }
+
+ // Add message about reward money
+ if (this.addon.getPlugin().getSettings().isUseEconomy() && rewardMoney > 0)
+ {
+ result.add(this.user.getTranslation("challenges.money-reward",
+ "[reward]", Double.toString(rewardMoney)));
+ }
+
+ return result;
+ }
+
+
+ /**
+ * This method creates button for given level.
+ * @param level which button must be created.
+ * @return Button for given level.
+ */
+ private PanelItem getLevelButton(LevelStatus level)
+ {
+ // Create a nice name for the level
+ String name = level.getLevel().getFriendlyName().isEmpty() ?
+ level.getLevel().getUniqueId() :
+ level.getLevel().getFriendlyName();
+
+ ItemStack icon;
+ List description;
+ PanelItem.ClickHandler clickHandler;
+ boolean glow;
+
+ if (level.isUnlocked())
+ {
+ icon = level.getLevel().getIcon();
+ description = GuiUtils.stringSplit(this.user.getTranslation("challenges.navigation", "[level]", name));
+ clickHandler = (panel, user1, clickType, slot) -> {
+ this.lastSelectedLevel = level;
+
+ // Reset level and page index.
+ this.levelIndex = 0;
+ this.pageIndex = 0;
+
+ this.build();
+ return true;
+ };
+ glow = this.challengesManager.isLevelCompleted(this.user, level.getLevel());
+ }
+ else
+ {
+ icon = new ItemStack(Material.BOOK);
+
+ description = GuiUtils.stringSplit(
+ this.user.getTranslation("challenges.to-complete",
+ "[challengesToDo]", Integer.toString(level.getNumberOfChallengesStillToDo()),
+ "[thisLevel]", level.getPreviousLevel().getFriendlyName()));
+
+ clickHandler = null;
+ glow = false;
+ }
+
+ return new PanelItem(icon, name, description, glow, clickHandler, false);
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ /**
+ * This will be used if free challenges are more then 18.
+ */
+ private int freeChallengeIndex = 0;
+
+ /**
+ * This will be used if levels are more then 9.
+ */
+ private int levelIndex;
+
+ /**
+ * This list contains all information about level completion in current world.
+ */
+ private List levelStatusList;
+
+ /**
+ * This indicate last selected level.
+ */
+ private LevelStatus lastSelectedLevel;
+
+ /**
+ * Challenge Manager object.
+ */
+ private ChallengesManager challengesManager;
+}
diff --git a/src/main/java/world/bentobox/challenges/panel/util/ConfirmationGUI.java b/src/main/java/world/bentobox/challenges/panel/util/ConfirmationGUI.java
new file mode 100644
index 0000000..3d36baf
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/util/ConfirmationGUI.java
@@ -0,0 +1,114 @@
+package world.bentobox.challenges.panel.util;
+
+
+import org.bukkit.Material;
+
+import java.util.function.Consumer;
+
+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.utils.GuiUtils;
+
+
+/**
+ * This GUI is used to confirm that user wants to run command, that should be created from
+ * command string list.
+ */
+public class ConfirmationGUI
+{
+ /**
+ * This constructor inits and opens ConfirmationGUI.
+ *
+ * @param user Gui Caller.
+ */
+ public ConfirmationGUI(User user, Consumer consumer)
+ {
+ this.user = user;
+ this.consumer = consumer;
+
+ this.build();
+ }
+
+
+ /**
+ * This method builds confirmation panel with 2 buttons.
+ */
+ public void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).name(this.user.getTranslation("challenges.gui.admin.confirm-title"));
+
+ GuiUtils.fillBorder(panelBuilder, Material.BLUE_STAINED_GLASS_PANE);
+
+ // Accept buttons
+ panelBuilder.item(10, this.getButton(true));
+ panelBuilder.item(11, this.getButton(true));
+ panelBuilder.item(12, this.getButton(true));
+
+ panelBuilder.item(19, this.getButton(true));
+ panelBuilder.item(20, this.getButton(true));
+ panelBuilder.item(21, this.getButton(true));
+
+ panelBuilder.item(28, this.getButton(true));
+ panelBuilder.item(29, this.getButton(true));
+ panelBuilder.item(30, this.getButton(true));
+
+ // Cancel Buttons
+ panelBuilder.item(14, this.getButton(false));
+ panelBuilder.item(15, this.getButton(false));
+ panelBuilder.item(16, this.getButton(false));
+
+ panelBuilder.item(23, this.getButton(false));
+ panelBuilder.item(24, this.getButton(false));
+ panelBuilder.item(25, this.getButton(false));
+
+ panelBuilder.item(32, this.getButton(false));
+ panelBuilder.item(33, this.getButton(false));
+ panelBuilder.item(34, this.getButton(false));
+
+ panelBuilder.item(44,
+ new PanelItemBuilder().
+ icon(Material.OAK_DOOR).
+ name(this.user.getTranslation("challenges.gui.buttons.return")).
+ clickHandler( (panel, user1, clickType, slot) -> {
+ this.consumer.accept(false);
+ return true;
+ }).build());
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method creates button with requested value.
+ * @param returnValue requested value
+ * @return PanelItem button.
+ */
+ private PanelItem getButton(boolean returnValue)
+ {
+ return new PanelItemBuilder().
+ name(this.user.getTranslation("challenges.gui.admin.buttons." + (returnValue ? "accept" : "cancel"))).
+ icon(returnValue ? Material.GRAY_STAINED_GLASS_PANE : Material.RED_STAINED_GLASS_PANE).
+ clickHandler((panel, user1, clickType, i) -> {
+ this.consumer.accept(returnValue);
+ return true;
+ }).
+ build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ /**
+ * User who wants to run command.
+ */
+ private User user;
+
+ /**
+ * Stores current Consumer
+ */
+ private Consumer consumer;
+}
diff --git a/src/main/java/world/bentobox/challenges/panel/util/ItemSwitchGUI.java b/src/main/java/world/bentobox/challenges/panel/util/ItemSwitchGUI.java
new file mode 100644
index 0000000..2d44739
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/util/ItemSwitchGUI.java
@@ -0,0 +1,236 @@
+package world.bentobox.challenges.panel.util;
+
+
+import org.bukkit.Material;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryCloseEvent;
+import org.bukkit.inventory.ItemStack;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.BiConsumer;
+
+import world.bentobox.bentobox.api.panels.PanelItem;
+import world.bentobox.bentobox.api.panels.PanelListener;
+import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
+import world.bentobox.bentobox.api.user.User;
+import world.bentobox.challenges.utils.GuiUtils;
+
+
+/**
+ * This class allows to change Input ItemStacks to different ItemStacks.
+ */
+public class ItemSwitchGUI
+{
+ public ItemSwitchGUI(User user, List itemStacks, BiConsumer> consumer)
+ {
+ this.consumer = consumer;
+ this.user = user;
+ this.itemStacks = itemStacks;
+ this.build();
+ }
+
+
+ /**
+ * This method builds panel that allows to change given number value.
+ */
+ private void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).name(this.user.getTranslation("challenges.gui.change-items"));
+
+ // Size of inventory that user can set via GUI.
+ panelBuilder.size(45);
+
+ panelBuilder.listener(new CustomPanelListener());
+
+ panelBuilder.item(0, this.getButton(Button.SAVE));
+
+ for (int i = 1; i < 8; i++)
+ {
+ panelBuilder.item(i, this.getButton(Button.EMPTY));
+ }
+
+ panelBuilder.item(8, this.getButton(Button.CANCEL));
+
+ for (ItemStack itemStack : this.itemStacks)
+ {
+ panelBuilder.item(new CustomPanelItem(itemStack));
+ }
+
+ panelBuilder.build().open(this.user);
+ }
+
+
+ /**
+ * This method create button that does some functionality in current gui.
+ * @param button Button functionality.
+ * @return PanelItem.
+ */
+ private PanelItem getButton(Button button)
+ {
+ ItemStack icon;
+ String name;
+ List description;
+ PanelItem.ClickHandler clickHandler;
+
+ switch (button)
+ {
+ case SAVE:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.save");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.COMMAND_BLOCK);
+ clickHandler = (panel, user, clickType, slot) -> {
+ // Magic number 9 - second row. First row is for custom buttons.
+ // Magic number 45 - This GUI is initialed with 45 elements.
+ List returnItems = new ArrayList<>(36);
+
+ for (int i = 9; i < 45; i++)
+ {
+ ItemStack itemStack = panel.getInventory().getItem(i);
+
+ if (itemStack != null)
+ {
+ returnItems.add(itemStack);
+ }
+ }
+
+ this.consumer.accept(true, returnItems);
+
+ return true;
+ };
+ break;
+ }
+ case CANCEL:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.cancel");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.IRON_DOOR);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.consumer.accept(false, Collections.emptyList());
+ return true;
+ };
+ break;
+ }
+ case EMPTY:
+ {
+ name = "";
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.BARRIER);
+ clickHandler = (panel, user, clickType, slot) -> true;
+ break;
+ }
+ default:
+ return null;
+ }
+
+ return new PanelItem(icon, name, GuiUtils.stringSplit(description), false, clickHandler, false);
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Private classes
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This CustomPanelItem does no lose Item original MetaData. After PanelItem has been
+ * created it restores original meta data. It also does not allow to change anything that
+ * could destroy meta data.
+ */
+ private class CustomPanelItem extends PanelItem
+ {
+ CustomPanelItem(ItemStack item)
+ {
+ super(item.clone(), "", Collections.emptyList(), false, null, false);
+ this.getItem().setItemMeta(item.getItemMeta());
+ }
+
+
+ @Override
+ public void setGlow(boolean glow)
+ {
+ }
+
+
+ @Override
+ public void setDescription(List description)
+ {
+ }
+
+
+ @Override
+ public void setName(String name)
+ {
+ }
+
+
+ @Override
+ public void setHead(ItemStack itemStack)
+ {
+ }
+ }
+
+
+ /**
+ * This CustomPanelListener allows to move items in current panel.
+ */
+ private class CustomPanelListener implements PanelListener
+ {
+ @Override
+ public void setup()
+ {
+ }
+
+
+ @Override
+ public void onInventoryClose(InventoryCloseEvent inventoryCloseEvent)
+ {
+ }
+
+
+ @Override
+ public void onInventoryClick(User user, InventoryClickEvent event)
+ {
+ // First row of elements should be ignored, as it contains buttons and blocked slots.
+ event.setCancelled(event.getRawSlot() < 9);
+ }
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Enums
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This enum holds all button values in current gui.
+ */
+ private enum Button
+ {
+ CANCEL,
+ SAVE,
+ EMPTY
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+
+ /**
+ * User who opens current gui.
+ */
+ private User user;
+
+ /**
+ * List with original items.
+ */
+ private List itemStacks;
+
+ /**
+ * Consumer that returns item stacks on save action.
+ */
+ private BiConsumer> consumer;
+}
diff --git a/src/main/java/world/bentobox/challenges/panel/util/NumberGUI.java b/src/main/java/world/bentobox/challenges/panel/util/NumberGUI.java
new file mode 100644
index 0000000..6eb0376
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/util/NumberGUI.java
@@ -0,0 +1,420 @@
+package world.bentobox.challenges.panel.util;
+
+
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.BiConsumer;
+
+import net.wesjd.anvilgui.AnvilGUI;
+import world.bentobox.bentobox.BentoBox;
+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.utils.GuiUtils;
+
+
+/**
+ * This gui allows to change current number and returns it to previous GUI
+ */
+public class NumberGUI
+{
+ public NumberGUI(User user, int value, BiConsumer consumer)
+ {
+ this(user, value, Integer.MIN_VALUE, Integer.MAX_VALUE, consumer);
+ }
+
+
+ public NumberGUI(User user, int value, int minValue, BiConsumer consumer)
+ {
+ this(user, value, minValue, Integer.MAX_VALUE, consumer);
+ }
+
+
+ public NumberGUI(User user, int value, int minValue, int maxValue, BiConsumer consumer)
+ {
+ this.user = user;
+ this.value = value;
+ this.consumer = consumer;
+
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+
+ this.currentOperation = Button.SET;
+
+ this.build();
+ }
+
+
+ /**
+ * This method builds panel that allows to change given number value.
+ */
+ private void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).name(this.user.getTranslation("challenges.gui.edit-number-title"));
+
+ GuiUtils.fillBorder(panelBuilder);
+
+ // Others
+ panelBuilder.item(1, this.getButton(Button.SAVE));
+
+ panelBuilder.item(19, this.getButton(Button.VALUE));
+ panelBuilder.item(44, this.getButton(Button.CANCEL));
+
+ panelBuilder.item(2, this.getButton(Button.INPUT));
+
+ // operations
+ panelBuilder.item(3, this.getButton(Button.SET));
+ panelBuilder.item(4, this.getButton(Button.INCREASE));
+ panelBuilder.item(5, this.getButton(Button.REDUCE));
+ panelBuilder.item(6, this.getButton(Button.MULTIPLY));
+
+ // Numbers
+ panelBuilder.item(11, this.createNumberButton(1));
+ panelBuilder.item(12, this.createNumberButton(10));
+ panelBuilder.item(13, this.createNumberButton(100));
+ panelBuilder.item(14, this.createNumberButton(1000));
+ panelBuilder.item(15, this.createNumberButton(10000));
+
+ panelBuilder.item(20, this.createNumberButton(2));
+ panelBuilder.item(21, this.createNumberButton(20));
+ panelBuilder.item(22, this.createNumberButton(200));
+ panelBuilder.item(23, this.createNumberButton(2000));
+ panelBuilder.item(24, this.createNumberButton(20000));
+
+ panelBuilder.item(29, this.createNumberButton(5));
+ panelBuilder.item(30, this.createNumberButton(50));
+ panelBuilder.item(31, this.createNumberButton(500));
+ panelBuilder.item(32, this.createNumberButton(5000));
+ panelBuilder.item(33, this.createNumberButton(50000));
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method creates PanelItem with required functionality.
+ * @param button Functionality requirement.
+ * @return PanelItem with functionality.
+ */
+ private PanelItem getButton(Button button)
+ {
+ ItemStack icon;
+ String name;
+ List description;
+ PanelItem.ClickHandler clickHandler;
+ boolean glow;
+
+ switch (button)
+ {
+ case SAVE:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.save");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.COMMAND_BLOCK);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.consumer.accept(true, this.value);
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case CANCEL:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.cancel");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.OAK_DOOR);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.consumer.accept(false, this.value);
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case INPUT:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.input");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.ANVIL);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new AnvilGUI(BentoBox.getInstance(),
+ this.user.getPlayer(),
+ Integer.toString(this.value),
+ (player, reply) -> {
+ try
+ {
+ this.value = Integer.parseInt(reply);
+
+ if (this.value > this.maxValue || this.value < this.minValue)
+ {
+ this.user.sendMessage("challenges.error.not-valid-integer",
+ "[value]", reply,
+ "[min]", Integer.toString(this.minValue),
+ "[max]", Integer.toString(this.maxValue));
+ }
+ else
+ {
+ this.build();
+ }
+ }
+ catch (Exception e)
+ {
+ reply = Integer.toString(this.value);
+ this.user.sendMessage("challenges.error.not-a-integer", "[value]", reply);
+ }
+
+ return reply;
+ });
+
+ return true;
+ };
+ glow = false;
+ break;
+ }
+ case VALUE:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.value");
+ description = Collections.singletonList(Integer.toString(this.value));
+ icon = new ItemStack(Material.PAPER);
+ clickHandler = (panel, user, clickType, slot) -> true;
+ glow = false;
+ break;
+ }
+ case SET:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.set");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.WHITE_STAINED_GLASS_PANE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.currentOperation = Button.SET;
+ this.build();
+ return true;
+ };
+ glow = this.currentOperation.equals(Button.SET);
+ break;
+ }
+ case INCREASE:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.increase");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.GREEN_STAINED_GLASS_PANE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.currentOperation = Button.INCREASE;
+ this.build();
+ return true;
+ };
+ glow = this.currentOperation.equals(Button.INCREASE);
+ break;
+ }
+ case REDUCE:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.reduce");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.RED_STAINED_GLASS_PANE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.currentOperation = Button.REDUCE;
+ this.build();
+ return true;
+ };
+ glow = this.currentOperation.equals(Button.REDUCE);
+ break;
+ }
+ case MULTIPLY:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.multiply");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.BLUE_STAINED_GLASS_PANE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ this.currentOperation = Button.MULTIPLY;
+ this.build();
+ return true;
+ };
+ glow = this.currentOperation.equals(Button.MULTIPLY);
+ break;
+ }
+ default:
+ return null;
+ }
+
+ return new PanelItem(icon, name, GuiUtils.stringSplit(description), glow, clickHandler, false);
+ }
+
+
+ /**
+ * This method creates Number Button based on input number.
+ * @param number Number which button must be created.
+ * @return PanelItem that represents number button.
+ */
+ private PanelItem createNumberButton(int number)
+ {
+ PanelItemBuilder itemBuilder = new PanelItemBuilder();
+
+ switch (this.currentOperation)
+ {
+ case SET:
+ {
+ itemBuilder.name(this.user.getTranslation("biomes.gui.buttons.set","[number]", Integer.toString(number)));
+ itemBuilder.icon(Material.WHITE_STAINED_GLASS_PANE);
+ itemBuilder.clickHandler((panel, user1, clickType, i) -> {
+ this.value = number;
+
+ if (this.value > this.maxValue)
+ {
+ this.user.sendMessage("challenges.error.not-valid-integer",
+ "[value]", Integer.toString(this.value),
+ "[min]", Integer.toString(this.minValue),
+ "[max]", Integer.toString(this.maxValue));
+
+ this.value = this.maxValue;
+ }
+
+ if (this.value < this.minValue)
+ {
+ this.user.sendMessage("challenges.error.not-valid-integer",
+ "[value]", Integer.toString(this.value),
+ "[min]", Integer.toString(this.minValue),
+ "[max]", Integer.toString(this.maxValue));
+
+ this.value = this.minValue;
+ }
+
+ this.build();
+ return true;
+ });
+
+ break;
+ }
+ case INCREASE:
+ {
+ itemBuilder.name(this.user.getTranslation("biomes.gui.buttons.increase","[number]", Integer.toString(number)));
+ itemBuilder.icon(Material.GREEN_STAINED_GLASS_PANE);
+ itemBuilder.clickHandler((panel, user1, clickType, i) -> {
+ this.value += number;
+
+ if (this.value > this.maxValue)
+ {
+ this.user.sendMessage("challenges.error.not-valid-integer",
+ "[value]", Integer.toString(this.value),
+ "[min]", Integer.toString(this.minValue),
+ "[max]", Integer.toString(this.maxValue));
+
+ this.value = this.maxValue;
+ }
+
+ this.build();
+ return true;
+ });
+
+ break;
+ }
+ case REDUCE:
+ {
+ itemBuilder.name(this.user.getTranslation("biomes.gui.buttons.reduce","[number]", Integer.toString(number)));
+ itemBuilder.icon(Material.RED_STAINED_GLASS_PANE);
+ itemBuilder.clickHandler((panel, user1, clickType, i) -> {
+ this.value -= number;
+
+ if (this.value < this.minValue)
+ {
+ this.user.sendMessage("challenges.error.not-valid-integer",
+ "[value]", Integer.toString(this.value),
+ "[min]", Integer.toString(this.minValue),
+ "[max]", Integer.toString(this.maxValue));
+
+ this.value = this.minValue;
+ }
+
+ this.build();
+ return true;
+ });
+
+ break;
+ }
+ case MULTIPLY:
+ {
+ itemBuilder.name(this.user.getTranslation("biomes.gui.buttons.multiply","[number]", Integer.toString(number)));
+ itemBuilder.icon(Material.BLUE_STAINED_GLASS_PANE);
+ itemBuilder.clickHandler((panel, user1, clickType, i) -> {
+ this.value *= number;
+
+ if (this.value > this.maxValue)
+ {
+ this.user.sendMessage("challenges.error.not-valid-integer",
+ "[value]", Integer.toString(this.value),
+ "[min]", Integer.toString(this.minValue),
+ "[max]", Integer.toString(this.maxValue));
+
+ this.value = this.maxValue;
+ }
+
+ this.build();
+ return true;
+ });
+
+ break;
+ }
+ }
+
+ return itemBuilder.build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Enums
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This enum contains all button types.
+ */
+ private enum Button
+ {
+ SAVE,
+ CANCEL,
+ INPUT,
+
+ VALUE,
+
+ SET,
+ INCREASE,
+ REDUCE,
+ MULTIPLY
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ /**
+ * This variable stores current GUI consumer.
+ */
+ private BiConsumer consumer;
+
+ /**
+ * User who runs GUI.
+ */
+ private User user;
+
+ /**
+ * Current value.
+ */
+ private int value;
+
+ /**
+ * Minimal value that is allowed to set.
+ */
+ private int minValue;
+
+ /**
+ * Maximal value that is allowed to set.
+ */
+ private int maxValue;
+
+ /**
+ * This variable holds which operation now is processed.
+ */
+ private Button currentOperation;
+}
diff --git a/src/main/java/world/bentobox/challenges/panel/util/SelectBlocksGUI.java b/src/main/java/world/bentobox/challenges/panel/util/SelectBlocksGUI.java
new file mode 100644
index 0000000..4870d04
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/util/SelectBlocksGUI.java
@@ -0,0 +1,195 @@
+package world.bentobox.challenges.panel.util;
+
+
+import org.apache.commons.lang.WordUtils;
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.function.BiConsumer;
+
+import world.bentobox.bentobox.api.panels.PanelItem;
+import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
+import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
+import world.bentobox.bentobox.api.user.User;
+import world.bentobox.challenges.utils.GuiUtils;
+
+
+/**
+ * This class contains all necessary things that allows to select single block from all ingame blocks. Selected
+ * block will be returned via BiConsumer.
+ */
+public class SelectBlocksGUI
+{
+ public SelectBlocksGUI(User user, BiConsumer consumer)
+ {
+ this(user, Collections.emptySet(), consumer);
+ }
+
+
+ public SelectBlocksGUI(User user, Set excludedMaterial, BiConsumer consumer)
+ {
+ this.consumer = consumer;
+ this.user = user;
+
+ // Current GUI cannot display air blocks. It crashes with null-pointer
+ excludedMaterial.add(Material.AIR);
+ excludedMaterial.add(Material.CAVE_AIR);
+ excludedMaterial.add(Material.VOID_AIR);
+
+ // Piston head and moving piston is not necessary. useless.
+ excludedMaterial.add(Material.PISTON_HEAD);
+ excludedMaterial.add(Material.MOVING_PISTON);
+
+ // Barrier cannot be accessible to user.
+ excludedMaterial.add(Material.BARRIER);
+
+ this.elements = new ArrayList<>();
+
+ for (Material material : Material.values())
+ {
+ if (material.isBlock() && !material.isLegacy() && !excludedMaterial.contains(material))
+ {
+ this.elements.add(material);
+ }
+ }
+
+ this.build(0);
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method builds all necessary elements in GUI panel.
+ */
+ public void build(int pageIndex)
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).
+ name(this.user.getTranslation("challenges.gui.admin.select-block"));
+
+ GuiUtils.fillBorder(panelBuilder, Material.BLUE_STAINED_GLASS_PANE);
+
+ final int MAX_ELEMENTS = 21;
+ final int correctPage;
+
+ if (pageIndex < 0)
+ {
+ correctPage = this.elements.size() / MAX_ELEMENTS;
+ }
+ else if (pageIndex > (this.elements.size() / MAX_ELEMENTS))
+ {
+ correctPage = 0;
+ }
+ else
+ {
+ correctPage = pageIndex;
+ }
+
+ int entitiesIndex = MAX_ELEMENTS * correctPage;
+
+ // I want first row to be only for navigation and return button.
+ int index = 10;
+
+ while (entitiesIndex < ((correctPage + 1) * MAX_ELEMENTS) &&
+ entitiesIndex < this.elements.size())
+ {
+ if (!panelBuilder.slotOccupied(index))
+ {
+ panelBuilder.item(index, this.createMaterialButton(this.elements.get(entitiesIndex++)));
+ }
+
+ index++;
+ }
+
+ panelBuilder.item(4,
+ new PanelItemBuilder().
+ icon(Material.RED_STAINED_GLASS_PANE).
+ name(this.user.getTranslation("challenges.gui.buttons.cancel")).
+ clickHandler( (panel, user1, clickType, slot) -> {
+ this.consumer.accept(false, null);
+ return true;
+ }).build());
+
+ if (this.elements.size() > MAX_ELEMENTS)
+ {
+ // Navigation buttons if necessary
+
+ panelBuilder.item(18,
+ new PanelItemBuilder().
+ icon(Material.SIGN).
+ name(this.user.getTranslation("challenges.gui.buttons.previous")).
+ clickHandler((panel, user1, clickType, slot) -> {
+ this.build(correctPage - 1);
+ return true;
+ }).build());
+
+ panelBuilder.item(26,
+ new PanelItemBuilder().
+ icon(Material.SIGN).
+ name(this.user.getTranslation("challenges.gui.buttons.next")).
+ clickHandler((panel, user1, clickType, slot) -> {
+ this.build(correctPage + 1);
+ return true;
+ }).build());
+ }
+
+ panelBuilder.item(44,
+ new PanelItemBuilder().
+ icon(Material.OAK_DOOR).
+ name(this.user.getTranslation("challenges.gui.buttons.return")).
+ clickHandler( (panel, user1, clickType, slot) -> {
+ this.consumer.accept(false, null);
+ return true;
+ }).build());
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method creates PanelItem that represents given material.
+ * Some materials is not displayable in Inventory GUI, so they are replaced with "placeholder" items.
+ * @param material Material which icon must be created.
+ * @return PanelItem that represents given material.
+ */
+ private PanelItem createMaterialButton(Material material)
+ {
+ ItemStack itemStack = GuiUtils.getMaterialItem(material);
+
+ return new PanelItemBuilder().
+ name(WordUtils.capitalize(material.name().toLowerCase().replace("_", " "))).
+ icon(itemStack).
+ clickHandler((panel, user1, clickType, slot) -> {
+ this.consumer.accept(true, material);
+ return true;
+ }).
+ glow(!itemStack.getType().equals(material)).
+ build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+ /**
+ * List with elements that will be displayed in current GUI.
+ */
+ private List elements;
+
+ /**
+ * This variable stores consumer.
+ */
+ private BiConsumer consumer;
+
+ /**
+ * User who runs GUI.
+ */
+ private User user;
+}
diff --git a/src/main/java/world/bentobox/challenges/panel/util/SelectChallengeGUI.java b/src/main/java/world/bentobox/challenges/panel/util/SelectChallengeGUI.java
new file mode 100644
index 0000000..ab6bdab
--- /dev/null
+++ b/src/main/java/world/bentobox/challenges/panel/util/SelectChallengeGUI.java
@@ -0,0 +1,158 @@
+package world.bentobox.challenges.panel.util;
+
+
+import org.bukkit.Material;
+import java.util.List;
+import java.util.function.BiConsumer;
+
+import world.bentobox.bentobox.api.panels.PanelItem;
+import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
+import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
+import world.bentobox.bentobox.api.user.User;
+import world.bentobox.challenges.database.object.Challenge;
+import world.bentobox.challenges.utils.GuiUtils;
+
+
+/**
+ * This class creates new GUI that allows to select single challenge, which is returned via consumer.
+ */
+public class SelectChallengeGUI
+{
+ public SelectChallengeGUI(User user, List challengesList, BiConsumer consumer)
+ {
+ this.consumer = consumer;
+ this.user = user;
+ this.challengesList = challengesList;
+
+ this.build(0);
+ }
+
+
+ /**
+ * This method builds panel that allows to select single challenge from input challenges.
+ */
+ private void build(int pageIndex)
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().user(this.user).name(this.user.getTranslation("challenges.gui.choose-challenge-title"));
+
+ GuiUtils.fillBorder(panelBuilder, Material.BLUE_STAINED_GLASS_PANE);
+
+ // Maximal elements in page.
+ final int MAX_ELEMENTS = 21;
+
+ final int correctPage;
+
+ if (pageIndex < 0)
+ {
+ correctPage = this.challengesList.size() / MAX_ELEMENTS;
+ }
+ else if (pageIndex > (this.challengesList.size() / MAX_ELEMENTS))
+ {
+ correctPage = 0;
+ }
+ else
+ {
+ correctPage = pageIndex;
+ }
+
+ panelBuilder.item(4,
+ new PanelItemBuilder().
+ icon(Material.RED_STAINED_GLASS_PANE).
+ name(this.user.getTranslation("challenges.gui.buttons.return")).
+ clickHandler( (panel, user1, clickType, slot) -> {
+ this.consumer.accept(false, null);
+ return true;
+ }).build());
+
+ if (this.challengesList.size() > MAX_ELEMENTS)
+ {
+ // Navigation buttons if necessary
+
+ panelBuilder.item(18,
+ new PanelItemBuilder().
+ icon(Material.SIGN).
+ name(this.user.getTranslation("challenges.gui.buttons.previous")).
+ clickHandler((panel, user1, clickType, slot) -> {
+ this.build(correctPage - 1);
+ return true;
+ }).build());
+
+ panelBuilder.item(26,
+ new PanelItemBuilder().
+ icon(Material.SIGN).
+ name(this.user.getTranslation("challenges.gui.buttons.next")).
+ clickHandler((panel, user1, clickType, slot) -> {
+ this.build(correctPage + 1);
+ return true;
+ }).build());
+ }
+
+ int challengesIndex = MAX_ELEMENTS * correctPage;
+
+ // I want first row to be only for navigation and return button.
+ int index = 10;
+
+ while (challengesIndex < ((correctPage + 1) * MAX_ELEMENTS) &&
+ challengesIndex < this.challengesList.size() &&
+ index < 36)
+ {
+ if (!panelBuilder.slotOccupied(index))
+ {
+ panelBuilder.item(index,
+ this.createChallengeButton(this.challengesList.get(challengesIndex++)));
+ }
+
+ index++;
+ }
+
+ panelBuilder.item(44,
+ new PanelItemBuilder().
+ icon(Material.OAK_DOOR).
+ name(this.user.getTranslation("challenges.gui.buttons.return")).
+ clickHandler( (panel, user1, clickType, slot) -> {
+ this.consumer.accept(false, null);
+ return true;
+ }).build());
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method builds PanelItem for given challenge.
+ * @param challenge Challenge which PanelItem must be created.
+ * @return new PanelItem for given Challenge.
+ */
+ private PanelItem createChallengeButton(Challenge challenge)
+ {
+ return new PanelItemBuilder().
+ name(challenge.getFriendlyName()).
+ description(GuiUtils.stringSplit(challenge.getDescription())).
+ icon(challenge.getIcon()).
+ clickHandler((panel, user1, clickType, slot) -> {
+ this.consumer.accept(true, challenge);
+ return true;
+ }).build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This variable stores consumer.
+ */
+ private BiConsumer consumer;
+
+ /**
+ * User who runs GUI.
+ */
+ private User user;
+
+ /**
+ * Current value.
+ */
+ private List