From 52b02e06bf921d57cdf00b3e43597b6f50e40612 Mon Sep 17 00:00:00 2001 From: BONNe Date: Thu, 24 Jan 2019 23:29:56 +0200 Subject: [PATCH] Rework TryToComplete class. Remove unnecessary code. --- .../challenges/panel/ChallengesPanels2.java | 24 +- .../challenges/panel/TryToComplete.java | 894 +++++++++++------- .../panel/admin/EditChallengeGUI.java | 1 + .../challenges/panel/user/ChallengesGUI.java | 7 +- 4 files changed, 584 insertions(+), 342 deletions(-) diff --git a/src/main/java/world/bentobox/challenges/panel/ChallengesPanels2.java b/src/main/java/world/bentobox/challenges/panel/ChallengesPanels2.java index ea56420..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,26 @@ 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.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.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; 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; /** @@ -152,7 +152,7 @@ public class ChallengesPanels2 { } else { // Player click itemBuilder.clickHandler((panel, player, c, s) -> { - new TryToComplete(addon, player, manager, challenge, world, permPrefix, label); + new TryToComplete(addon, player, challenge, world, label, permPrefix); return true; }); } diff --git a/src/main/java/world/bentobox/challenges/panel/TryToComplete.java b/src/main/java/world/bentobox/challenges/panel/TryToComplete.java index aadbc38..92b558a 100644 --- a/src/main/java/world/bentobox/challenges/panel/TryToComplete.java +++ b/src/main/java/world/bentobox/challenges/panel/TryToComplete.java @@ -3,387 +3,532 @@ */ 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.Challenge; -import world.bentobox.challenges.database.object.Challenge.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; + /** * 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 Challenge 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; + + +// --------------------------------------------------------------------- +// 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(Challenge 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.getRewardExperience()); // Run commands - runCommands(challenge.getRewardCommands()); - user.sendMessage("challenges.you-completed", "[challenge]", challenge.getFriendlyName()); - if (addon.getChallengesSettings().isBroadcastMessages()) { - 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.getRepeatExperienceReward()); // 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); - user.closeInventory(); - user.getPlayer().performCommand(label + " " + ChallengesCommand.CHALLENGE_COMMAND + " " + challenge.getLevel()); + this.manager.setChallengeComplete(this.user, this.challenge); + return result; } - /** - * @param addon - * @param user - * @param manager - * @param challenge - * @param world - * @param permPrefix - */ - public TryToComplete(ChallengesAddon addon, User user, ChallengesManager manager, Challenge 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.getRewardExperience()); - // Run commands - runCommands(challenge.getRewardCommands()); - user.sendMessage("challenges.you-completed", "[challenge]", challenge.getFriendlyName()); - if (addon.getChallengesSettings().isBroadcastMessages()) { - 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.getRepeatExperienceReward()); - // Run commands - runCommands(challenge.getRepeatRewardCommands()); - user.sendMessage("challenges.you-repeated", "[challenge]", challenge.getFriendlyName()); - } - // Mark as complete - manager.setChallengeComplete(user, challenge); - 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() + { + ChallengeType type = this.challenge.getChallengeType(); + // Check the world - if (!challenge.getUniqueId().startsWith(Util.getWorld(world).getName())) { - user.sendMessage("general.errors.wrong-world"); - return new ChallengeResult(); + if (!this.challenge.getUniqueId().startsWith(Util.getWorld(this.world).getName())) + { + this.user.sendMessage("general.errors.wrong-world"); } - // Check if user has the - if (!challenge.getLevel().equals(ChallengesManager.FREE) && !manager.isLevelUnlocked(user, world, manager.getLevel(challenge.getLevel()))) { - user.sendMessage("challenges.errors.challenge-level-not-available"); - return new ChallengeResult(); + // 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"); } // Check max times - if (challenge.isRepeatable() && challenge.getMaxTimes() > 0 && manager.getChallengeTimes(user, challenge) >= 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"); } // Check repeatability - if (manager.isChallengeComplete(user, challenge) - && (!challenge.isRepeatable() || challenge.getChallengeType().equals(ChallengeType.OTHER) - || 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.manager.isChallengeComplete(this.user, this.challenge) + && (!this.challenge.isRepeatable() || type.equals(ChallengeType.ISLAND))) { - if (!vaultHook.get().has(this.user, this.challenge.getRequiredMoney())) - { - this.user.sendMessage("challenges.not-enough-money", "[money]", Integer.toString(this.challenge.getRequiredMoney())); - return new ChallengeResult(); - } + this.user.sendMessage("challenges.not-repeatable"); } - - // Check exp - if (this.user.getPlayer().getTotalExperience() < this.challenge.getRequiredExperience()) + else if (type.equals(ChallengeType.INVENTORY)) { - this.user.sendMessage("challenges.not-enough-exp", "[xp]", Integer.toString(this.challenge.getRequiredExperience())); - return new ChallengeResult(); + return this.checkInventory(); + } + else if (type.equals(ChallengeType.ISLAND)) + { + return this.checkSurrounding(); + } + else if (type.equals(ChallengeType.OTHER)) + { + return this.checkOthers(); } - switch (challenge.getChallengeType()) { - case INVENTORY: - return checkInventory(); - case OTHER: - 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)); + // Everything fails till this point. + return new ChallengeResult(); } /** - * 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 runs all commands from command list. + * @param commands List of commands that must be performed. + */ + private void runCommands(List commands) { - Optional vaultHook = this.addon.getPlugin().getVault(); - - if (vaultHook.isPresent() && - this.challenge.isTakeMoney() && - this.challenge.getRequiredMoney() > 0) + // Ignore commands with this perm + if (user.hasPermission(this.permissionPrefix + "command.challengeexempt") && !user.isOp()) { - vaultHook.get().withdraw(this.user, this.challenge.getRequiredMoney()); + 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 new ChallengeResult(); + } + 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 new ChallengeResult(); + } + } + } + + // 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.getRequiredIslandLevel()) { - // process money removal - this.removeMoney(); - return new ChallengeResult().setMeetsRequirements(); - } else { - user.sendMessage("challenges.error.island-level", TextVariables.NUMBER, String.valueOf(challenge.getRequiredIslandLevel())); - 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.world, this.user)) { - // process money removal - this.removeMoney(); + // Player is not on island + this.user.sendMessage("challenges.error.not-on-island"); + result = new ChallengeResult(); + } + 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,92 +536,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)); + + blocks.forEach((k, v) -> user.sendMessage("challenges.error.you-still-need", + "[amount]", String.valueOf(v), + "[item]", Util.prettifyText(k.toString()))); - 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(); } /** - * 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 new ChallengeResult(); + } + + + /** + * 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 new ChallengeResult(); + } + + +// --------------------------------------------------------------------- +// Section: Private classes +// --------------------------------------------------------------------- + + + /** + * Contains flags on completion of challenge + * + * @author tastybento + */ + private class ChallengeResult + { private boolean meetsRequirements; + private boolean repeat; + + /** */ - 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/EditChallengeGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/EditChallengeGUI.java index 523a652..33d7653 100644 --- a/src/main/java/world/bentobox/challenges/panel/admin/EditChallengeGUI.java +++ b/src/main/java/world/bentobox/challenges/panel/admin/EditChallengeGUI.java @@ -24,6 +24,7 @@ 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 { diff --git a/src/main/java/world/bentobox/challenges/panel/user/ChallengesGUI.java b/src/main/java/world/bentobox/challenges/panel/user/ChallengesGUI.java index 575fe8d..b4f0775 100644 --- a/src/main/java/world/bentobox/challenges/panel/user/ChallengesGUI.java +++ b/src/main/java/world/bentobox/challenges/panel/user/ChallengesGUI.java @@ -14,10 +14,10 @@ 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.utils.LevelStatus; import world.bentobox.challenges.database.object.Challenge; import world.bentobox.challenges.panel.CommonGUI; import world.bentobox.challenges.panel.TryToComplete; +import world.bentobox.challenges.utils.LevelStatus; /** @@ -324,11 +324,10 @@ public class ChallengesGUI extends CommonGUI clickHandler((panel, user1, clickType, slot) -> { new TryToComplete(this.addon, this.user, - this.challengesManager, challenge, this.world, - this.permissionPrefix, - this.topLabel); + this.topLabel, + this.permissionPrefix); return true; }). glow(this.challengesManager.isChallengeComplete(this.user, challenge)).