diff options
Diffstat (limited to 'src/main/java/com')
75 files changed, 2386 insertions, 853 deletions
diff --git a/src/main/java/com/leonardobishop/quests/QuestCompleter.java b/src/main/java/com/leonardobishop/quests/QuestCompleter.java index b783540c..97357126 100644 --- a/src/main/java/com/leonardobishop/quests/QuestCompleter.java +++ b/src/main/java/com/leonardobishop/quests/QuestCompleter.java @@ -6,11 +6,16 @@ import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; import com.leonardobishop.quests.player.questprogressfile.TaskProgress; import com.leonardobishop.quests.quests.Quest; import com.leonardobishop.quests.quests.Task; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; -import java.util.Map; +import java.util.LinkedList; +import java.util.Queue; public class QuestCompleter implements Runnable { + private final Queue<QuestProgress> completionQueue = new LinkedList<>(); + private final Queue<QuestProgressFile> fullCheckQueue = new LinkedList<>(); private final Quests plugin; public QuestCompleter(Quests plugin) { @@ -19,12 +24,34 @@ public class QuestCompleter implements Runnable { @Override public void run() { - //TODO if it still runs like shit then maybe only process a few players per X ticks rather than the whole server in one go - for (QPlayer qPlayer : plugin.getPlayerManager().getQPlayers()) { - if (qPlayer.isOnlyDataLoaded()) { - continue; - } + this.processCompletionQueue(); + this.processFullCheckQueue(); + } + + private void processCompletionQueue() { + QuestProgress questProgress = completionQueue.poll(); + if (questProgress == null) return; + + Player player = Bukkit.getPlayer(questProgress.getPlayer()); + if (player != null && player.isOnline()) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + Quest quest = plugin.getQuestManager().getQuestById(questProgress.getQuestId()); + + if (!questProgressFile.hasStartedQuest(quest)) return; + + if (checkComplete(quest, questProgress)) { + questProgressFile.completeQuest(quest); + } + } + } + + private void processFullCheckQueue() { + QuestProgressFile questProgressFile = fullCheckQueue.poll(); + if (questProgressFile == null) return; + + Player player = Bukkit.getPlayer(questProgressFile.getPlayerUUID()); + if (player != null && player.isOnline()) { for (QuestProgress questProgress : questProgressFile.getAllQuestProgress()) { Quest quest = plugin.getQuestManager().getQuestById(questProgress.getQuestId()); if (quest == null) continue; @@ -44,4 +71,25 @@ public class QuestCompleter implements Runnable { } } } -}
\ No newline at end of file + + private boolean checkComplete(Quest quest, QuestProgress questProgress) { + boolean complete = true; + for (Task task : quest.getTasks()) { + TaskProgress taskProgress; + if ((taskProgress = questProgress.getTaskProgress(task.getId())) == null || !taskProgress.isCompleted()) { + complete = false; + break; + } + } + + return complete; + } + + public void queueSingular(QuestProgress questProgress) { + completionQueue.add(questProgress); + } + + public void queueFullCheck(QuestProgressFile questProgressFile) { + fullCheckQueue.add(questProgressFile); + } +} diff --git a/src/main/java/com/leonardobishop/quests/Quests.java b/src/main/java/com/leonardobishop/quests/Quests.java index c0ccf7db..5272e9ac 100644 --- a/src/main/java/com/leonardobishop/quests/Quests.java +++ b/src/main/java/com/leonardobishop/quests/Quests.java @@ -1,15 +1,20 @@ package com.leonardobishop.quests; -import com.leonardobishop.quests.api.QuestsPlaceholders; import com.leonardobishop.quests.bstats.Metrics; import com.leonardobishop.quests.commands.CommandQuests; import com.leonardobishop.quests.events.EventInventory; import com.leonardobishop.quests.events.EventPlayerJoin; import com.leonardobishop.quests.events.EventPlayerLeave; -import com.leonardobishop.quests.itemgetter.ItemGetter; -import com.leonardobishop.quests.itemgetter.ItemGetterLatest; -import com.leonardobishop.quests.itemgetter.ItemGetter_1_13; -import com.leonardobishop.quests.itemgetter.ItemGetter_Late_1_8; +import com.leonardobishop.quests.hooks.itemgetter.ItemGetter; +import com.leonardobishop.quests.hooks.itemgetter.ItemGetterLatest; +import com.leonardobishop.quests.hooks.itemgetter.ItemGetter_1_13; +import com.leonardobishop.quests.hooks.itemgetter.ItemGetter_Late_1_8; +import com.leonardobishop.quests.hooks.papi.IPlaceholderAPIHook; +import com.leonardobishop.quests.hooks.papi.PlaceholderAPIHook; +import com.leonardobishop.quests.hooks.title.Title; +import com.leonardobishop.quests.hooks.title.Title_Bukkit; +import com.leonardobishop.quests.hooks.title.Title_BukkitNoTimings; +import com.leonardobishop.quests.hooks.title.Title_Other; import com.leonardobishop.quests.obj.Messages; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.QPlayerManager; @@ -17,10 +22,7 @@ import com.leonardobishop.quests.quests.QuestManager; import com.leonardobishop.quests.quests.tasktypes.TaskType; import com.leonardobishop.quests.quests.tasktypes.TaskTypeManager; import com.leonardobishop.quests.quests.tasktypes.types.*; -import com.leonardobishop.quests.title.Title; -import com.leonardobishop.quests.title.Title_Bukkit; -import com.leonardobishop.quests.title.Title_BukkitNoTimings; -import com.leonardobishop.quests.title.Title_Other; +import com.leonardobishop.quests.quests.tasktypes.types.dependent.*; import com.leonardobishop.quests.updater.Updater; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; @@ -31,7 +33,6 @@ import org.bukkit.scheduler.BukkitTask; import java.io.*; import java.util.ArrayList; -import java.util.Map; public class Quests extends JavaPlugin { @@ -42,12 +43,14 @@ public class Quests extends JavaPlugin { private static Updater updater; private static Title title; private ItemGetter itemGetter; + private QuestCompleter questCompleter; private QuestsConfigLoader questsConfigLoader; private QuestsLogger questsLogger; + private IPlaceholderAPIHook placeholderAPIHook; private boolean brokenConfig = false; - private BukkitTask questCompleterTask; private BukkitTask questAutosaveTask; + private BukkitTask questQueuePollTask; public static Quests get() { return (Quests) Bukkit.getPluginManager().getPlugin("Quests"); @@ -98,7 +101,8 @@ public class Quests extends JavaPlugin { @Override public void onEnable() { - questsLogger = new QuestsLogger(this, LoggingLevel.INFO); + questsLogger = new QuestsLogger(this, QuestsLogger.LoggingLevel.INFO); + questCompleter = new QuestCompleter(this); taskTypeManager = new TaskTypeManager(this); questManager = new QuestManager(this); @@ -112,10 +116,6 @@ public class Quests extends JavaPlugin { Bukkit.getPluginManager().registerEvents(new EventInventory(this), this); Bukkit.getPluginManager().registerEvents(new EventPlayerLeave(this), this); - if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { - new QuestsPlaceholders(this).register(); - } - Metrics metrics = new Metrics(this); if (metrics.isEnabled()) { this.getQuestsLogger().info("Metrics started. This can be disabled at /plugins/bStats/config.yml."); @@ -146,6 +146,8 @@ public class Quests extends JavaPlugin { taskTypeManager.registerTaskType(new EnchantingTaskType()); taskTypeManager.registerTaskType(new DealDamageTaskType()); taskTypeManager.registerTaskType(new PermissionTaskType()); + taskTypeManager.registerTaskType(new DistancefromTaskType()); + taskTypeManager.registerTaskType(new CommandTaskType()); // TODO: FIX // taskTypeManager.registerTaskType(new BrewingCertainTaskType()); if (Bukkit.getPluginManager().isPluginEnabled("ASkyBlock")) { @@ -170,27 +172,37 @@ public class Quests extends JavaPlugin { if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { taskTypeManager.registerTaskType(new PlaceholderAPIEvaluateTaskType()); } + if (Bukkit.getPluginManager().isPluginEnabled("Essentials")) { + taskTypeManager.registerTaskType(new EssentialsMoneyEarnTaskType()); + taskTypeManager.registerTaskType(new EssentialsBalanceTaskType()); + } taskTypeManager.closeRegistrations(); reloadQuests(); - if (!questsConfigLoader.getBrokenFiles().isEmpty()) { - this.getQuestsLogger().severe("Quests has failed to load the following files:"); - for (Map.Entry<String, QuestsConfigLoader.ConfigLoadError> entry : questsConfigLoader.getBrokenFiles().entrySet()) { - this.getQuestsLogger().severe(" - " + entry.getKey() + ": " + entry.getValue().getMessage()); - } - } +// if (!questsConfigLoader.getBrokenFiles().isEmpty()) { +// this.getQuestsLogger().severe("Quests has failed to load the following files:"); +// for (Map.Entry<String, QuestsConfigLoader.ConfigLoadError> entry : questsConfigLoader.getBrokenFiles().entrySet()) { +// this.getQuestsLogger().severe(" - " + entry.getKey() + ": " + entry.getValue().getMessage()); +// } +// } for (Player player : Bukkit.getOnlinePlayers()) { - qPlayerManager.loadPlayer(player.getUniqueId(), false); + qPlayerManager.loadPlayer(player.getUniqueId()); } }); + if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { + this.placeholderAPIHook = new PlaceholderAPIHook(); + this.placeholderAPIHook.registerExpansion(this); + } + // this intentionally should not be documented boolean ignoreUpdates = false; try { ignoreUpdates = new File(this.getDataFolder() + File.separator + "stfuQuestsUpdate").exists(); } catch (Throwable ignored) { } + updater = new Updater(this); if (!ignoreUpdates) { Bukkit.getScheduler().runTaskAsynchronously(this, () -> { @@ -199,6 +211,10 @@ public class Quests extends JavaPlugin { } } + public IPlaceholderAPIHook getPlaceholderAPIHook() { + return placeholderAPIHook; + } + @Override public void onDisable() { for (TaskType taskType : getTaskTypeManager().getTaskTypes()) { @@ -207,11 +223,9 @@ public class Quests extends JavaPlugin { } catch (Exception ignored) { } } for (QPlayer qPlayer : qPlayerManager.getQPlayers()) { - if (qPlayer.isOnlyDataLoaded()) { - continue; - } qPlayer.getQuestProgressFile().saveToDisk(true); } + if (placeholderAPIHook != null) placeholderAPIHook.unregisterExpansion(); } public void reloadQuests() { @@ -222,36 +236,52 @@ public class Quests extends JavaPlugin { questsConfigLoader.loadConfig(); long autocompleteInterval = 12000; - long completerPollInterval = 100; if (!isBrokenConfig()) { autocompleteInterval = this.getConfig().getLong("options.performance-tweaking.quest-autocomplete-interval", 12000); - completerPollInterval = this.getConfig().getLong("options.performance-tweaking.quest-completer-poll-interval", 100); } + boolean autosaveTaskCancelled = true; if (questAutosaveTask != null) { try { questAutosaveTask.cancel(); - } catch (Exception ignored) { } + } catch (Exception ex) { + questsLogger.debug("Cannot cancel and restart quest autosave task"); + autosaveTaskCancelled = false; + } } - questAutosaveTask = Bukkit.getScheduler().runTaskTimer(this, () -> { - for (QPlayer qPlayer : qPlayerManager.getQPlayers()) { - if (qPlayer.isOnlyDataLoaded()) { - continue; + if (autosaveTaskCancelled) { + questAutosaveTask = Bukkit.getScheduler().runTaskTimer(this, () -> { + for (QPlayer qPlayer : qPlayerManager.getQPlayers()) { + qPlayer.getQuestProgressFile().saveToDisk(false); } - qPlayer.getQuestProgressFile().saveToDisk(false); - } - }, autocompleteInterval, autocompleteInterval); - if (questCompleterTask != null) { + }, autocompleteInterval, autocompleteInterval); + } + + boolean queuePollTaskCancelled = true; + long queueExecuteInterval = 1; + if (!isBrokenConfig()) { + queueExecuteInterval = this.getConfig().getLong("options.performance-tweaking.quest-queue-executor-interval", 1); + } + if (questQueuePollTask != null) { try { - questCompleterTask.cancel(); - } catch (Exception ignored) { } + questQueuePollTask.cancel(); + } catch (Exception ex) { + questsLogger.debug("Cannot cancel and restart quest autosave task"); + queuePollTaskCancelled = false; + } + } + if (queuePollTaskCancelled) { + questQueuePollTask = Bukkit.getScheduler().runTaskTimer(this, questCompleter, queueExecuteInterval, queueExecuteInterval); } - questCompleterTask = Bukkit.getScheduler().runTaskTimer(this, new QuestCompleter(this), 20, completerPollInterval); } public ItemStack getItemStack(String path, ConfigurationSection config, ItemGetter.Filter... excludes) { return itemGetter.getItem(path, config, this, excludes); } + public ItemGetter getItemGetter() { + return itemGetter; + } + private void setupVersionSpecific() { String version; try { @@ -330,6 +360,7 @@ public class Quests extends JavaPlugin { examples.add("example4.yml"); examples.add("example5.yml"); examples.add("example6.yml"); + examples.add("example7.yml"); examples.add("README.txt"); for (String name : examples) { @@ -356,6 +387,10 @@ public class Quests extends JavaPlugin { } } + public QuestCompleter getQuestCompleter() { + return questCompleter; + } + public QuestsLogger getQuestsLogger() { return questsLogger; } diff --git a/src/main/java/com/leonardobishop/quests/QuestsConfigLoader.java b/src/main/java/com/leonardobishop/quests/QuestsConfigLoader.java index 460b75d2..b6517e5e 100644 --- a/src/main/java/com/leonardobishop/quests/QuestsConfigLoader.java +++ b/src/main/java/com/leonardobishop/quests/QuestsConfigLoader.java @@ -1,11 +1,11 @@ package com.leonardobishop.quests; -import com.leonardobishop.quests.itemgetter.ItemGetter; +import com.leonardobishop.quests.hooks.itemgetter.ItemGetter; +import com.leonardobishop.quests.obj.Options; import com.leonardobishop.quests.obj.misc.QItemStack; import com.leonardobishop.quests.quests.Category; import com.leonardobishop.quests.quests.Quest; import com.leonardobishop.quests.quests.Task; -import com.leonardobishop.quests.quests.tasktypes.ConfigValue; import com.leonardobishop.quests.quests.tasktypes.TaskType; import org.apache.commons.lang.StringUtils; import org.bukkit.ChatColor; @@ -18,15 +18,15 @@ import java.io.IOException; import java.net.URI; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class QuestsConfigLoader { - private final Map<String, ConfigLoadError> brokenFiles = new HashMap<>(); + private final Map<String, List<ConfigProblem>> filesWithProblems = new HashMap<>(); private final Quests plugin; + private int problemsCount; public QuestsConfigLoader(Quests plugin) { this.plugin = plugin; @@ -37,7 +37,7 @@ public class QuestsConfigLoader { */ public void loadConfig() { plugin.reloadConfig(); - brokenFiles.clear(); + filesWithProblems.clear(); plugin.setBrokenConfig(false); // test CONFIG file integrity @@ -45,154 +45,237 @@ public class QuestsConfigLoader { YamlConfiguration config = new YamlConfiguration(); config.load(new File(plugin.getDataFolder() + File.separator + "config.yml")); } catch (Exception ex) { - brokenFiles.put("<MAIN CONFIG> config.yml", new ConfigLoadError(ConfigLoadErrorType.MALFORMED_YAML)); + filesWithProblems.put("<MAIN CONFIG> config.yml", Collections.singletonList(new ConfigProblem(ConfigProblemType.ERROR, ConfigProblemDescriptions.MALFORMED_YAML.getDescription()))); plugin.setBrokenConfig(true); - return; } - for (String id : plugin.getConfig().getConfigurationSection("categories").getKeys(false)) { - ItemStack displayItem = plugin.getItemStack("categories." + id + ".display", plugin.getConfig()); - boolean permissionRequired = plugin.getConfig().getBoolean("categories." + id + ".permission-required", false); + if (!plugin.isBrokenConfig()) { + for (String id : plugin.getConfig().getConfigurationSection("categories").getKeys(false)) { + ItemStack displayItem = plugin.getItemStack("categories." + id + ".display", plugin.getConfig()); + boolean permissionRequired = plugin.getConfig().getBoolean("categories." + id + ".permission-required", false); - Category category = new Category(id, displayItem, permissionRequired); - plugin.getQuestManager().registerCategory(category); - } - plugin.getQuestsLogger().setServerLoggingLevel(LoggingLevel.fromNumber(plugin.getConfig().getInt("options.verbose-logging-level", 2))); + Category category = new Category(id, displayItem, permissionRequired); + plugin.getQuestManager().registerCategory(category); + } + plugin.getQuestsLogger().setServerLoggingLevel(QuestsLogger.LoggingLevel.fromNumber(plugin.getConfig().getInt("options.verbose-logging-level", 2))); - FileVisitor<Path> fileVisitor = new SimpleFileVisitor<Path>() { - final URI questsRoot = Paths.get(plugin.getDataFolder() + File.separator + "quests").toUri(); + HashMap<String, Quest> pathToQuest = new HashMap<>(); - @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attributes) { - File questFile = new File(path.toUri()); - URI relativeLocation = questsRoot.relativize(path.toUri()); + FileVisitor<Path> fileVisitor = new SimpleFileVisitor<Path>() { + final URI questsRoot = Paths.get(plugin.getDataFolder() + File.separator + "quests").toUri(); - if (!questFile.getName().toLowerCase().endsWith(".yml")) return FileVisitResult.CONTINUE; + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attributes) { + File questFile = new File(path.toUri()); + URI relativeLocation = questsRoot.relativize(path.toUri()); - YamlConfiguration config = new YamlConfiguration(); - // test QUEST file integrity - try { - config.load(questFile); - } catch (Exception ex) { - brokenFiles.put(relativeLocation.getPath(), new ConfigLoadError(ConfigLoadErrorType.MALFORMED_YAML)); - return FileVisitResult.CONTINUE; - } + if (!questFile.getName().toLowerCase().endsWith(".yml")) return FileVisitResult.CONTINUE; - String id = questFile.getName().replace(".yml", ""); + YamlConfiguration config = new YamlConfiguration(); + // test QUEST file integrity + try { + config.load(questFile); + } catch (Exception ex) { + filesWithProblems.put(relativeLocation.getPath(), Collections.singletonList(new ConfigProblem(ConfigProblemType.ERROR, ConfigProblemDescriptions.MALFORMED_YAML.getDescription()))); + return FileVisitResult.CONTINUE; + } - if (!StringUtils.isAlphanumeric(id)) { - brokenFiles.put(relativeLocation.getPath(), new ConfigLoadError(ConfigLoadErrorType.INVALID_QUEST_ID)); - return FileVisitResult.CONTINUE; - } + String id = questFile.getName().replace(".yml", ""); + + List<ConfigProblem> configProblems = new ArrayList<>(); + + if (!StringUtils.isAlphanumeric(id)) { + configProblems.add(new ConfigProblem(ConfigProblemType.ERROR, ConfigProblemDescriptions.INVALID_QUEST_ID.getDescription(id))); + } + + // CHECK EVERYTHING WRONG WITH THE QUEST FILE BEFORE ACTUALLY LOADING THE QUEST + + if (!config.isConfigurationSection("tasks")) { + configProblems.add(new ConfigProblem(ConfigProblemType.ERROR, ConfigProblemDescriptions.NO_TASKS.getDescription(), "tasks")); + } else { //continue + int validTasks = 0; + for (String taskId : config.getConfigurationSection("tasks").getKeys(false)) { + boolean isValid = true; + String taskRoot = "tasks." + taskId; + String taskType = config.getString(taskRoot + ".type"); + + if (!config.isConfigurationSection(taskRoot)) { + configProblems.add(new ConfigProblem(ConfigProblemType.WARNING, ConfigProblemDescriptions.TASK_MALFORMED_NOT_SECTION.getDescription(taskId), taskRoot)); + continue; + } + + if (taskType == null) { + configProblems.add(new ConfigProblem(ConfigProblemType.WARNING, ConfigProblemDescriptions.NO_TASK_TYPE.getDescription(), taskRoot)); + continue; + } + + // check the tasks + TaskType t = plugin.getTaskTypeManager().getTaskType(taskType); + if (t != null) { + HashMap<String, Object> configValues = new HashMap<>(); + for (String key : config.getConfigurationSection(taskRoot).getKeys(false)) { + configValues.put(key, config.get(taskRoot + "." + key)); + } + + configProblems.addAll(t.detectProblemsInConfig(taskRoot, configValues)); + } else { + configProblems.add(new ConfigProblem(ConfigProblemType.WARNING, ConfigProblemDescriptions.UNKNOWN_TASK_TYPE.getDescription(taskType), taskRoot)); + isValid = false; + } + + if (isValid) { + validTasks++; + } + } + if (validTasks == 0) { + configProblems.add(new ConfigProblem(ConfigProblemType.ERROR, ConfigProblemDescriptions.NO_TASKS.getDescription(), "tasks")); + } + } - // CHECK EVERYTHING WRONG WITH THE QUEST FILE BEFORE ACTUALLY LOADING THE QUEST + boolean error = false; + for (ConfigProblem problem : configProblems) { + if (problem.getType() == ConfigProblemType.ERROR) { + error = true; + } + } - List<String> questErrors = new ArrayList<>(); - List<String> taskErrors = new ArrayList<>(); + // END OF THE CHECKING + + QItemStack displayItem = getQItemStack("display", config); + List<String> rewards = config.getStringList("rewards"); + List<String> requirements = config.getStringList("options.requires"); + List<String> rewardString = config.getStringList("rewardstring"); + List<String> startString = config.getStringList("startstring"); + boolean repeatable = config.getBoolean("options.repeatable", false); + boolean cooldown = config.getBoolean("options.cooldown.enabled", false); + boolean permissionRequired = config.getBoolean("options.permission-required", false); + int cooldownTime = config.getInt("options.cooldown.time", 10); + int sortOrder = config.getInt("options.sort-order", 1); + String category = config.getString("options.category"); + + if (category == null) category = ""; + + Quest quest; + if (category.equals("")) { + quest = new Quest(id, displayItem, rewards, requirements, repeatable, cooldown, cooldownTime, permissionRequired, rewardString, startString, sortOrder); + } else { + quest = new Quest(id, displayItem, rewards, requirements, repeatable, cooldown, cooldownTime, permissionRequired, rewardString, startString, category, sortOrder); + Category c = plugin.getQuestManager().getCategoryById(category); + if (c != null) { + c.registerQuestId(id); + } else { + configProblems.add(new ConfigProblem(ConfigProblemType.WARNING, ConfigProblemDescriptions.UNKNOWN_CATEGORY.getDescription(category), "options.category")); + } + } - if (!config.isConfigurationSection("tasks")) { - questErrors.add("'tasks' section not defined"); - } else { //continue for (String taskId : config.getConfigurationSection("tasks").getKeys(false)) { String taskRoot = "tasks." + taskId; String taskType = config.getString(taskRoot + ".type"); - if (!config.isConfigurationSection(taskRoot)) { - questErrors.add("task '" + taskId + "' cannot be read (has no children)"); - continue; + Task task = new Task(taskId, taskType); + + for (String key : config.getConfigurationSection(taskRoot).getKeys(false)) { + task.addConfigValue(key, config.get(taskRoot + "." + key)); } - // check the tasks - TaskType t = plugin.getTaskTypeManager().getTaskType(taskType); - if (t != null) { - List<String> missingFields = new ArrayList<>(); - for (ConfigValue cv : t.getCreatorConfigValues()) { - if (cv.isRequired() && config.get(taskRoot + "." + cv.getKey()) == null) - missingFields.add(cv.getKey()); + quest.registerTask(task); + } + + Pattern pattern = Pattern.compile("\\{([^}]+)}"); + + for (String line : displayItem.getLoreNormal()) { + Matcher matcher = pattern.matcher(line); + while (matcher.find()) { + String[] parts = matcher.group(1).split(":"); + boolean match = false; + for (Task t : quest.getTasks()) { + if (t.getId().equals(parts[0])) { + match = true; + break; + } } - if (!missingFields.isEmpty()) - taskErrors.add("task '" + taskId + "': '" + t.getType() + "' missing required field(s) '" + String.join(", ", missingFields) + "'"); + if (!match) + configProblems.add(new ConfigProblem(ConfigProblemType.WARNING, + ConfigProblemDescriptions.UNKNOWN_TASK_REFERENCE.getDescription(parts[0]), "display.lore-normal")); + } + } + for (String line : displayItem.getLoreStarted()) { + Matcher matcher = pattern.matcher(line); + while (matcher.find()) { + String[] parts = matcher.group(1).split(":"); + boolean match = false; + for (Task t : quest.getTasks()) { + if (t.getId().equals(parts[0])) { + match = true; + break; + } + } + if (!match) + configProblems.add(new ConfigProblem(ConfigProblemType.WARNING, + ConfigProblemDescriptions.UNKNOWN_TASK_REFERENCE.getDescription(parts[0]), "display.lore-started")); } } - } - if (!questErrors.isEmpty()) { //if the file quest is not okay, do not load the quest - brokenFiles.put(relativeLocation.getPath(), new ConfigLoadError(ConfigLoadErrorType.MALFORMED_QUEST, String.join("; ", questErrors))); - return FileVisitResult.CONTINUE; //next quest please! - } else if (!taskErrors.isEmpty()) { // likewise with tasks - brokenFiles.put(relativeLocation.getPath(), new ConfigLoadError(ConfigLoadErrorType.MALFORMED_TASK, String.join("; ", taskErrors))); + pathToQuest.put(relativeLocation.getPath(), quest); + if (!configProblems.isEmpty()) { + filesWithProblems.put(relativeLocation.getPath(), configProblems); + } + if (!error && !Options.ERROR_CHECKING_OVERRIDE.getBooleanValue(false)) { + if (plugin.getConfig().getBoolean("options.show-quest-registrations")) { + plugin.getQuestsLogger().info("Registering quest " + quest.getId() + " with " + quest.getTasks().size() + " tasks."); + } + plugin.getQuestManager().registerQuest(quest); + plugin.getTaskTypeManager().registerQuestTasksWithTaskTypes(quest); + } return FileVisitResult.CONTINUE; } + }; - // END OF THE CHECKING - - QItemStack displayItem = getQItemStack("display", config); - List<String> rewards = config.getStringList("rewards"); - List<String> requirements = config.getStringList("options.requires"); - List<String> rewardString = config.getStringList("rewardstring"); - List<String> startString = config.getStringList("startstring"); - boolean repeatable = config.getBoolean("options.repeatable", false); - boolean cooldown = config.getBoolean("options.cooldown.enabled", false); - boolean permissionRequired = config.getBoolean("options.permission-required", false); - int cooldownTime = config.getInt("options.cooldown.time", 10); - int sortOrder = config.getInt("options.sort-order", 1); - String category = config.getString("options.category"); - - if (category == null) category = ""; + try { + Files.walkFileTree(Paths.get(plugin.getDataFolder() + File.separator + "quests"), fileVisitor); + } catch (IOException e) { + e.printStackTrace(); + } - Quest quest; - if (category.equals("")) { - quest = new Quest(id, displayItem, rewards, requirements, repeatable, cooldown, cooldownTime, permissionRequired, rewardString, startString, sortOrder); - } else { - quest = new Quest(id, displayItem, rewards, requirements, repeatable, cooldown, cooldownTime, permissionRequired, rewardString, startString, category, sortOrder); - Category c = plugin.getQuestManager().getCategoryById(category); - if (c != null) { - c.registerQuestId(id); + // post-load checks + for (Map.Entry<String, Quest> loadedQuest : pathToQuest.entrySet()) { + List<ConfigProblem> configProblems = new ArrayList<>(); + for (String req : loadedQuest.getValue().getRequirements()) { + if (plugin.getQuestManager().getQuestById(req) == null) { + configProblems.add(new ConfigProblem(ConfigProblemType.WARNING, ConfigProblemDescriptions.UNKNOWN_REQUIREMENT.getDescription(req), "options.requires")); } } - for (String taskId : config.getConfigurationSection("tasks").getKeys(false)) { - String taskRoot = "tasks." + taskId; - String taskType = config.getString(taskRoot + ".type"); - - Task task = new Task(taskId, taskType); - - for (String key : config.getConfigurationSection(taskRoot).getKeys(false)) { - task.addConfigValue(key, config.get(taskRoot + "." + key)); + if (!configProblems.isEmpty()) { + if (filesWithProblems.containsKey(loadedQuest.getKey())) { + filesWithProblems.get(loadedQuest.getKey()).addAll(configProblems); + } else { + filesWithProblems.put(loadedQuest.getKey(), configProblems); } - - quest.registerTask(task); } + } - if (plugin.getConfig().getBoolean("options.show-quest-registrations")) { - plugin.getQuestsLogger().info("Registering quest " + quest.getId() + " with " + quest.getTasks().size() + " tasks."); + for (TaskType taskType : plugin.getTaskTypeManager().getTaskTypes()) { + try { + taskType.onReady(); + } catch (Exception e) { + e.printStackTrace(); } - plugin.getQuestManager().registerQuest(quest); - plugin.getTaskTypeManager().registerQuestTasksWithTaskTypes(quest); - return FileVisitResult.CONTINUE; } - }; - - try { - Files.walkFileTree(Paths.get(plugin.getDataFolder() + File.separator + "quests"), fileVisitor); - } catch (IOException e) { - e.printStackTrace(); } - for (TaskType taskType : plugin.getTaskTypeManager().getTaskTypes()) { - try { - taskType.onReady(); - } catch (Exception ignored) { } + problemsCount = 0; + for (List<QuestsConfigLoader.ConfigProblem> problemList : plugin.getQuestsConfigLoader().getFilesWithProblems().values()) { + problemsCount = problemsCount + problemList.size(); } } - /** - * Gets recent file errors during load. - * - * @return Errors during load, Map<String, ConfigLoadError> of file name and error - */ - public Map<String, ConfigLoadError> getBrokenFiles() { - return brokenFiles; + public Map<String, List<ConfigProblem>> getFilesWithProblems() { + return filesWithProblems; + } + + public int getProblemsCount() { + return problemsCount; } private QItemStack getQItemStack(String path, FileConfiguration config) { @@ -218,38 +301,107 @@ public class QuestsConfigLoader { ItemStack is = plugin.getItemStack(path, config, ItemGetter.Filter.DISPLAY_NAME, ItemGetter.Filter.LORE, ItemGetter.Filter.ENCHANTMENTS, ItemGetter.Filter.ITEM_FLAGS); - return new QItemStack(name, loreNormal, loreStarted, is); + return new QItemStack(plugin, name, loreNormal, loreStarted, is); + } + + public enum ConfigProblemDescriptions { + + MALFORMED_YAML("Malformed YAML file, cannot read config"), + INVALID_QUEST_ID("ID '%s' is invalid, must be alphanumeric, unique and with no spaces"), + NO_TASKS("Quest contains no valid tasks"), + NO_TASK_TYPE("Task type not specified"), + UNKNOWN_TASK_TYPE("Task type '%s' does not exist"), + NO_DISPLAY_NAME("No name specified"), + NO_DISPLAY_MATERIAL("No material specified"), + UNKNOWN_MATERIAL("Material '%s' does not exist"), + UNKNOWN_ENTITY_TYPE("Entity type '%s' does not exist"), + TASK_MALFORMED_NOT_SECTION("Task '%s' is not a configuration section (has no fields)"), + TASK_MISSING_FIELD("Required field '%s' is missing for task type '%s'"), + UNKNOWN_TASK_REFERENCE("Attempt to reference unknown task '%s'"), + UNKNOWN_CATEGORY("Category '%s' does not exist"), + UNKNOWN_REQUIREMENT("Quest requirement '%s' does not exist"); + + private final String description; + + ConfigProblemDescriptions(String description) { + this.description = description; + } + + @Override + public String toString() { + return getDescription(); + } + + public String getDescription(String... format) { + return String.format(description, (Object[]) format); + } } - public enum ConfigLoadErrorType { + public enum ConfigProblemType { - MALFORMED_YAML("Malformed YAML"), - INVALID_QUEST_ID("Invalid quest ID (must be alphanumeric)"), - MALFORMED_QUEST("Quest file is not configured properly: %s"), - MALFORMED_TASK("Tasks are not configured properly: %s"); + ERROR("Error", "E", ChatColor.RED, 1), + WARNING("Warning", "W", ChatColor.YELLOW, 2); - private String message; + private final String title; + private final String shortened; + private final ChatColor color; + private final int priority; - ConfigLoadErrorType(String message) { - this.message = message; + ConfigProblemType(String title, String shortened, ChatColor color, int priority) { + this.title = title; + this.shortened = shortened; + this.color = color; + this.priority = priority; } - public String getMessage() { - return message; + public String getTitle() { + return title; } + + public String getShortened() { + return shortened; + } + + public ChatColor getColor() { + return color; + } + + public int getPriority() { + return priority; + } + } - public class ConfigLoadError { - private ConfigLoadErrorType type; - private String[] extraInfo; + public static class ConfigProblem { + + private final ConfigProblemType type; + private final String description; + private final String location; + + public ConfigProblem(ConfigProblemType type, String description, String location) { + this.type = type; + this.description = description == null ? "?" : description; + ; + this.location = location == null ? "?" : location; + } - public ConfigLoadError(ConfigLoadErrorType type, String... extraInfo) { + public ConfigProblem(ConfigProblemType type, String description) { this.type = type; - this.extraInfo = extraInfo; + this.description = description == null ? "?" : description; + ; + this.location = "?"; + } + + public ConfigProblemType getType() { + return type; + } + + public String getDescription() { + return description; } - public String getMessage() { - return String.format(type.getMessage(), (Object[]) extraInfo); + public String getLocation() { + return location; } } } diff --git a/src/main/java/com/leonardobishop/quests/QuestsLogger.java b/src/main/java/com/leonardobishop/quests/QuestsLogger.java index 212592c2..895b03dd 100644 --- a/src/main/java/com/leonardobishop/quests/QuestsLogger.java +++ b/src/main/java/com/leonardobishop/quests/QuestsLogger.java @@ -2,7 +2,7 @@ package com.leonardobishop.quests; public class QuestsLogger { - private Quests plugin; + private final Quests plugin; private LoggingLevel serverLoggingLevel; public QuestsLogger(Quests plugin, LoggingLevel serverLoggingLevel) { @@ -53,29 +53,31 @@ public class QuestsLogger { public void severe(String str) { log(str, LoggingLevel.ERROR); } -} -enum LoggingLevel { - ERROR(0), - WARNING(1), - INFO(2), - DEBUG(3); - private int numericVerbosity; + public enum LoggingLevel { + ERROR(0), + WARNING(1), + INFO(2), + DEBUG(3); - LoggingLevel(int number) { - numericVerbosity = number; - } + private int numericVerbosity; - public int getNumericVerbosity() { - return numericVerbosity; - } + LoggingLevel(int number) { + numericVerbosity = number; + } - static LoggingLevel fromNumber(int number) { - for (LoggingLevel level : LoggingLevel.values()) { - if (level.getNumericVerbosity() == number) { - return level; + public int getNumericVerbosity() { + return numericVerbosity; + } + + static LoggingLevel fromNumber(int number) { + for (LoggingLevel level : LoggingLevel.values()) { + if (level.getNumericVerbosity() == number) { + return level; + } } + return LoggingLevel.INFO; } - return LoggingLevel.INFO; } + } diff --git a/src/main/java/com/leonardobishop/quests/api/QuestsPlaceholders.java b/src/main/java/com/leonardobishop/quests/api/QuestsPlaceholders.java index f9acb3bb..2836f7ee 100644 --- a/src/main/java/com/leonardobishop/quests/api/QuestsPlaceholders.java +++ b/src/main/java/com/leonardobishop/quests/api/QuestsPlaceholders.java @@ -4,38 +4,47 @@ import com.leonardobishop.quests.Quests; import com.leonardobishop.quests.api.enums.QuestStartResult; import com.leonardobishop.quests.obj.Options; import com.leonardobishop.quests.player.QPlayer; -import com.leonardobishop.quests.player.questprogressfile.QuestProgress; import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; import com.leonardobishop.quests.quests.Category; import com.leonardobishop.quests.quests.Quest; +import me.clip.placeholderapi.expansion.Cacheable; import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import java.util.concurrent.TimeUnit; -public class QuestsPlaceholders extends PlaceholderExpansion { +public class QuestsPlaceholders extends PlaceholderExpansion implements Cacheable { + private final Quests plugin; + private final Map<String, Map<String, String>> cache = new HashMap<>(); + private final Map<String, SimpleDateFormat> formats = new HashMap<>(); public QuestsPlaceholders(Quests plugin) { this.plugin = plugin; } @Override + public void clear() { + cache.clear(); + formats.clear(); + } + + @Override public String getIdentifier() { return "quests"; } @Override public String getAuthor() { - return this.plugin.getDescription().getAuthors().toString(); + return plugin.getDescription().getAuthors().toString(); } @Override public String getVersion() { - return this.plugin.getDescription().getVersion(); + return plugin.getDescription().getVersion(); } @Override @@ -43,224 +52,247 @@ public class QuestsPlaceholders extends PlaceholderExpansion { return true; } - //TODO maybe cache these results for a bit? all these calls could be heavy - @Override public String onPlaceholderRequest(Player p, String params) { - if (p == null || !p.isOnline()) - return null; + if (p == null || !p.isOnline()) return null; + if (cache.containsKey(p.getName()) && cache.get(p.getName()).containsKey(params)) return cache.get(p.getName()).get(params); - String[] key = params.split("_", 5); - QPlayer questP = this.plugin.getPlayerManager().getPlayer(p.getUniqueId()); + String[] args = params.split("_", 4); + if (args.length < 1) return "Invalid Placeholder"; - if (key[0].equals("all") || key[0].equals("completed") || key[0].equals("completedBefore") - || key[0].equals("completedbefore") || key[0].equals("started") || key[0].equals("categories")) { - if (key.length == 1) { - switch (key[0]) { - case "all": - return String.valueOf(this.plugin.getQuestManager().getQuests().size()); - case "completed": - return String.valueOf(questP.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.COMPLETED).size()); - case "completedbefore": - case "completedBefore": - return String.valueOf(questP.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.COMPLETED_BEFORE).size()); - case "started": - return String.valueOf(questP.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.STARTED).size()); - case "categories": - return String.valueOf(this.plugin.getQuestManager().getCategories().size()); - } - } else if (key[1].equals("list") || key[1].equals("l")) { - String separator = ","; - if (!(key.length == 2)) { - separator = key[2]; - } + final boolean save = args[args.length-1].toLowerCase().equals("cache"); + if (save) args = Arrays.copyOf(args, args.length - 1); - switch (key[0]) { - case "all": - return String.join(separator, this.plugin.getQuestManager().getQuests().toString()); - case "categories": - return String.join(separator, this.plugin.getQuestManager().getCategories().toString()); - case "completed": - List<String> listCompleted = new ArrayList<>(); - for (Quest qCompleted : questP.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.COMPLETED)) { - listCompleted.add(qCompleted.getDisplayNameStripped()); - } - return String.join(separator, listCompleted); - case "completedbefore": - case "completedBefore": - List<String> listCompletedBefore = new ArrayList<>(); - for (Quest qCompletedBefore : questP.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.COMPLETED_BEFORE)) { - listCompletedBefore.add(qCompletedBefore.getDisplayNameStripped()); - } - return String.join(separator, listCompletedBefore); - case "started": - List<String> listStarted = new ArrayList<>(); - for (Quest qStarted : questP.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.STARTED)) { - listStarted.add(qStarted.getDisplayNameStripped()); - } - return String.join(separator, listStarted); - } - } - return "null"; - } + final QPlayer qPlayer = plugin.getPlayerManager().getPlayer(p.getUniqueId()); + String split = args[args.length-1]; - if (key[0].startsWith("quest:") || key[0].startsWith("q:")) { - Quest quest = this.plugin.getQuestManager().getQuestById(key[0].substring(key[0].lastIndexOf(":") + 1)); - if (key.length < 2) { - if (quest != null) { - return quest.getId(); - } else { - return "null"; - } - } else if (key[1].equals("started") || key[1].equals("s")) { - if (quest != null && questP.getQuestProgressFile().getQuestProgress(quest).isStarted()) { - return "true"; - } - return "false"; - } else if (key[1].equals("completed") || key[1].equals("c")) { - if (quest != null && questP.getQuestProgressFile().getQuestProgress(quest).isCompleted()) { - return "true"; - } - return "false"; - } else if (key[1].equals("completedbefore") || key[1].equals("completedBefore") || key[1].equals("cB")) { - if (quest != null && questP.getQuestProgressFile().getQuestProgress(quest).isCompletedBefore()) { - return "true"; - } - return "false"; - } else if (key[1].equals("completiondate") || key[1].equals("completionDate")) { - if (quest != null && questP.getQuestProgressFile().getQuestProgress(quest).isCompleted()) { - SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); //TODO make configurable for all our american friends - return sdf.format(questP.getQuestProgressFile().getQuestProgress(quest).getCompletionDate()); - } - return "Never"; - } else if (key[1].equals("cooldown")) { - if (quest != null && questP.getQuestProgressFile().getQuestProgress(quest).isCompleted()) { - String time = this.plugin.convertToFormat(TimeUnit.SECONDS.convert(questP.getQuestProgressFile().getCooldownFor(quest), TimeUnit.MILLISECONDS)); - if (time.startsWith("-")) { - return "0"; - } - return time; - } - return "0"; - } else if (key[1].equals("canaccept") || key[1].equals("canAccept")) { - if (quest != null && questP.getQuestProgressFile().canStartQuest(quest) == QuestStartResult.QUEST_SUCCESS) { - return "true"; - } - return "false"; - } else if (key[1].equals("meetsrequirements") || key[1].equals("meetsRequirements")) { - if (quest != null && questP.getQuestProgressFile().hasMetRequirements(quest)) { - return "true"; - } - return "false"; - } else if (key[1].startsWith("task") || key[1].startsWith("t")) { - String[] t = key[1].split(":"); - if (key[2].equals("progress") || key[2].equals("p")) { - if (quest == null || questP.getQuestProgressFile().getQuestProgress(quest).getTaskProgress(t[1]).getProgress() == null) { - return "0"; - } - return String.valueOf(questP.getQuestProgressFile().getQuestProgress(quest).getTaskProgress(t[1]).getProgress()); - } else if (key[2].equals("completed") || key[2].equals("c")) { - if (quest == null || questP.getQuestProgressFile().getQuestProgress(quest).getTaskProgress(t[1]).isCompleted()) { - return "true"; + String result = "null"; + if (!args[0].contains(":")) { + if (args.length > 1 && split.equals(args[1])) split = ","; + + switch (args[0].toLowerCase()) { + case "all": + case "a": + final List<Quest> listAll = new ArrayList<>(plugin.getQuestManager().getQuests().values()); + result = (args.length == 1 ? String.valueOf(listAll.size()) : parseList((List<Quest>) listAll, args[1], split)); + break; + case "completed": + case "c": + final List<Quest> listCompleted = qPlayer.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.COMPLETED); + result = (args.length == 1 ? String.valueOf(listCompleted.size()) : parseList(listCompleted, args[1], split)); + break; + case "completedbefore": + case "cb": + final List<Quest> listCompletedB = qPlayer.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.COMPLETED_BEFORE); + result = (args.length == 1 ? String.valueOf(listCompletedB.size()) : parseList(listCompletedB, args[1], split)); + break; + case "started": + case "s": + final List<Quest> listStarted = qPlayer.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.STARTED); + result = (args.length == 1 ? String.valueOf(listStarted.size()) : parseList(listStarted, args[1], split)); + break; + case "categories": + if (args.length == 1) { + result = String.valueOf(plugin.getQuestManager().getCategories().size()); + } else { + final List<String> listCategories = new ArrayList<>(); + switch (args[1].toLowerCase()) { + case "list": + case "l": + plugin.getQuestManager().getCategories().forEach(c -> listCategories.add(c.getDisplayNameStripped())); + break; + case "listid": + case "lid": + plugin.getQuestManager().getCategories().forEach(c -> listCategories.add(c.getId())); + break; + default: + return args[0] + "_" + args[1] + "is not a valid placeholder"; + } + result = String.join(split, listCategories); } - return "false"; - } + break; + default: + return args[0] + "is not a valid placeholder"; } + } else { + final String[] key = args[0].split(":"); + switch (key[0].toLowerCase()) { + case "quest": + case "q": + if (key.length == 1) return "Please specify quest name"; - return "null"; - } + final Quest quest = plugin.getQuestManager().getQuestById(key[1]); + if (quest == null) return key[1] + "is not a quest"; - if (key[0].startsWith("category:") || key[0].startsWith("c:")) { - if (!Options.CATEGORIES_ENABLED.getBooleanValue()) { - return "Categories Disabled"; - } - Category category = this.plugin.getQuestManager().getCategoryById(key[0].substring(key[0].lastIndexOf(":") + 1)); - if (key.length < 2) { - if (category != null) { - return category.getId(); - } else { - return "null"; - } - } else if (key.length == 2) { - switch (key[1]) { - case "all": - case "a": - return String.valueOf(category.getRegisteredQuestIds().size()); - case "completed": - case "c": - return String.valueOf(getCategoryQuests(questP, category, QuestProgressFile.QuestsProgressFilter.COMPLETED).size()); - case "completedbefore": - case "completedBefore": - case "cB": - return String.valueOf(getCategoryQuests(questP, category, QuestProgressFile.QuestsProgressFilter.COMPLETED_BEFORE).size()); - case "started": - case "s": - return String.valueOf(getCategoryQuests(questP, category, QuestProgressFile.QuestsProgressFilter.STARTED).size()); - } - } else if (key[2].equals("list") || key[2].equals("l")) { - String separator = ","; - if (!(key.length == 3)) { - separator = key[3]; - } + if (args.length == 1) { + result = quest.getDisplayNameStripped(); + } else { + switch (args[1].toLowerCase()) { + case "started": + case "s": + result = (qPlayer.getQuestProgressFile().getQuestProgress(quest).isStarted() ? "true" : "false"); + break; + case "completed": + case "c": + result = (qPlayer.getQuestProgressFile().getQuestProgress(quest).isCompleted() ? "true" : "false"); + break; + case "completedbefore": + case "cb": + result = (qPlayer.getQuestProgressFile().getQuestProgress(quest).isCompletedBefore() ? "true" : "false"); + break; + case "completiondate": + case "cd": + if (qPlayer.getQuestProgressFile().getQuestProgress(quest).isCompleted()) { + result = parseDate(args, qPlayer.getQuestProgressFile().getQuestProgress(quest).getCompletionDate()); + } else { + result = "Never"; + } + break; + case "cooldown": + if (qPlayer.getQuestProgressFile().getQuestProgress(quest).isCompleted()) { + final String time = plugin.convertToFormat(TimeUnit.SECONDS.convert(qPlayer.getQuestProgressFile().getCooldownFor(quest), TimeUnit.MILLISECONDS)); + if (!time.startsWith("-")) result = time; + } else { + result = "0"; + } + break; + case "canaccept": + result = (qPlayer.getQuestProgressFile().canStartQuest(quest) == QuestStartResult.QUEST_SUCCESS ? "true" : "false"); + break; + case "meetsrequirements": + result = (qPlayer.getQuestProgressFile().hasMetRequirements(quest) ? "true" : "false"); + break; + default: + if (!args[1].contains(":")) return args[0] + "_" + args[1] + "is not a valid placeholder"; - switch (key[1]) { - case "all": - case "a": - List<String> listAll = new ArrayList<>(); - for (Quest qCompleted : getCategoryQuests(questP, category, QuestProgressFile.QuestsProgressFilter.ALL)) { - listAll.add(qCompleted.getDisplayNameStripped()); - } - return String.join(separator, listAll); - case "completed": - case "c": - List<String> listCompleted = new ArrayList<>(); - for (Quest qCompleted : getCategoryQuests(questP, category, QuestProgressFile.QuestsProgressFilter.COMPLETED)) { - listCompleted.add(qCompleted.getDisplayNameStripped()); - } - return String.join(separator, listCompleted); - case "completedbefore": - case "completedBefore": - case "cB": - List<String> listCompletedBefore = new ArrayList<>(); - for (Quest qCompletedBefore : getCategoryQuests(questP, category, QuestProgressFile.QuestsProgressFilter.COMPLETED_BEFORE)) { - listCompletedBefore.add(qCompletedBefore.getDisplayNameStripped()); + final String[] t = args[1].split(":"); + if (!t[0].toLowerCase().equals("task") && !t[0].toLowerCase().equals("t")) return args[0] + "_" + args[1] + "is not a valid placeholder"; + if (t.length == 1) return "Please specify task name"; + + if (args.length == 2) { + result = qPlayer.getQuestProgressFile().getQuestProgress(quest).getTaskProgress(t[1]).getTaskId(); + } else { + switch (args[2].toLowerCase()) { + case "progress": + case "p": + final Object progress = qPlayer.getQuestProgressFile().getQuestProgress(quest).getTaskProgress(t[1]).getProgress(); + result = (progress == null ? "0" : String.valueOf(progress)); + break; + case "completed": + case "c": + result = String.valueOf(qPlayer.getQuestProgressFile().getQuestProgress(quest).getTaskProgress(t[1]).isCompleted()); + break; + default: + return args[0] + "_" + args[1] + "_" + args[2] + "is not a valid placeholder"; + } + } } - return String.join(separator, listCompletedBefore); - case "started": - case "s": - List<String> listStarted = new ArrayList<>(); - for (Quest qStarted : getCategoryQuests(questP, category, QuestProgressFile.QuestsProgressFilter.STARTED)) { - listStarted.add(qStarted.getDisplayNameStripped()); + } + break; + case "category": + case "c": + if (!Options.CATEGORIES_ENABLED.getBooleanValue()) return "Categories Disabled"; + if (key.length == 1) return "Please specify category name"; + + final Category category = plugin.getQuestManager().getCategoryById(key[1]); + if (category == null) return key[1] + "is not a category"; + + if (args.length == 1) { + result = category.getDisplayNameStripped(); + } else { + if (args.length > 2 && split.equals(args[2])) split = ","; + switch (args[1].toLowerCase()) { + case "all": + case "a": + final List<Quest> listAll = getCategoryQuests(qPlayer, category, QuestProgressFile.QuestsProgressFilter.ALL); + result = (args.length == 2 ? String.valueOf(listAll.size()) : parseList(listAll, args[2], split)); + break; + case "completed": + case "c": + final List<Quest> listCompleted = getCategoryQuests(qPlayer, category, QuestProgressFile.QuestsProgressFilter.COMPLETED); + result = (args.length == 2 ? String.valueOf(listCompleted.size()) : parseList(listCompleted, args[2], split)); + break; + case "completedbefore": + case "cb": + final List<Quest> listCompletedB = getCategoryQuests(qPlayer, category, QuestProgressFile.QuestsProgressFilter.COMPLETED_BEFORE); + result = (args.length == 2 ? String.valueOf(listCompletedB.size()) : parseList(listCompletedB, args[2], split)); + break; + case "started": + case "s": + final List<Quest> listStarted = getCategoryQuests(qPlayer, category, QuestProgressFile.QuestsProgressFilter.STARTED); + result = (args.length == 2 ? String.valueOf(listStarted.size()) : parseList(listStarted, args[2], split)); + break; + default: + return args[0] + "_" + args[1] + "is not a valid placeholder"; } - return String.join(separator, listStarted); - } + } + break; + default: + return args[0] + "is not a valid placeholder"; } - return "null"; } - return null; + return (save ? cache(p.getName(), params, result) : result); } - private List<Quest> getCategoryQuests(QPlayer questP, Category category, QuestProgressFile.QuestsProgressFilter filter) { - List<Quest> categoryQuests = new ArrayList<>(); - for (String cQuests : category.getRegisteredQuestIds()) { - Quest quest = plugin.getQuestManager().getQuestById(cQuests); - if (quest == null) continue; + private String cache(String player, String params, String result) { + if (!cache.containsKey(player) || !cache.get(player).containsKey(params)) { + final Map<String, String> map = new HashMap<>(); + map.put(params, result); + cache.put(player, map); + Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> cache.get(player).remove(params), plugin.getConfig().getInt("options.placeholder-cache-time", 10) * 20); + } + return result; + } - boolean condition = false; - if (filter == QuestProgressFile.QuestsProgressFilter.STARTED) { - condition = questP.getQuestProgressFile().getQuestProgress(quest).isStarted(); - } else if (filter == QuestProgressFile.QuestsProgressFilter.COMPLETED_BEFORE) { - condition = questP.getQuestProgressFile().getQuestProgress(quest).isCompletedBefore(); - } else if (filter == QuestProgressFile.QuestsProgressFilter.COMPLETED) { - condition = questP.getQuestProgressFile().getQuestProgress(quest).isCompleted(); - } else if (filter == QuestProgressFile.QuestsProgressFilter.ALL) { - condition = true; - } + private String parseDate(String[] args, Long date) { + final String format = (args[args.length-1].equals(args[1]) ? "dd/MM/yyyy" : args[args.length-1]); + SimpleDateFormat sdf; + if (formats.containsKey(format)) { + sdf = formats.get(format); + } else { + sdf = new SimpleDateFormat(format); + formats.put(format, sdf); + } + return sdf.format(date); + } - if (condition) { - categoryQuests.add(quest); - } + private String parseList(List<Quest> list, String type, String separator) { + final List<String> quests = new ArrayList<>(); + switch (type.toLowerCase()) { + case "list": + case "l": + list.forEach(q -> quests.add(q.getDisplayNameStripped())); + break; + case "listid": + case "lid": + list.forEach(q -> quests.add(q.getId())); + break; + default: + return type + "is not a valid placeholder"; } + return String.join(separator, quests); + } + + private List<Quest> getCategoryQuests(QPlayer questP, Category category, QuestProgressFile.QuestsProgressFilter filter) { + final List<Quest> categoryQuests = new ArrayList<>(); + category.getRegisteredQuestIds().forEach(q -> { + Quest quest = plugin.getQuestManager().getQuestById(q); + if (quest != null) { + switch (filter) { + case STARTED: + if (questP.getQuestProgressFile().getQuestProgress(quest).isStarted()) categoryQuests.add(quest); + break; + case COMPLETED: + if (questP.getQuestProgressFile().getQuestProgress(quest).isCompleted()) categoryQuests.add(quest); + break; + case COMPLETED_BEFORE: + if (questP.getQuestProgressFile().getQuestProgress(quest).isCompletedBefore()) categoryQuests.add(quest); + break; + default: + categoryQuests.add(quest); + } + } + }); return categoryQuests; } } diff --git a/src/main/java/com/leonardobishop/quests/blocktype/Block.java b/src/main/java/com/leonardobishop/quests/blocktype/Block.java index 4fa71515..4b3b7d6a 100644 --- a/src/main/java/com/leonardobishop/quests/blocktype/Block.java +++ b/src/main/java/com/leonardobishop/quests/blocktype/Block.java @@ -2,6 +2,7 @@ package com.leonardobishop.quests.blocktype; import org.bukkit.Material; +@Deprecated public class Block { private Material material; diff --git a/src/main/java/com/leonardobishop/quests/commands/CommandQuests.java b/src/main/java/com/leonardobishop/quests/commands/CommandQuests.java index 382c3c1a..6c72a4e8 100644 --- a/src/main/java/com/leonardobishop/quests/commands/CommandQuests.java +++ b/src/main/java/com/leonardobishop/quests/commands/CommandQuests.java @@ -14,14 +14,20 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; +import org.bukkit.util.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.Map; -import java.util.UUID; +import java.io.File; +import java.io.IOException; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.*; -public class CommandQuests implements CommandExecutor { +public class CommandQuests implements TabExecutor { private final Quests plugin; @@ -32,13 +38,19 @@ public class CommandQuests implements CommandExecutor { @SuppressWarnings("deprecation") @Override public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { + if (plugin.getTaskTypeManager().areRegistrationsAccepted()) { + sender.sendMessage(ChatColor.RED + "Quests is not ready yet."); + return true; + } if (plugin.isBrokenConfig() && !(args.length >= 2 && (args[0].equalsIgnoreCase("a") || args[0].equalsIgnoreCase("admin")) && args[1].equalsIgnoreCase("reload"))) { - sender.sendMessage(ChatColor.RED + "The main config must be in tact before quests can be used. Quests has failed to load the following files:"); - for (Map.Entry<String, QuestsConfigLoader.ConfigLoadError> entry : plugin.getQuestsConfigLoader().getBrokenFiles().entrySet()) { - sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + entry.getKey() + ": " + ChatColor.GRAY + entry.getValue().getMessage()); + sender.sendMessage(ChatColor.RED + "Quests cannot be used right now. Please speak to an administrator."); + if (sender.hasPermission("quests.admin")) { + showProblems(sender); + sender.sendMessage(ChatColor.RED + "The main config (config.yml) must be in tact before quests can be used. " + + "Please use the above information to help rectify the problem."); } return true; } @@ -65,15 +77,11 @@ public class CommandQuests implements CommandExecutor { } else if (args[1].equalsIgnoreCase("reload")) { plugin.reloadConfig(); plugin.reloadQuests(); - Options.clearBoolValues(); - if (!plugin.getQuestsConfigLoader().getBrokenFiles().isEmpty()) { - sender.sendMessage(ChatColor.RED + "Quests has failed to load the following files:"); - for (Map.Entry<String, QuestsConfigLoader.ConfigLoadError> entry : plugin.getQuestsConfigLoader().getBrokenFiles().entrySet()) { - sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + entry.getKey() + ": " + ChatColor.GRAY + entry.getValue().getMessage()); - } - } else { - sender.sendMessage(ChatColor.GRAY + "Quests was reloaded."); - } + showProblems(sender); + sender.sendMessage(ChatColor.GRAY + "Quests successfully reloaded."); + return true; + } else if (args[1].equalsIgnoreCase("config")) { + showProblems(sender); return true; } else if (args[1].equalsIgnoreCase("types")) { sender.sendMessage(ChatColor.GRAY + "Registered task types:"); @@ -99,6 +107,41 @@ public class CommandQuests implements CommandExecutor { showAdminHelp(sender, "opengui"); return true; } else if (args[1].equalsIgnoreCase("moddata")) { + if (args[2].equalsIgnoreCase("clean")) { + FileVisitor<Path> fileVisitor = new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attributes) { + File playerDataFile = new File(path.toUri()); + if (!playerDataFile.getName().toLowerCase().endsWith(".yml")) return FileVisitResult.CONTINUE; + String uuidStr = playerDataFile.getName().replace(".yml", ""); + UUID uuid; + try { + uuid = UUID.fromString(uuidStr); + } catch (IllegalArgumentException ex) { + return FileVisitResult.CONTINUE; + } + + plugin.getPlayerManager().loadPlayer(uuid); + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(uuid); + qPlayer.getQuestProgressFile().clean(); + qPlayer.getQuestProgressFile().saveToDisk(false, true); + if (Bukkit.getPlayer(uuid) == null) { + plugin.getPlayerManager().dropPlayer(uuid); + } + return FileVisitResult.CONTINUE; + } + }; + //TODO command to clean specific player + try { + Files.walkFileTree(Paths.get(plugin.getDataFolder() + File.separator + "playerdata"), fileVisitor); + } catch (IOException e) { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_CLEAN_FAIL.getMessage()); + e.printStackTrace(); + return true; + } + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_CLEAN_SUCCESS.getMessage()); + return true; + } showAdminHelp(sender, "moddata"); return true; } else if (args[1].equalsIgnoreCase("types")) { @@ -140,7 +183,7 @@ public class CommandQuests implements CommandExecutor { String name; // Player.class is a superclass for OfflinePlayer. // getofflinePlayer return a player regardless if exists or not - if (ofp != null) { + if (ofp.hasPlayedBefore()) { uuid = ofp.getUniqueId(); name = ofp.getName(); } else { @@ -151,7 +194,7 @@ public class CommandQuests implements CommandExecutor { QPlayer qPlayer = plugin.getPlayerManager().getPlayer(uuid); if (qPlayer == null) { sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_LOADDATA.getMessage().replace("{player}", name)); - plugin.getPlayerManager().loadPlayer(uuid, true); + plugin.getPlayerManager().loadPlayer(uuid); qPlayer = plugin.getPlayerManager().getPlayer(uuid); //get again } if (qPlayer == null) { @@ -161,12 +204,12 @@ public class CommandQuests implements CommandExecutor { QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); questProgressFile.clear(); questProgressFile.saveToDisk(false); + if (Bukkit.getPlayer(uuid) == null) { + plugin.getPlayerManager().dropPlayer(uuid); + } sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_FULLRESET.getMessage().replace("{player}", name)); return true; } - if (plugin.getPlayerManager().getPlayer(uuid).isOnlyDataLoaded()) { - plugin.getPlayerManager().removePlayer(uuid); - } showAdminHelp(sender, "moddata"); return true; } @@ -204,7 +247,7 @@ public class CommandQuests implements CommandExecutor { OfflinePlayer ofp = Bukkit.getOfflinePlayer(args[3]); UUID uuid; String name; - if (ofp != null) { + if (ofp.hasPlayedBefore()) { uuid = ofp.getUniqueId(); name = ofp.getName(); } else { @@ -214,7 +257,7 @@ public class CommandQuests implements CommandExecutor { QPlayer qPlayer = plugin.getPlayerManager().getPlayer(uuid); if (qPlayer == null) { sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_LOADDATA.getMessage().replace("{player}", name)); - plugin.getPlayerManager().loadPlayer(uuid, true); + plugin.getPlayerManager().loadPlayer(uuid); } if (qPlayer == null) { sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_NODATA.getMessage().replace("{player}", name)); @@ -230,7 +273,7 @@ public class CommandQuests implements CommandExecutor { } if (args[2].equalsIgnoreCase("reset")) { questProgressFile.generateBlankQuestProgress(quest.getId()); - questProgressFile.saveToDisk(false); + questProgressFile.saveToDisk(false, true); sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_RESET_SUCCESS.getMessage().replace("{player}", name).replace("{quest}", quest.getId())); success = true; } else if (args[2].equalsIgnoreCase("start")) { @@ -266,12 +309,12 @@ public class CommandQuests implements CommandExecutor { sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_COMPLETE_SUCCESS.getMessage().replace("{player}", name).replace("{quest}", quest.getId())); success = true; } - if (plugin.getPlayerManager().getPlayer(uuid).isOnlyDataLoaded()) { - plugin.getPlayerManager().removePlayer(uuid); - } if (!success) { showAdminHelp(sender, "moddata"); } + if (Bukkit.getPlayer(uuid) == null) { + plugin.getPlayerManager().dropPlayer(uuid); + } return true; } } @@ -325,13 +368,64 @@ public class CommandQuests implements CommandExecutor { } } showHelp(sender); - return true; } else { sender.sendMessage(ChatColor.RED + "Only admin commands are available to non-player senders."); } return true; } + private void showProblems(CommandSender sender) { + if (!plugin.getQuestsConfigLoader().getFilesWithProblems().isEmpty()) { +// sender.sendMessage(ChatColor.DARK_GRAY.toString() + "----"); + sender.sendMessage(ChatColor.GRAY + "Detected problems and potential issues:"); + Set<QuestsConfigLoader.ConfigProblemType> problemTypes = new HashSet<>(); + for (Map.Entry<String, List<QuestsConfigLoader.ConfigProblem>> entry : plugin.getQuestsConfigLoader().getFilesWithProblems().entrySet()) { + HashMap<QuestsConfigLoader.ConfigProblemType, List<QuestsConfigLoader.ConfigProblem>> sortedProblems = new HashMap<>(); + for (QuestsConfigLoader.ConfigProblem problem : entry.getValue()) { + if (sortedProblems.containsKey(problem.getType())) { + sortedProblems.get(problem.getType()).add(problem); + } else { + List<QuestsConfigLoader.ConfigProblem> specificProblems = new ArrayList<>(); + specificProblems.add(problem); + sortedProblems.put(problem.getType(), specificProblems); + } + problemTypes.add(problem.getType()); + } + QuestsConfigLoader.ConfigProblemType highest = null; + for (QuestsConfigLoader.ConfigProblemType type : QuestsConfigLoader.ConfigProblemType.values()) { + if (sortedProblems.containsKey(type)) { + highest = type; + break; + } + } + ChatColor highestColor = ChatColor.WHITE; + if (highest != null) { + highestColor = highest.getColor(); + } + sender.sendMessage(highestColor + entry.getKey() + ChatColor.DARK_GRAY + " ----"); + for (QuestsConfigLoader.ConfigProblemType type : QuestsConfigLoader.ConfigProblemType.values()) { + if (sortedProblems.containsKey(type)) { + for (QuestsConfigLoader.ConfigProblem problem : sortedProblems.get(type)) { + sender.sendMessage(ChatColor.DARK_GRAY + " | - " + problem.getType().getColor() + + problem.getType().getShortened() + ChatColor.DARK_GRAY + ": " + + ChatColor.GRAY + problem.getDescription() + ChatColor.DARK_GRAY + " :" + problem.getLocation()); + } + } + } + } +// sender.sendMessage(ChatColor.DARK_GRAY.toString() + "----"); + List<String> legend = new ArrayList<>(); + for (QuestsConfigLoader.ConfigProblemType type : QuestsConfigLoader.ConfigProblemType.values()) { + if (problemTypes.contains(type)) + legend.add(type.getColor() + type.getShortened() + ChatColor.DARK_GRAY + " = " + type.getColor() + type.getTitle()); + } + sender.sendMessage(ChatColor.DARK_GRAY.toString() + "----"); + sender.sendMessage(ChatColor.GRAY.toString() + plugin.getQuestsConfigLoader().getProblemsCount() + " problem(s) | " + String.join(ChatColor.DARK_GRAY + ", ", legend)); + } else { + sender.sendMessage(ChatColor.GRAY + "Quests did not detect any problems with your configuration."); + } + } + private void showHelp(CommandSender sender) { sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "------------=[" + ChatColor.RED + " Quests v" + plugin .getDescription().getVersion() + " " + ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "]=------------"); @@ -349,7 +443,7 @@ public class CommandQuests implements CommandExecutor { sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "------------=[" + ChatColor.RED + " Quests Admin: opengui " + ChatColor .GRAY.toString() + ChatColor.STRIKETHROUGH + "]=------------"); sender.sendMessage(ChatColor.GRAY + "The following commands are available: "); - sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a opengui q/quest <player> " + ChatColor.DARK_GRAY + ": forcefully show" + + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a opengui q/quests <player> " + ChatColor.DARK_GRAY + ": forcefully show" + " quests for player"); sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a opengui c/category <player> <category> " + ChatColor.DARK_GRAY + ": " + "forcefully " + @@ -361,12 +455,14 @@ public class CommandQuests implements CommandExecutor { sender.sendMessage(ChatColor.GRAY + "The following commands are available: "); sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata fullreset <player> " + ChatColor.DARK_GRAY + ": clear a " + "players quest data file"); - sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata reset <player> <questid>" + ChatColor.DARK_GRAY + ": clear a " + + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata reset <player> <questid> " + ChatColor.DARK_GRAY + ": clear a " + "players data for specifc quest"); - sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata start <player> <questid>" + ChatColor.DARK_GRAY + ": start a " + + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata start <player> <questid> " + ChatColor.DARK_GRAY + ": start a " + "quest for a player"); - sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata complete <player> <questid>" + ChatColor.DARK_GRAY + ": " + + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata complete <player> <questid> " + ChatColor.DARK_GRAY + ": " + "complete a quest for a player"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata clean " + ChatColor.DARK_GRAY + ": " + + "clean quest data files for quests which are no longer defined"); sender.sendMessage(ChatColor.GRAY + "These commands modify quest progress for players. Use them cautiously. Changes are irreversible."); } else { sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "------------=[" + ChatColor.RED + " Quests Admin " + ChatColor.GRAY @@ -376,9 +472,99 @@ public class CommandQuests implements CommandExecutor { sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata " + ChatColor.DARK_GRAY + ": view help for quest progression"); sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a types [type]" + ChatColor.DARK_GRAY + ": view registered task types"); sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a reload " + ChatColor.DARK_GRAY + ": reload Quests configuration"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a config " + ChatColor.DARK_GRAY + ": see detected problems in config"); sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a update " + ChatColor.DARK_GRAY + ": check for updates"); } sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "-----=[" + ChatColor.RED + " requires permission: quests.admin " + ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "]=-----"); } + + private List<String> matchTabComplete(String arg, List<String> options) { + List<String> completions = new ArrayList<>(); + StringUtil.copyPartialMatches(arg, options, completions); + Collections.sort(completions); + return completions; + } + + private List<String> tabCompleteCategory(String arg) { + List<String> options = new ArrayList<>(); + for (Category c : plugin.getQuestManager().getCategories()) { + options.add(c.getId()); + } + return matchTabComplete(arg, options); + } + + private List<String> tabCompleteQuests(String arg) { + List<String> options = new ArrayList<>(plugin.getQuestManager().getQuests().keySet()); + return matchTabComplete(arg, options); + } + + @Nullable + @Override + public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { + if (!Options.TAB_COMPLETE_ENABLED.getBooleanValue(true)) { + return null; + } + if (sender instanceof Player) { + if (args.length == 1) { + List<String> options = new ArrayList<>(Arrays.asList("quest", "category")); + if (sender.hasPermission("quests.admin")) { + options.add("admin"); + } + return matchTabComplete(args[0], options); + } else if (args.length == 2) { + if (args[0].equalsIgnoreCase("c") || args[0].equalsIgnoreCase("category")) { + return tabCompleteCategory(args[1]); + } else if (args[0].equalsIgnoreCase("q") || args[0].equalsIgnoreCase("quest")) { + return tabCompleteQuests(args[1]); + } else if (args[0].equalsIgnoreCase("a") || args[0].equalsIgnoreCase("admin") + && sender.hasPermission("quests.admin")) { + List<String> options = Arrays.asList("opengui", "moddata", "types", "reload", "update", "config"); + return matchTabComplete(args[1], options); + } + } else if (args.length == 3) { + if (args[0].equalsIgnoreCase("q") || args[0].equalsIgnoreCase("quest") + && sender.hasPermission("quests.admin")) { + Quest q = plugin.getQuestManager().getQuestById(args[1]); + if (q != null) { + List<String> options = Arrays.asList("start", "cancel"); + return matchTabComplete(args[2], options); + } + } else if (args[0].equalsIgnoreCase("a") || args[0].equalsIgnoreCase("admin") + && sender.hasPermission("quests.admin")) { + if (args[1].equalsIgnoreCase("types")) { + List<String> options = new ArrayList<>(); + for (TaskType taskType : plugin.getTaskTypeManager().getTaskTypes()) { + options.add(taskType.getType()); + } + return matchTabComplete(args[2], options); + } else if (args[1].equalsIgnoreCase("opengui")) { + List<String> options = Arrays.asList("quests", "category"); + return matchTabComplete(args[2], options); + } else if (args[1].equalsIgnoreCase("moddata")) { + List<String> options = Arrays.asList("fullreset", "reset", "start", "complete", "clean"); + return matchTabComplete(args[2], options); + } + } + } else if (args.length == 4) { + if (sender.hasPermission("quests.admin")) return null; + } else if (args.length == 5) { + if (args[0].equalsIgnoreCase("a") || args[0].equalsIgnoreCase("admin") + && sender.hasPermission("quests.admin")) { + if (args[1].equalsIgnoreCase("opengui")) { + if (args[2].equalsIgnoreCase("c") || args[2].equalsIgnoreCase("category")) { + return tabCompleteCategory(args[4]); + } + } else if (args[1].equalsIgnoreCase("moddata")) { + if (args[2].equalsIgnoreCase("start") + || args[2].equalsIgnoreCase("complete") + || args[2].equalsIgnoreCase("reset")) { + return tabCompleteQuests(args[4]); + } + } + } + } + } + return Collections.emptyList(); + } } diff --git a/src/main/java/com/leonardobishop/quests/events/EventInventory.java b/src/main/java/com/leonardobishop/quests/events/EventInventory.java index aba0b12f..10f76538 100644 --- a/src/main/java/com/leonardobishop/quests/events/EventInventory.java +++ b/src/main/java/com/leonardobishop/quests/events/EventInventory.java @@ -1,14 +1,14 @@ package com.leonardobishop.quests.events; +import com.leonardobishop.quests.Quests; import com.leonardobishop.quests.api.enums.QuestStartResult; import com.leonardobishop.quests.obj.Messages; -import com.leonardobishop.quests.quests.Quest; -import com.leonardobishop.quests.Quests; import com.leonardobishop.quests.obj.Options; import com.leonardobishop.quests.obj.misc.QMenu; import com.leonardobishop.quests.obj.misc.QMenuCancel; import com.leonardobishop.quests.obj.misc.QMenuCategory; import com.leonardobishop.quests.obj.misc.QMenuQuest; +import com.leonardobishop.quests.quests.Quest; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.inventory.ClickType; @@ -22,12 +22,12 @@ import java.util.UUID; public class EventInventory implements Listener { - private static HashMap<UUID, QMenu> tracker = new HashMap<>(); - private Quests plugin; + private static final HashMap<UUID, QMenu> tracker = new HashMap<>(); + private final Quests plugin; // ADD PLAYERS TO THE BUFFER BEFORE AN ANTICIPATED MENU CHANGE SO THAT // THEY ARE NOT LOST FROM THE TRACKER WHEN CHANGING MENUS - private ArrayList<UUID> buffer = new ArrayList<>(); + private final ArrayList<UUID> buffer = new ArrayList<>(); public EventInventory(Quests plugin) { this.plugin = plugin; @@ -136,5 +136,4 @@ public class EventInventory implements Listener { buffer.remove(event.getPlayer().getUniqueId()); } else tracker.remove(event.getPlayer().getUniqueId()); } - } diff --git a/src/main/java/com/leonardobishop/quests/events/EventPlayerJoin.java b/src/main/java/com/leonardobishop/quests/events/EventPlayerJoin.java index 322316b1..52020ef7 100644 --- a/src/main/java/com/leonardobishop/quests/events/EventPlayerJoin.java +++ b/src/main/java/com/leonardobishop/quests/events/EventPlayerJoin.java @@ -2,6 +2,7 @@ package com.leonardobishop.quests.events; import com.leonardobishop.quests.Quests; import com.leonardobishop.quests.obj.Messages; +import com.leonardobishop.quests.obj.Options; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -11,7 +12,7 @@ import java.util.UUID; public class EventPlayerJoin implements Listener { - private Quests plugin; + private final Quests plugin; public EventPlayerJoin(Quests plugin) { this.plugin = plugin; @@ -20,7 +21,13 @@ public class EventPlayerJoin implements Listener { @EventHandler public void onEvent(PlayerJoinEvent event) { UUID playerUuid = event.getPlayer().getUniqueId(); - plugin.getPlayerManager().loadPlayer(playerUuid, false); + plugin.getPlayerManager().loadPlayer(playerUuid); + if (Options.SOFT_CLEAN_QUESTSPROGRESSFILE_ON_JOIN.getBooleanValue()) { + plugin.getPlayerManager().getPlayer(playerUuid).getQuestProgressFile().clean(); + if (Options.PUSH_SOFT_CLEAN_TO_DISK.getBooleanValue()) { + plugin.getPlayerManager().getPlayer(playerUuid).getQuestProgressFile().saveToDisk(false, true); + } + } if (plugin.getDescription().getVersion().contains("beta") && event.getPlayer().hasPermission("quests.admin")) { event.getPlayer().sendMessage(Messages.BETA_REMINDER.getMessage()); } @@ -28,6 +35,8 @@ public class EventPlayerJoin implements Listener { // delay for a bit so they actually see the message Bukkit.getScheduler().runTaskLater(this.plugin, () -> event.getPlayer().sendMessage(plugin.getUpdater().getMessage()), 50L); } + // run a full check to check for any missed quest completions + plugin.getQuestCompleter().queueFullCheck(plugin.getPlayerManager().getPlayer(playerUuid).getQuestProgressFile()); } } diff --git a/src/main/java/com/leonardobishop/quests/events/EventPlayerLeave.java b/src/main/java/com/leonardobishop/quests/events/EventPlayerLeave.java index 9992bc22..2253cbec 100644 --- a/src/main/java/com/leonardobishop/quests/events/EventPlayerLeave.java +++ b/src/main/java/com/leonardobishop/quests/events/EventPlayerLeave.java @@ -1,7 +1,6 @@ package com.leonardobishop.quests.events; import com.leonardobishop.quests.Quests; -import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; diff --git a/src/main/java/com/leonardobishop/quests/itemgetter/ItemGetter.java b/src/main/java/com/leonardobishop/quests/hooks/itemgetter/ItemGetter.java index 661d7302..a0d7545e 100644 --- a/src/main/java/com/leonardobishop/quests/itemgetter/ItemGetter.java +++ b/src/main/java/com/leonardobishop/quests/hooks/itemgetter/ItemGetter.java @@ -1,10 +1,8 @@ -package com.leonardobishop.quests.itemgetter; +package com.leonardobishop.quests.hooks.itemgetter; import com.leonardobishop.quests.Quests; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.java.JavaPlugin; public interface ItemGetter { @@ -29,6 +27,15 @@ public interface ItemGetter { */ ItemStack getItemStack(String material, Quests plugin); + /** + * Validates a material from a string. + * For pre-1.13 server implementations, the string may use a data code. + * + * @param material the string + * @return true if it a material + */ + boolean isValidMaterial(String material); + enum Filter { DISPLAY_NAME, LORE, diff --git a/src/main/java/com/leonardobishop/quests/itemgetter/ItemGetterLatest.java b/src/main/java/com/leonardobishop/quests/hooks/itemgetter/ItemGetterLatest.java index 4015385a..c33baac7 100644 --- a/src/main/java/com/leonardobishop/quests/itemgetter/ItemGetterLatest.java +++ b/src/main/java/com/leonardobishop/quests/hooks/itemgetter/ItemGetterLatest.java @@ -1,4 +1,4 @@ -package com.leonardobishop.quests.itemgetter; +package com.leonardobishop.quests.hooks.itemgetter; import com.leonardobishop.quests.Quests; import org.bukkit.ChatColor; @@ -7,13 +7,11 @@ import org.bukkit.NamespacedKey; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.plugin.java.JavaPlugin; import java.util.*; @@ -228,4 +226,14 @@ public class ItemGetterLatest implements ItemGetter { } return new ItemStack(type, 1); } + + @Override + public boolean isValidMaterial(String material) { + try { + Material.valueOf(material); + return true; + } catch (IllegalArgumentException ex) { + return false; + } + } } diff --git a/src/main/java/com/leonardobishop/quests/itemgetter/ItemGetter_1_13.java b/src/main/java/com/leonardobishop/quests/hooks/itemgetter/ItemGetter_1_13.java index b356f696..0e0850cd 100644 --- a/src/main/java/com/leonardobishop/quests/itemgetter/ItemGetter_1_13.java +++ b/src/main/java/com/leonardobishop/quests/hooks/itemgetter/ItemGetter_1_13.java @@ -1,4 +1,4 @@ -package com.leonardobishop.quests.itemgetter; +package com.leonardobishop.quests.hooks.itemgetter; import com.leonardobishop.quests.Quests; import org.bukkit.ChatColor; @@ -7,13 +7,11 @@ import org.bukkit.NamespacedKey; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.plugin.java.JavaPlugin; import java.util.*; @@ -218,4 +216,14 @@ public class ItemGetter_1_13 implements ItemGetter { } return new ItemStack(type, 1); } + + @Override + public boolean isValidMaterial(String material) { + try { + Material.valueOf(material); + return true; + } catch (IllegalArgumentException ex) { + return false; + } + } } diff --git a/src/main/java/com/leonardobishop/quests/itemgetter/ItemGetter_Late_1_8.java b/src/main/java/com/leonardobishop/quests/hooks/itemgetter/ItemGetter_Late_1_8.java index 696560b1..f3523b70 100644 --- a/src/main/java/com/leonardobishop/quests/itemgetter/ItemGetter_Late_1_8.java +++ b/src/main/java/com/leonardobishop/quests/hooks/itemgetter/ItemGetter_Late_1_8.java @@ -1,16 +1,14 @@ -package com.leonardobishop.quests.itemgetter; +package com.leonardobishop.quests.hooks.itemgetter; import com.leonardobishop.quests.Quests; import org.apache.commons.lang.StringUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.plugin.java.JavaPlugin; import java.util.ArrayList; import java.util.Arrays; @@ -142,4 +140,22 @@ public class ItemGetter_Late_1_8 implements ItemGetter { } return new ItemStack(type, 1, (short) data); } + + @Override + public boolean isValidMaterial(String material) { + Material type = null; + + if (Material.getMaterial(material) != null) { + type = Material.getMaterial(material); + } else if (material.contains(":")) { + String[] parts = material.split(Pattern.quote(":")); + if (parts.length > 1) { + if (Material.getMaterial(parts[0]) != null) { + type = Material.getMaterial(parts[0]); + } + } + } + + return !(type == null); + } } diff --git a/src/main/java/com/leonardobishop/quests/hooks/papi/IPlaceholderAPIHook.java b/src/main/java/com/leonardobishop/quests/hooks/papi/IPlaceholderAPIHook.java new file mode 100644 index 00000000..bc0c92a2 --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/hooks/papi/IPlaceholderAPIHook.java @@ -0,0 +1,14 @@ +package com.leonardobishop.quests.hooks.papi; + +import com.leonardobishop.quests.Quests; +import org.bukkit.entity.Player; + +public interface IPlaceholderAPIHook { + + String replacePlaceholders(Player player, String text); + + void registerExpansion(Quests plugin); + + void unregisterExpansion(); + +} diff --git a/src/main/java/com/leonardobishop/quests/hooks/papi/PlaceholderAPIHook.java b/src/main/java/com/leonardobishop/quests/hooks/papi/PlaceholderAPIHook.java new file mode 100644 index 00000000..13542b28 --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/hooks/papi/PlaceholderAPIHook.java @@ -0,0 +1,29 @@ +package com.leonardobishop.quests.hooks.papi; + +import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.api.QuestsPlaceholders; +import me.clip.placeholderapi.PlaceholderAPI; +import org.bukkit.entity.Player; + +public class PlaceholderAPIHook implements IPlaceholderAPIHook { + + private QuestsPlaceholders placeholder; + + public String replacePlaceholders(Player player, String text) { + return PlaceholderAPI.setPlaceholders(player, text); + } + + @Override + public void registerExpansion(Quests plugin) { + placeholder = new QuestsPlaceholders(plugin); + placeholder.register(); + } + + + @Override + public void unregisterExpansion() { + placeholder.unregister(); + } + + +} diff --git a/src/main/java/com/leonardobishop/quests/title/Title.java b/src/main/java/com/leonardobishop/quests/hooks/title/Title.java index 232c3b36..030d7455 100644 --- a/src/main/java/com/leonardobishop/quests/title/Title.java +++ b/src/main/java/com/leonardobishop/quests/hooks/title/Title.java @@ -1,4 +1,4 @@ -package com.leonardobishop.quests.title; +package com.leonardobishop.quests.hooks.title; import org.bukkit.entity.Player; diff --git a/src/main/java/com/leonardobishop/quests/title/Title_Bukkit.java b/src/main/java/com/leonardobishop/quests/hooks/title/Title_Bukkit.java index d05f815b..0f46771a 100644 --- a/src/main/java/com/leonardobishop/quests/title/Title_Bukkit.java +++ b/src/main/java/com/leonardobishop/quests/hooks/title/Title_Bukkit.java @@ -1,4 +1,4 @@ -package com.leonardobishop.quests.title; +package com.leonardobishop.quests.hooks.title; import org.bukkit.entity.Player; diff --git a/src/main/java/com/leonardobishop/quests/title/Title_BukkitNoTimings.java b/src/main/java/com/leonardobishop/quests/hooks/title/Title_BukkitNoTimings.java index 6bbbc32f..92ffdd16 100644 --- a/src/main/java/com/leonardobishop/quests/title/Title_BukkitNoTimings.java +++ b/src/main/java/com/leonardobishop/quests/hooks/title/Title_BukkitNoTimings.java @@ -1,4 +1,4 @@ -package com.leonardobishop.quests.title; +package com.leonardobishop.quests.hooks.title; import org.bukkit.entity.Player; diff --git a/src/main/java/com/leonardobishop/quests/title/Title_Other.java b/src/main/java/com/leonardobishop/quests/hooks/title/Title_Other.java index e4e998b9..ab7b7bf2 100644 --- a/src/main/java/com/leonardobishop/quests/title/Title_Other.java +++ b/src/main/java/com/leonardobishop/quests/hooks/title/Title_Other.java @@ -1,4 +1,4 @@ -package com.leonardobishop.quests.title; +package com.leonardobishop.quests.hooks.title; import org.bukkit.entity.Player; diff --git a/src/main/java/com/leonardobishop/quests/obj/Messages.java b/src/main/java/com/leonardobishop/quests/obj/Messages.java index b3c9ceab..92a0dca9 100644 --- a/src/main/java/com/leonardobishop/quests/obj/Messages.java +++ b/src/main/java/com/leonardobishop/quests/obj/Messages.java @@ -36,6 +36,8 @@ public enum Messages { BETA_REMINDER("messages.beta-reminder"), COMMAND_QUEST_ADMIN_LOADDATA("messages.command-quest-admin-loaddata"), COMMAND_QUEST_ADMIN_NODATA("messages.command-quest-admin-nodata"), + COMMAND_QUEST_ADMIN_CLEAN_SUCCESS("messages.command-quest-admin-clean-success"), + COMMAND_QUEST_ADMIN_CLEAN_FAIL("messages.command-quest-admin-clean-fail"), COMMAND_QUEST_ADMIN_FULLRESET("messages.command-quest-admin-fullreset"), COMMAND_QUEST_ADMIN_START_FAILLOCKED("messages.command-quest-admin-start-faillocked"), COMMAND_QUEST_ADMIN_START_FAILCOOLDOWN("messages.command-quest-admin-start-failcooldown"), diff --git a/src/main/java/com/leonardobishop/quests/obj/Options.java b/src/main/java/com/leonardobishop/quests/obj/Options.java index ffe8f6b7..9ed69fd7 100644 --- a/src/main/java/com/leonardobishop/quests/obj/Options.java +++ b/src/main/java/com/leonardobishop/quests/obj/Options.java @@ -17,11 +17,16 @@ public enum Options { GUI_HIDE_LOCKED("options.gui-hide-locked"), GUI_HIDE_QUESTS_NOPERMISSION("options.gui-hide-quests-nopermission"), GUI_HIDE_CATEGORIES_NOPERMISSION("options.gui-hide-categories-nopermission"), + GUI_USE_PLACEHOLDERAPI("options.gui-use-placeholderapi"), GUITITLE_QUESTS_CATEGORY("options.guinames.quests-category"), GUITITLE_QUESTS("options.guinames.quests-menu"), GUITITLE_DAILY_QUESTS("options.guinames.daily-quests"), GUITITLE_QUEST_CANCEL("options.guinames.quest-cancel"), ALLOW_QUEST_CANCEL("options.allow-quest-cancel"), + SOFT_CLEAN_QUESTSPROGRESSFILE_ON_JOIN("options.soft-clean-questsprogressfile-on-join"), + PUSH_SOFT_CLEAN_TO_DISK("options.tab-completion.push-soft-clean-to-disk"), + TAB_COMPLETE_ENABLED("options.tab-completion.enabled"), + ERROR_CHECKING_OVERRIDE("options.error-checking.override-errors"), QUEST_AUTOSTART("options.quest-autostart"); private static final Map<String, Boolean> cachedBools = new HashMap<>(); @@ -36,10 +41,18 @@ public enum Options { return Quests.get().getConfig().getInt(path); } + public int getIntValue(int def) { + return Quests.get().getConfig().getInt(path, def); + } + public String getStringValue() { return Quests.get().getConfig().getString(path); } + public String getStringValue(String def) { + return Quests.get().getConfig().getString(path, def); + } + public boolean getBooleanValue() { Boolean val = cachedBools.get(path); if (val != null) { @@ -50,6 +63,10 @@ public enum Options { } } + public boolean getBooleanValue(boolean def) { + return Quests.get().getConfig().getBoolean(path, def); + } + public List<String> getStringListValue() { return Quests.get().getConfig().getStringList(path); } diff --git a/src/main/java/com/leonardobishop/quests/obj/misc/QItemStack.java b/src/main/java/com/leonardobishop/quests/obj/misc/QItemStack.java index f7eca148..20bb3eb7 100644 --- a/src/main/java/com/leonardobishop/quests/obj/misc/QItemStack.java +++ b/src/main/java/com/leonardobishop/quests/obj/misc/QItemStack.java @@ -1,9 +1,13 @@ package com.leonardobishop.quests.obj.misc; +import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.obj.Options; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; import com.leonardobishop.quests.quests.Quest; +import org.bukkit.Bukkit; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -15,12 +19,15 @@ import java.util.regex.Pattern; public class QItemStack { + private final Quests plugin; + private String name; private List<String> loreNormal; private List<String> loreStarted; private ItemStack startingItemStack; - public QItemStack(String name, List<String> loreNormal, List<String> loreStarted, ItemStack startingItemStack) { + public QItemStack(Quests plugin, String name, List<String> loreNormal, List<String> loreStarted, ItemStack startingItemStack) { + this.plugin = plugin; this.name = name; this.loreNormal = loreNormal; this.loreStarted = loreStarted; @@ -66,6 +73,8 @@ public class QItemStack { ism.setDisplayName(name); List<String> formattedLore = new ArrayList<>(); List<String> tempLore = new ArrayList<>(loreNormal); + + Player player = Bukkit.getPlayer(questProgressFile.getPlayerUUID()); if (questProgressFile.hasStartedQuest(quest)) { tempLore.addAll(loreStarted); ism.addEnchant(Enchantment.ARROW_INFINITE, 1, true); @@ -76,6 +85,9 @@ public class QItemStack { } } + if (plugin.getPlaceholderAPIHook() != null && Options.GUI_USE_PLACEHOLDERAPI.getBooleanValue()) { + ism.setDisplayName(plugin.getPlaceholderAPIHook().replacePlaceholders(player, ism.getDisplayName())); + } if (questProgress != null) { for (String s : tempLore) { Matcher m = Pattern.compile("\\{([^}]+)}").matcher(s); @@ -95,6 +107,9 @@ public class QItemStack { } } } + if (plugin.getPlaceholderAPIHook() != null && Options.GUI_USE_PLACEHOLDERAPI.getBooleanValue()) { + s = plugin.getPlaceholderAPIHook().replacePlaceholders(player, s); + } formattedLore.add(s); } } diff --git a/src/main/java/com/leonardobishop/quests/obj/misc/QMenuCancel.java b/src/main/java/com/leonardobishop/quests/obj/misc/QMenuCancel.java index 9a4a2c4d..72445aaf 100644 --- a/src/main/java/com/leonardobishop/quests/obj/misc/QMenuCancel.java +++ b/src/main/java/com/leonardobishop/quests/obj/misc/QMenuCancel.java @@ -1,11 +1,10 @@ package com.leonardobishop.quests.obj.misc; -import com.leonardobishop.quests.player.QPlayer; -import com.leonardobishop.quests.quests.Quest; import com.leonardobishop.quests.obj.Items; import com.leonardobishop.quests.obj.Options; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.quests.Quest; import org.bukkit.Bukkit; -import org.bukkit.Material; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -78,22 +77,4 @@ public class QMenuCancel implements QMenu { return superMenu; } - public ItemStack replaceItemStack(ItemStack is, Map<String, String> placeholders) { - ItemStack newItemStack = is.clone(); - List<String> lore = newItemStack.getItemMeta().getLore(); - List<String> newLore = new ArrayList<>(); - ItemMeta ism = newItemStack.getItemMeta(); - if (lore != null) { - for (String s : lore) { - for (Map.Entry<String, String> entry : placeholders.entrySet()) { - s = s.replace(entry.getKey(), entry.getValue()); - ism.setDisplayName(ism.getDisplayName().replace(entry.getKey(), entry.getValue())); - } - newLore.add(s); - } - } - ism.setLore(newLore); - newItemStack.setItemMeta(ism); - return newItemStack; - } } diff --git a/src/main/java/com/leonardobishop/quests/obj/misc/QMenuCategory.java b/src/main/java/com/leonardobishop/quests/obj/misc/QMenuCategory.java index 3418831f..86f4d57f 100644 --- a/src/main/java/com/leonardobishop/quests/obj/misc/QMenuCategory.java +++ b/src/main/java/com/leonardobishop/quests/obj/misc/QMenuCategory.java @@ -1,14 +1,17 @@ package com.leonardobishop.quests.obj.misc; -import com.leonardobishop.quests.player.QPlayer; -import com.leonardobishop.quests.quests.Category; import com.leonardobishop.quests.Quests; import com.leonardobishop.quests.obj.Options; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.quests.Category; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -17,11 +20,13 @@ import java.util.List; */ public class QMenuCategory implements QMenu { + private final Quests plugin; private final int pageSize = 45; private final HashMap<Integer, QMenuQuest> slotsToMenuQuest = new HashMap<>(); private final QPlayer owner; - public QMenuCategory(QPlayer owner) { + public QMenuCategory(Quests plugin, QPlayer owner) { + this.plugin = plugin; this.owner = owner; } @@ -61,12 +66,12 @@ public class QMenuCategory implements QMenu { if (slotsToMenuQuest.containsKey(pointer)) { Category category = Quests.get().getQuestManager().getCategoryById(slotsToMenuQuest.get(pointer).getCategoryName()); if (category != null) { - inventory.setItem(pointer, category.getDisplayItem()); + inventory.setItem(pointer, replaceItemStack(category.getDisplayItem())); } } } - inventory.setItem(49, pageIs); + inventory.setItem(49, replaceItemStack(pageIs)); if (Options.TRIM_GUI_SIZE.getBooleanValue() && page == 1) { int slotsUsed = 0; @@ -85,7 +90,7 @@ public class QMenuCategory implements QMenu { Inventory trimmedInventory = Bukkit.createInventory(null, inventorySize, title); for (int slot = 0; slot < pageMax; slot++) { - if (slot >= trimmedInventory.getSize()){ + if (slot >= trimmedInventory.getSize()) { break; } trimmedInventory.setItem(slot, inventory.getItem(slot)); @@ -97,4 +102,25 @@ public class QMenuCategory implements QMenu { } + public ItemStack replaceItemStack(ItemStack is) { + if (plugin.getPlaceholderAPIHook() != null && Options.GUI_USE_PLACEHOLDERAPI.getBooleanValue()) { + ItemStack newItemStack = is.clone(); + List<String> lore = newItemStack.getItemMeta().getLore(); + List<String> newLore = new ArrayList<>(); + ItemMeta ism = newItemStack.getItemMeta(); + Player player = Bukkit.getPlayer(owner.getUuid()); + ism.setDisplayName(plugin.getPlaceholderAPIHook().replacePlaceholders(player, ism.getDisplayName())); + if (lore != null) { + for (String s : lore) { + s = plugin.getPlaceholderAPIHook().replacePlaceholders(player, s); + newLore.add(s); + } + } + ism.setLore(newLore); + newItemStack.setItemMeta(ism); + return newItemStack; + } + return is; + } + } diff --git a/src/main/java/com/leonardobishop/quests/obj/misc/QMenuDaily.java b/src/main/java/com/leonardobishop/quests/obj/misc/QMenuDaily.java index 220f288a..0e0cc132 100644 --- a/src/main/java/com/leonardobishop/quests/obj/misc/QMenuDaily.java +++ b/src/main/java/com/leonardobishop/quests/obj/misc/QMenuDaily.java @@ -1,8 +1,8 @@ package com.leonardobishop.quests.obj.misc; +import com.leonardobishop.quests.obj.Options; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.quests.Quest; -import com.leonardobishop.quests.obj.Options; import org.bukkit.Bukkit; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -99,22 +99,6 @@ public class QMenuDaily implements QMenu { return Bukkit.createInventory(null, 27, title); } - public ItemStack replaceItemStack(ItemStack is, Map<String, String> placeholders) { - ItemStack newItemStack = is.clone(); - List<String> lore = newItemStack.getItemMeta().getLore(); - List<String> newLore = new ArrayList<>(); - for (String s : lore) { - for (Map.Entry<String, String> entry : placeholders.entrySet()) { - s = s.replace(entry.getKey(), entry.getValue()); - } - newLore.add(s); - } - ItemMeta ism = newItemStack.getItemMeta(); - ism.setLore(newLore); - newItemStack.setItemMeta(ism); - return newItemStack; - } - //Implement too public QMenuCategory getSuperMenu() { return this.superMenu; diff --git a/src/main/java/com/leonardobishop/quests/obj/misc/QMenuQuest.java b/src/main/java/com/leonardobishop/quests/obj/misc/QMenuQuest.java index 622e4558..dbaf23ff 100644 --- a/src/main/java/com/leonardobishop/quests/obj/misc/QMenuQuest.java +++ b/src/main/java/com/leonardobishop/quests/obj/misc/QMenuQuest.java @@ -1,12 +1,13 @@ package com.leonardobishop.quests.obj.misc; -import com.leonardobishop.quests.player.QPlayer; -import com.leonardobishop.quests.player.questprogressfile.QuestProgress; -import com.leonardobishop.quests.quests.Quest; import com.leonardobishop.quests.Quests; import com.leonardobishop.quests.obj.Items; import com.leonardobishop.quests.obj.Options; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.quests.Quest; import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -19,18 +20,21 @@ import java.util.concurrent.TimeUnit; */ public class QMenuQuest implements QMenu { + private final Quests plugin; private final HashMap<Integer, String> slotsToQuestIds = new HashMap<>(); + private final QMenuCategory superMenu; + private final String categoryName; + private final int pageSize = 45; + private final QPlayer owner; + private int backButtonLocation = -1; private int pagePrevLocation = -1; private int pageNextLocation = -1; private int currentPage = -1; private boolean backButtonEnabled = true; - private final QMenuCategory superMenu; - private final String categoryName; - private final int pageSize = 45; - private final QPlayer owner; - public QMenuQuest(QPlayer owner, String categoryName, QMenuCategory superMenu) { + public QMenuQuest(Quests plugin, QPlayer owner, String categoryName, QMenuCategory superMenu) { + this.plugin = plugin; this.owner = owner; this.categoryName = categoryName; this.superMenu = superMenu; @@ -133,7 +137,8 @@ public class QMenuQuest implements QMenu { ItemStack is = replaceItemStack(Items.QUEST_COOLDOWN.getItem(), placeholders); inventory.setItem(invSlot, is); } else { - inventory.setItem(invSlot, Quests.get().getQuestManager().getQuestById(quest.getId()).getDisplayItem().toItemStack(quest, owner.getQuestProgressFile(), questProgress)); + inventory.setItem(invSlot, replaceItemStack(Quests.get().getQuestManager().getQuestById( + quest.getId()).getDisplayItem().toItemStack(quest, owner.getQuestProgressFile(), questProgress))); } } invSlot++; @@ -214,20 +219,33 @@ public class QMenuQuest implements QMenu { return superMenu; } + public ItemStack replaceItemStack(ItemStack is) { + return replaceItemStack(is, Collections.emptyMap()); + } + public ItemStack replaceItemStack(ItemStack is, Map<String, String> placeholders) { ItemStack newItemStack = is.clone(); List<String> lore = newItemStack.getItemMeta().getLore(); List<String> newLore = new ArrayList<>(); ItemMeta ism = newItemStack.getItemMeta(); + Player player = Bukkit.getPlayer(owner.getUuid()); if (lore != null) { for (String s : lore) { for (Map.Entry<String, String> entry : placeholders.entrySet()) { s = s.replace(entry.getKey(), entry.getValue()); - ism.setDisplayName(ism.getDisplayName().replace(entry.getKey(), entry.getValue())); + if (plugin.getPlaceholderAPIHook() != null && Options.GUI_USE_PLACEHOLDERAPI.getBooleanValue()) { + s = plugin.getPlaceholderAPIHook().replacePlaceholders(player, s); + } } newLore.add(s); } } + for (Map.Entry<String, String> entry : placeholders.entrySet()) { + ism.setDisplayName(ism.getDisplayName().replace(entry.getKey(), entry.getValue())); + if (plugin.getPlaceholderAPIHook() != null && Options.GUI_USE_PLACEHOLDERAPI.getBooleanValue()) { + ism.setDisplayName(plugin.getPlaceholderAPIHook().replacePlaceholders(player, ism.getDisplayName())); + } + } ism.setLore(newLore); newItemStack.setItemMeta(ism); return newItemStack; diff --git a/src/main/java/com/leonardobishop/quests/player/QPlayer.java b/src/main/java/com/leonardobishop/quests/player/QPlayer.java index 0f4e0da5..6c270fa1 100644 --- a/src/main/java/com/leonardobishop/quests/player/QPlayer.java +++ b/src/main/java/com/leonardobishop/quests/player/QPlayer.java @@ -11,23 +11,20 @@ import com.leonardobishop.quests.quests.Quest; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; public class QPlayer { private final UUID uuid; private final QuestProgressFile questProgressFile; - private boolean onlyDataLoaded; private final Quests plugin; - public QPlayer(UUID uuid, QuestProgressFile questProgressFile, Quests plugin) { - this(uuid, questProgressFile, false, plugin); - } - - public QPlayer(UUID uuid, QuestProgressFile questProgressFile, boolean onlyDataLoaded, Quests plugin) { + public QPlayer(UUID uuid, QuestProgressFile questProgressFile, Quests plugin) { this.uuid = uuid; this.questProgressFile = questProgressFile; - this.onlyDataLoaded = onlyDataLoaded; this.plugin = plugin; } @@ -39,10 +36,6 @@ public class QPlayer { * @return 0 if success, 1 if no permission, 2 is only data loaded, 3 if player not found */ public int openCategory(Category category, QMenuCategory superMenu, boolean backButton) { - if (onlyDataLoaded) { - return 2; - } - Player player = Bukkit.getPlayer(this.uuid); if (player == null) { return 3; @@ -53,7 +46,7 @@ public class QPlayer { } // Using `this` instead of searching again for this QPlayer - QMenuQuest qMenuQuest = new QMenuQuest(this, category.getId(), superMenu); + QMenuQuest qMenuQuest = new QMenuQuest(plugin, this, category.getId(), superMenu); List<Quest> quests = new ArrayList<>(); for (String questid : category.getRegisteredQuestIds()) { Quest quest = plugin.getQuestManager().getQuestById(questid); @@ -70,10 +63,6 @@ public class QPlayer { * @return 0 if success, 1 if no permission, 2 is only data loaded, 3 if player not found */ public int openCategory(Category category, QMenuQuest qMenuQuest) { - if (onlyDataLoaded) { - return 2; - } - Player player = Bukkit.getPlayer(this.uuid); if (player == null) { return 3; @@ -89,10 +78,6 @@ public class QPlayer { } public void openQuests() { - if (onlyDataLoaded) { - return; - } - if (this.uuid == null) { return; } @@ -102,10 +87,10 @@ public class QPlayer { } if (Options.CATEGORIES_ENABLED.getBooleanValue()) { - QMenuCategory qMenuCategory = new QMenuCategory(plugin.getPlayerManager().getPlayer(player.getUniqueId())); + QMenuCategory qMenuCategory = new QMenuCategory(plugin, plugin.getPlayerManager().getPlayer(player.getUniqueId())); List<QMenuQuest> questMenus = new ArrayList<>(); for (Category category : plugin.getQuestManager().getCategories()) { - QMenuQuest qMenuQuest = new QMenuQuest(plugin.getPlayerManager().getPlayer(player.getUniqueId()), category.getId(), qMenuCategory); + QMenuQuest qMenuQuest = new QMenuQuest(plugin, plugin.getPlayerManager().getPlayer(player.getUniqueId()), category.getId(), qMenuCategory); List<Quest> quests = new ArrayList<>(); for (String questid : category.getRegisteredQuestIds()) { Quest quest = plugin.getQuestManager().getQuestById(questid); @@ -121,7 +106,7 @@ public class QPlayer { player.openInventory(qMenuCategory.toInventory(1)); EventInventory.track(player.getUniqueId(), qMenuCategory); } else { - QMenuQuest qMenuQuest = new QMenuQuest(plugin.getPlayerManager().getPlayer(player.getUniqueId()), "", null); + QMenuQuest qMenuQuest = new QMenuQuest(plugin, plugin.getPlayerManager().getPlayer(player.getUniqueId()), "", null); List<Quest> quests = new ArrayList<>(); for (Map.Entry<String, Quest> entry : plugin.getQuestManager().getQuests().entrySet()) { quests.add(entry.getValue()); @@ -134,14 +119,6 @@ public class QPlayer { } } - public boolean isOnlyDataLoaded() { - return onlyDataLoaded; - } - - public void setOnlyDataLoaded(boolean onlyDataLoaded) { - this.onlyDataLoaded = onlyDataLoaded; - } - public QuestProgressFile getQuestProgressFile() { return questProgressFile; } diff --git a/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java b/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java index 13fa644d..d531f168 100644 --- a/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java +++ b/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java @@ -1,6 +1,7 @@ package com.leonardobishop.quests.player; import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.QuestsLogger; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; import com.leonardobishop.quests.player.questprogressfile.TaskProgress; @@ -37,22 +38,28 @@ public class QPlayerManager { * Gets the QPlayer from a given UUID. * * @param uuid the uuid - * @param loadIfNull load the QPlayer if the result is null and return the QPlayer if successfully loaded + * @param loadIfNull do not use * @return {@link QPlayer} if they are loaded */ public QPlayer getPlayer(UUID uuid, boolean loadIfNull) { QPlayer qPlayer = qPlayers.get(uuid); - if (qPlayer == null && loadIfNull) { - plugin.getQuestsLogger().debug("QPlayer of " + uuid + " is null, but was requested! Attempting to load it."); - loadPlayer(uuid, false); - return getPlayer(uuid, false); + if (qPlayer == null) { + plugin.getQuestsLogger().debug("QPlayer of " + uuid + " is null, but was requested:"); + if (plugin.getQuestsLogger().getServerLoggingLevel() == QuestsLogger.LoggingLevel.DEBUG) { + Thread.dumpStack(); + } } - return qPlayers.get(uuid); + return qPlayer; } public void removePlayer(UUID uuid) { + plugin.getQuestsLogger().debug("Unloading and saving player " + uuid + "."); this.getPlayer(uuid).getQuestProgressFile().saveToDisk(false); - plugin.getQuestsLogger().debug("Unloading player " + uuid + "."); + qPlayers.remove(uuid); + } + + public void dropPlayer(UUID uuid) { + plugin.getQuestsLogger().debug("Dropping player " + uuid + "."); qPlayers.remove(uuid); } @@ -65,10 +72,9 @@ public class QPlayerManager { // loadPlayer(uuid, false); //} - // TODO redo "onlyData" and use a less confusing way - public void loadPlayer(UUID uuid, boolean onlyData) { + public void loadPlayer(UUID uuid) { plugin.getQuestsLogger().debug("Loading player " + uuid + " from disk."); - if (getPlayer(uuid) == null || getPlayer(uuid).isOnlyDataLoaded()) { + if (qPlayers.get(uuid) == null) { QuestProgressFile questProgressFile = new QuestProgressFile(uuid, plugin); try { @@ -84,19 +90,23 @@ public class QPlayerManager { boolean completedBefore = data.getBoolean("quest-progress." + id + ".completed-before"); long completionDate = data.getLong("quest-progress." + id + ".completion-date"); - QuestProgress questProgress = new QuestProgress(id, completed, completedBefore, completionDate, uuid, started, true); + QuestProgress questProgress = new QuestProgress(plugin, id, completed, completedBefore, completionDate, uuid, started, true); - for (String taskid : data.getConfigurationSection("quest-progress." + id + ".task-progress").getKeys(false)) { - boolean taskCompleted = data.getBoolean("quest-progress." + id + ".task-progress." + taskid + ".completed"); - Object taskProgression = data.get("quest-progress." + id + ".task-progress." + taskid + ".progress"); + if (data.isConfigurationSection("quest-progress." + id + ".task-progress")) { + for (String taskid : data.getConfigurationSection("quest-progress." + id + ".task-progress").getKeys(false)) { + boolean taskCompleted = data.getBoolean("quest-progress." + id + ".task-progress." + taskid + ".completed"); + Object taskProgression = data.get("quest-progress." + id + ".task-progress." + taskid + ".progress"); - TaskProgress taskProgress = new TaskProgress(taskid, taskProgression, uuid, taskCompleted, false); - questProgress.addTaskProgress(taskProgress); + TaskProgress taskProgress = new TaskProgress(questProgress, taskid, taskProgression, uuid, taskCompleted, false); + questProgress.addTaskProgress(taskProgress); + } } questProgressFile.addQuestProgress(questProgress); } } + } else { + plugin.getQuestsLogger().debug("Player " + uuid + " does not have a quest progress file."); } } } catch (Exception ex) { @@ -105,9 +115,11 @@ public class QPlayerManager { // fuck } - QPlayer qPlayer = new QPlayer(uuid, questProgressFile, onlyData, plugin); + QPlayer qPlayer = new QPlayer(uuid, questProgressFile, plugin); this.qPlayers.put(uuid, qPlayer); + } else { + plugin.getQuestsLogger().debug("Player " + uuid + " is already loaded."); } } } diff --git a/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgress.java b/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgress.java index fe9108ce..442b802c 100644 --- a/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgress.java +++ b/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgress.java @@ -1,5 +1,7 @@ package com.leonardobishop.quests.player.questprogressfile; +import com.leonardobishop.quests.Quests; + import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -7,16 +9,20 @@ import java.util.UUID; public class QuestProgress { - private Map<String, TaskProgress> taskProgress = new HashMap<>(); - private String questid; + private final Quests plugin; + + private final Map<String, TaskProgress> taskProgress = new HashMap<>(); + private final String questid; + private final UUID player; + private boolean started; private boolean completed; private boolean completedBefore; private long completionDate; - private UUID player; private boolean modified; - public QuestProgress(String questid, boolean completed, boolean completedBefore, long completionDate, UUID player, boolean started) { + public QuestProgress(Quests plugin, String questid, boolean completed, boolean completedBefore, long completionDate, UUID player, boolean started) { + this.plugin = plugin; this.questid = questid; this.completed = completed; this.completedBefore = completedBefore; @@ -25,8 +31,8 @@ public class QuestProgress { this.started = started; } - public QuestProgress(String questid, boolean completed, boolean completedBefore, long completionDate, UUID player, boolean started, boolean modified) { - this(questid, completed, completedBefore, completionDate, player, started); + public QuestProgress(Quests plugin, String questid, boolean completed, boolean completedBefore, long completionDate, UUID player, boolean started, boolean modified) { + this(plugin, questid, completed, completedBefore, completionDate, player, started); this.modified = modified; } @@ -82,6 +88,10 @@ public class QuestProgress { return taskProgress.values(); } + public Map<String, TaskProgress> getTaskProgressMap() { + return taskProgress; + } + public TaskProgress getTaskProgress(String taskId) { TaskProgress tP = taskProgress.getOrDefault(taskId, null); if (tP == null) { @@ -92,10 +102,11 @@ public class QuestProgress { } public void repairTaskProgress(String taskid) { - TaskProgress taskProgress = new TaskProgress(taskid, null, player, false, false); + TaskProgress taskProgress = new TaskProgress(this, taskid, null, player, false, false); this.addTaskProgress(taskProgress); } + @Deprecated // this shit is annoying to maintain public boolean isWorthSaving() { if (modified) return true; else { @@ -106,6 +117,10 @@ public class QuestProgress { } } + public void queueForCompletionTest() { + plugin.getQuestCompleter().queueSingular(this); + } + public void resetModified() { this.modified = false; for (TaskProgress progress : this.taskProgress.values()) { diff --git a/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgressFile.java b/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgressFile.java index d3689185..83dcb80a 100644 --- a/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgressFile.java +++ b/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgressFile.java @@ -36,6 +36,10 @@ public class QuestProgressFile { public boolean completeQuest(Quest quest) { QuestProgress questProgress = getQuestProgress(quest); questProgress.setStarted(false); + for (TaskProgress taskProgress : questProgress.getTaskProgress()) { + taskProgress.setCompleted(false); + taskProgress.setProgress(null); + } questProgress.setCompleted(true); questProgress.setCompletedBefore(true); questProgress.setCompletionDate(System.currentTimeMillis()); @@ -76,7 +80,7 @@ public class QuestProgressFile { */ public QuestStartResult canStartQuest(Quest quest) { Player p = Bukkit.getPlayer(playerUUID); - if (getStartedQuests().size() >= Options.QUESTS_START_LIMIT.getIntValue()) { + if (getStartedQuests().size() >= Options.QUESTS_START_LIMIT.getIntValue() && !Options.QUEST_AUTOSTART.getBooleanValue()) { return QuestStartResult.QUEST_LIMIT_REACHED; } QuestProgress questProgress = getQuestProgress(quest); @@ -194,6 +198,13 @@ public class QuestProgressFile { player.sendMessage(ChatColor.translateAlternateColorCodes('&', s)); } } + for (Task task : quest.getTasks()) { + try { + plugin.getTaskTypeManager().getTaskType(task.getType()).onStart(quest, task, playerUUID); + } catch (Exception e) { + e.printStackTrace(); + } + } } return code; } @@ -367,9 +378,9 @@ public class QuestProgressFile { public boolean generateBlankQuestProgress(String questid) { if (plugin.getQuestManager().getQuestById(questid) != null) { Quest quest = plugin.getQuestManager().getQuestById(questid); - QuestProgress questProgress = new QuestProgress(quest.getId(), false, false, 0, playerUUID, false, false); + QuestProgress questProgress = new QuestProgress(plugin, quest.getId(), false, false, 0, playerUUID, false, false); for (Task task : quest.getTasks()) { - TaskProgress taskProgress = new TaskProgress(task.getId(), null, playerUUID, false, false); + TaskProgress taskProgress = new TaskProgress(questProgress, task.getId(), null, playerUUID, false, false); questProgress.addTaskProgress(taskProgress); } @@ -379,7 +390,15 @@ public class QuestProgressFile { return false; } + public void saveToDisk() { + saveToDisk(false, false); + } + public void saveToDisk(boolean disable) { + saveToDisk(disable, false); + } + + public void saveToDisk(boolean disable, boolean fullWrite) { plugin.getQuestsLogger().debug("Saving player " + playerUUID + " to disk."); File directory = new File(plugin.getDataFolder() + File.separator + "playerdata"); if (!directory.exists() && !directory.isDirectory()) { @@ -395,11 +414,8 @@ public class QuestProgressFile { } YamlConfiguration data = YamlConfiguration.loadConfiguration(file); - //data.set("quest-progress", null); + data.set("quest-progress", null); for (QuestProgress questProgress : questProgress.values()) { - if (!questProgress.isWorthSaving()) { - continue; - } data.set("quest-progress." + questProgress.getQuestId() + ".started", questProgress.isStarted()); data.set("quest-progress." + questProgress.getQuestId() + ".completed", questProgress.isCompleted()); data.set("quest-progress." + questProgress.getQuestId() + ".completed-before", questProgress.isCompletedBefore()); @@ -433,4 +449,33 @@ public class QuestProgressFile { questProgress.clear(); } + /** + * Removes any references to quests or tasks which are no longer defined in the config + */ + public void clean() { + plugin.getQuestsLogger().debug("Cleaning file " + playerUUID + "."); + if (!plugin.getTaskTypeManager().areRegistrationsAccepted()) { + ArrayList<String> invalidQuests = new ArrayList<>(); + for (String questId : this.questProgress.keySet()) { + Quest q; + if ((q = plugin.getQuestManager().getQuestById(questId)) == null) { + invalidQuests.add(questId); + } else { + ArrayList<String> invalidTasks = new ArrayList<>(); + for (String taskId : this.questProgress.get(questId).getTaskProgressMap().keySet()) { + if (q.getTaskById(taskId) == null) { + invalidTasks.add(taskId); + } + } + for (String taskId : invalidTasks) { + this.questProgress.get(questId).getTaskProgressMap().remove(taskId); + } + } + } + for (String questId : invalidQuests) { + this.questProgress.remove(questId); + } + } + } + } diff --git a/src/main/java/com/leonardobishop/quests/player/questprogressfile/TaskProgress.java b/src/main/java/com/leonardobishop/quests/player/questprogressfile/TaskProgress.java index a4c71460..fa361a7a 100644 --- a/src/main/java/com/leonardobishop/quests/player/questprogressfile/TaskProgress.java +++ b/src/main/java/com/leonardobishop/quests/player/questprogressfile/TaskProgress.java @@ -4,20 +4,24 @@ import java.util.UUID; public class TaskProgress { + private final QuestProgress questProgress; + private final String taskid; + private final UUID player; + private boolean modified; - private String taskid; private Object progress; - private UUID player; private boolean completed; - public TaskProgress(String taskid, Object progress, UUID player, boolean completed) { + public TaskProgress(QuestProgress questProgress, String taskid, Object progress, UUID player, boolean completed) { + this.questProgress = questProgress; this.taskid = taskid; this.progress = progress; + this.player = player; this.completed = completed; } - public TaskProgress(String taskid, Object progress, UUID player, boolean completed, boolean modified) { - this(taskid, progress, player, completed); + public TaskProgress(QuestProgress questProgress, String taskid, Object progress, UUID player, boolean completed, boolean modified) { + this(questProgress, taskid, progress, player, completed); this.modified = modified; } @@ -45,6 +49,10 @@ public class TaskProgress { public void setCompleted(boolean complete) { this.completed = complete; this.modified = true; + + if (complete) { + questProgress.queueForCompletionTest(); + } } public boolean isModified() { diff --git a/src/main/java/com/leonardobishop/quests/quests/Category.java b/src/main/java/com/leonardobishop/quests/quests/Category.java index dd2683ed..0fdedad4 100644 --- a/src/main/java/com/leonardobishop/quests/quests/Category.java +++ b/src/main/java/com/leonardobishop/quests/quests/Category.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests; +import org.bukkit.ChatColor; import org.bukkit.inventory.ItemStack; import java.util.ArrayList; @@ -7,9 +8,9 @@ import java.util.List; public class Category { - private String id; - private ItemStack displayItem; - private boolean permissionRequired; + private final String id; + private final ItemStack displayItem; + private final boolean permissionRequired; private final List<String> registeredQuestIds = new ArrayList<>(); public Category(String id, ItemStack displayItem, boolean permissionRequired) { @@ -22,26 +23,14 @@ public class Category { return id; } - public void setId(String id) { - this.id = id; - } - public boolean isPermissionRequired() { return permissionRequired; } - public void setPermissionRequired(boolean permissionRequired) { - this.permissionRequired = permissionRequired; - } - public ItemStack getDisplayItem() { return displayItem; } - public void setDisplayItem(ItemStack displayItem) { - this.displayItem = displayItem; - } - public void registerQuestId(String questid) { registeredQuestIds.add(questid); } @@ -49,4 +38,9 @@ public class Category { public List<String> getRegisteredQuestIds() { return registeredQuestIds; } + + + public String getDisplayNameStripped() { + return ChatColor.stripColor(this.displayItem.getItemMeta().getDisplayName()); + } } diff --git a/src/main/java/com/leonardobishop/quests/quests/Quest.java b/src/main/java/com/leonardobishop/quests/quests/Quest.java index ab02bd19..78bbc6b0 100644 --- a/src/main/java/com/leonardobishop/quests/quests/Quest.java +++ b/src/main/java/com/leonardobishop/quests/quests/Quest.java @@ -8,7 +8,7 @@ import java.util.*; public class Quest implements Comparable<Quest> { private Map<String, Task> tasks = new HashMap<>(); - //TODO: maybe store by <tasktypename (string), list<task>> since we never get task by id, but always get tasks by type. + //TODO: maybe ALSO store by <tasktypename (string), list<task>> private final String id; private final QItemStack displayItem; private final List<String> rewards; @@ -19,7 +19,7 @@ public class Quest implements Comparable<Quest> { private final boolean cooldownEnabled; private final int cooldown; private final int sortOrder; - private boolean permissionRequired; + private final boolean permissionRequired; private String categoryid; @@ -50,6 +50,10 @@ public class Quest implements Comparable<Quest> { return tasks.values(); } + public Task getTaskById(String id) { + return tasks.get(id); + } + public List<Task> getTasksOfType(String type) { List<Task> tasks = new ArrayList<>(); for (Task task : getTasks()) { @@ -65,10 +69,6 @@ public class Quest implements Comparable<Quest> { return permissionRequired; } - public void setPermissionRequired(boolean permissionRequired) { - this.permissionRequired = permissionRequired; - } - public List<String> getRewardString() { return rewardString; } diff --git a/src/main/java/com/leonardobishop/quests/quests/QuestManager.java b/src/main/java/com/leonardobishop/quests/quests/QuestManager.java index 35c13efc..022c2c89 100644 --- a/src/main/java/com/leonardobishop/quests/quests/QuestManager.java +++ b/src/main/java/com/leonardobishop/quests/quests/QuestManager.java @@ -2,7 +2,10 @@ package com.leonardobishop.quests.quests; import com.leonardobishop.quests.Quests; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; public class QuestManager { diff --git a/src/main/java/com/leonardobishop/quests/quests/Task.java b/src/main/java/com/leonardobishop/quests/quests/Task.java index eb9cd1b4..ca0f7150 100644 --- a/src/main/java/com/leonardobishop/quests/quests/Task.java +++ b/src/main/java/com/leonardobishop/quests/quests/Task.java @@ -6,9 +6,8 @@ import java.util.Map; public class Task { private final Map<String, Object> configValues = new HashMap<>(); - - private String id; - private String type; + private final String id; + private final String type; public Task(String id, String type) { this.id = id; @@ -27,6 +26,10 @@ public class Task { return configValues.getOrDefault(key, null); //??? this will return null without the need of `OrDefault(key, null)` } + public Object getConfigValue(String key, boolean def) { + return configValues.getOrDefault(key, def); + } + public Map<String, Object> getConfigValues() { return configValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/ConfigValue.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/ConfigValue.java index 4232da32..06a8f2f1 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/ConfigValue.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/ConfigValue.java @@ -8,11 +8,13 @@ public final class ConfigValue { private final String key; private final boolean required; private final String description; + private final String[] requirementExceptions; - public ConfigValue(String key, boolean required, String description) { + public ConfigValue(String key, boolean required, String description, String... requirementExceptions) { this.key = key; this.required = required; this.description = description; + this.requirementExceptions = requirementExceptions; } public String getKey() { @@ -26,4 +28,8 @@ public final class ConfigValue { public String getDescription() { return description; } + + public String[] getRequirementExceptions() { + return requirementExceptions; + } } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskType.java index 1e8a0433..a085a89c 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskType.java @@ -1,11 +1,11 @@ package com.leonardobishop.quests.quests.tasktypes; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.quests.Quest; +import com.leonardobishop.quests.quests.Task; import org.bukkit.event.Listener; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; /** * A task type which can be used within Quests. A {@link Quest} @@ -77,14 +77,34 @@ public abstract class TaskType implements Listener { } public List<ConfigValue> getCreatorConfigValues() { + // not implemented here return Collections.emptyList(); } + /** + * Called when Quests has finished registering all quests to the task type + * May be called several times if an operator uses /quests admin reload + */ public void onReady() { // not implemented here } + /** + * Called when a player starts a quest containing a task of this type + */ + public void onStart(Quest quest, Task task, UUID playerUUID) { + // not implemented here + } + public void onDisable() { // not implemented here } + + /** + * Called when Quests reloads the configuration - used to detect errors in the configuration of your task type + */ + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + // not implemented here + return Collections.emptyList(); + } } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskTypeManager.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskTypeManager.java index 7b01d463..d5196af0 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskTypeManager.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskTypeManager.java @@ -9,7 +9,7 @@ import java.util.ArrayList; public class TaskTypeManager { - private Quests plugin; + private final Quests plugin; private boolean allowRegistrations; public TaskTypeManager(Quests plugin) { @@ -21,6 +21,10 @@ public class TaskTypeManager { allowRegistrations = false; } + public boolean areRegistrationsAccepted() { + return allowRegistrations; + } + private ArrayList<TaskType> taskTypes = new ArrayList<>(); public ArrayList<TaskType> getTaskTypes() { diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskUtils.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskUtils.java index e036a4c1..f7f2768b 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskUtils.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskUtils.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.quests.Task; import org.bukkit.entity.Player; @@ -36,4 +37,51 @@ public class TaskUtils { return true; } + + public static void configValidateInt(String path, Object object, List<QuestsConfigLoader.ConfigProblem> problems, boolean allowNull, boolean greaterThanZero, String... args) { + if (object == null) { + if (!allowNull) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.ERROR, + String.format("Expected an integer for '%s', but got null instead", (Object[]) args), path)); + } + return; + } + + try { + Integer i = (Integer) object; + if (greaterThanZero && i <= 0) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.ERROR, + String.format("Value for field '%s' must be greater than 0", (Object[]) args), path)); + } + } catch (ClassCastException ex) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.ERROR, + String.format("Expected an integer for '%s', but got '" + object + "' instead", (Object[]) args), path)); + } + } + + public static void configValidateBoolean(String path, Object object, List<QuestsConfigLoader.ConfigProblem> problems, boolean allowNull, String... args) { + if (object == null) { + if (!allowNull) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.ERROR, + String.format("Expected a boolean for '%s', but got null instead", (Object[]) args), path)); + } + return; + } + + try { + Boolean b = (Boolean) object; + } catch (ClassCastException ex) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.ERROR, + String.format("Expected a boolean for '%s', but got '" + object + "' instead", (Object[]) args), path)); + } + } + + public static boolean configValidateExists(String path, Object object, List<QuestsConfigLoader.ConfigProblem> problems, String... args) { + if (object == null) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.ERROR, + String.format(QuestsConfigLoader.ConfigProblemDescriptions.TASK_MISSING_FIELD.getDescription(args), (Object[]) args), path)); + return false; + } + return true; + } } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BreedingTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BreedingTaskType.java index b18bcd08..5130815e 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BreedingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BreedingTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -18,6 +19,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class BreedingTaskType extends TaskType { @@ -31,6 +33,14 @@ public final class BreedingTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BrewingTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BrewingTaskType.java index fdee1dc9..15a02d03 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BrewingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BrewingTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -38,6 +39,14 @@ public final class BrewingTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BuildingCertainTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BuildingCertainTaskType.java index 73252665..44e49c97 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BuildingCertainTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BuildingCertainTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -18,6 +19,7 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class BuildingCertainTaskType extends TaskType { @@ -35,6 +37,43 @@ public final class BuildingCertainTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + if (config.get("block") == null && config.get("blocks") == null) { + TaskUtils.configValidateExists(root + ".block", config.get("block"), problems, "block", super.getType()); + } else { + Object configBlock; + String source; + if (config.containsKey("block")) { + source = "block"; + } else { + source = "blocks"; + } + configBlock = config.get(source); + List<String> checkBlocks = new ArrayList<>(); + if (configBlock instanceof List) { + checkBlocks.addAll((List) configBlock); + } else { + checkBlocks.add(String.valueOf(configBlock)); + } + + for (String materialName : checkBlocks) { + String[] split = materialName.split(":"); + if (Material.getMaterial(String.valueOf(split[0])) == null) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.WARNING, + QuestsConfigLoader.ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(materialName), root + "." + source)); + } + } + } + TaskUtils.configValidateBoolean(root + ".reverse-if-broken", config.get("reverse-if-broken"), problems, true,"reverse-if-broken"); + TaskUtils.configValidateBoolean(root + ".use-similar-blocks", config.get("use-similar-blocks"), problems, true,"use-similar-blocks"); + TaskUtils.configValidateInt(root + ".data", config.get("data"), problems, true,true, "data"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } @@ -123,8 +162,9 @@ public final class BuildingCertainTaskType extends TaskType { short blockData = block.getData(); - if (blockType.equals(material)) { - return configData == null || ((int) blockData) == comparableData; + if (blockType == material) { + if (((split.length == 1 && configData == null) || ((int) blockData) == comparableData)) + return true; } } return false; diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BuildingTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BuildingTaskType.java index b25c70af..bf8d9172 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BuildingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BuildingTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -15,6 +16,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockPlaceEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class BuildingTaskType extends TaskType { @@ -28,6 +30,14 @@ public final class BuildingTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/CommandTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/CommandTaskType.java new file mode 100644 index 00000000..4a1d096c --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/CommandTaskType.java @@ -0,0 +1,96 @@ +package com.leonardobishop.quests.quests.tasktypes.types; + +import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.api.QuestsAPI; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.quests.Quest; +import com.leonardobishop.quests.quests.Task; +import com.leonardobishop.quests.quests.tasktypes.ConfigValue; +import com.leonardobishop.quests.quests.tasktypes.TaskType; +import com.leonardobishop.quests.quests.tasktypes.TaskUtils; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class CommandTaskType extends TaskType { + + private List<ConfigValue> creatorConfigValues = new ArrayList<>(); + + public CommandTaskType() { + super("command", "LMBishop", "Execute a certain command."); + this.creatorConfigValues.add(new ConfigValue("command", true, "The command to execute.")); + this.creatorConfigValues.add(new ConfigValue("ignore-case", false, "Ignore the casing of the command.")); + this.creatorConfigValues.add(new ConfigValue("worlds", false, "Permitted worlds the player must be in.")); + } + + @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".command", config.get("command"), problems, "command", super.getType()); + TaskUtils.configValidateBoolean(root + ".ignore-case", config.get("ignore-case"), problems, true, "ignore-case", super.getType()); + return problems; + } + + @Override + public List<ConfigValue> getCreatorConfigValues() { + return creatorConfigValues; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onCommand(PlayerCommandPreprocessEvent e) { + Player player = e.getPlayer(); + + QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(player.getUniqueId(), true); + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + + for (Quest quest : super.getRegisteredQuests()) { + if (questProgressFile.hasStartedQuest(quest)) { + QuestProgress questProgress = questProgressFile.getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + Object configCommand = task.getConfigValue("command"); + Object configIgnoreCase = task.getConfigValue("ignore-case"); + + List<String> commands = new ArrayList<>(); + if (configCommand instanceof List) { + commands.addAll((List) configCommand); + } else { + commands.add(String.valueOf(configCommand)); + } + + boolean ignoreCasing = false; + if (configIgnoreCase != null) { + ignoreCasing = (boolean) task.getConfigValue("ignore-case"); + } + String message = e.getMessage(); + if (message.length() >= 1) { + message = message.substring(1); + } + + for (String command : commands) { + if (ignoreCasing && command.equalsIgnoreCase(message)) { + taskProgress.setCompleted(true); + } else if (!ignoreCasing && command.equals(message)) { + taskProgress.setCompleted(true); + } + } + } + } + } + } +} diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/DealDamageTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/DealDamageTaskType.java index 277f1fff..b0c1f48b 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/DealDamageTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/DealDamageTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -16,6 +17,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDamageByEntityEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class DealDamageTaskType extends TaskType { @@ -29,6 +31,14 @@ public final class DealDamageTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } @@ -71,6 +81,7 @@ public final class DealDamageTaskType extends TaskType { taskProgress.setProgress(progressDamage + damage); if (((double) taskProgress.getProgress()) >= (double) damageNeeded) { + taskProgress.setProgress(damageNeeded); taskProgress.setCompleted(true); } } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/DistancefromTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/DistancefromTaskType.java index bc181249..e40df767 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/DistancefromTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/DistancefromTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -9,6 +10,7 @@ import com.leonardobishop.quests.quests.Quest; import com.leonardobishop.quests.quests.Task; import com.leonardobishop.quests.quests.tasktypes.ConfigValue; import com.leonardobishop.quests.quests.tasktypes.TaskType; +import com.leonardobishop.quests.quests.tasktypes.TaskUtils; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; @@ -18,6 +20,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerMoveEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class DistancefromTaskType extends TaskType { @@ -34,10 +37,39 @@ public final class DistancefromTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".x", config.get("x"), problems, "x", super.getType())) + TaskUtils.configValidateInt(root + ".x", config.get("x"), problems, false, false, "x"); + if (TaskUtils.configValidateExists(root + ".y", config.get("y"), problems, "y", super.getType())) + TaskUtils.configValidateInt(root + ".y", config.get("y"), problems, false, false, "y"); + if (TaskUtils.configValidateExists(root + ".z", config.get("z"), problems, "z", super.getType())) + TaskUtils.configValidateInt(root + ".z", config.get("z"), problems, false, false, "z"); + if (TaskUtils.configValidateExists(root + ".distance", config.get("distance"), problems, "distance", super.getType())) + TaskUtils.configValidateInt(root + ".distance", config.get("distance"), problems, false, true, "distance"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } +// private HashMap<String, HashMap<String, Integer>> distanceSquaredCache = new HashMap<>(); +// +// @Override +// public void onReady() { +// distanceSquaredCache.clear(); +// for (Quest quest : super.getRegisteredQuests()) { +// HashMap<String, Integer> squaredDistances = new HashMap<>(); +// for (Task task : quest.getTasksOfType(super.getType())) { +// int distance = (int) task.getConfigValue("distance"); +// squaredDistances.put(task.getId(), distance); +// } +// distanceSquaredCache.put(quest.getId(), squaredDistances); +// } +// } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onMove(PlayerMoveEvent event) { if (event.getFrom().getBlockX() == event.getTo().getBlockX() && event.getFrom().getBlockZ() == event.getTo().getBlockZ()) { @@ -65,14 +97,15 @@ public final class DistancefromTaskType extends TaskType { int z = (int) task.getConfigValue("z"); String worldString = (String) task.getConfigValue("world"); int distance = (int) task.getConfigValue("distance"); + int distanceSquared = distance * distance; World world = Bukkit.getWorld(worldString); if (world == null) { - return; + continue; } Location location = new Location(world, x, y, z); - if (player.getWorld().equals(world) && player.getLocation().distance(location) > distance) { + if (player.getWorld().equals(world) && player.getLocation().distanceSquared(location) > distanceSquared) { taskProgress.setCompleted(true); } } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/EnchantingTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/EnchantingTaskType.java index aee02dc4..768c597e 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/EnchantingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/EnchantingTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -16,6 +17,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.enchantment.EnchantItemEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class EnchantingTaskType extends TaskType { @@ -29,6 +31,14 @@ public final class EnchantingTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/ExpEarnTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/ExpEarnTaskType.java index b1731dd7..b5a70b1a 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/ExpEarnTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/ExpEarnTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -15,6 +16,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerExpChangeEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class ExpEarnTaskType extends TaskType { @@ -26,7 +28,15 @@ public final class ExpEarnTaskType extends TaskType { this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of exp that needs to be earned.")); this.creatorConfigValues.add(new ConfigValue("worlds", false, "Permitted worlds the player must be in.")); } - + + @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/FishingTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/FishingTaskType.java index 5e57a0c1..340eebc0 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/FishingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/FishingTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -16,6 +17,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerFishEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class FishingTaskType extends TaskType { @@ -29,6 +31,14 @@ public final class FishingTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/InventoryTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/InventoryTaskType.java index 74caace5..93a4763f 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/InventoryTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/InventoryTaskType.java @@ -1,6 +1,7 @@ package com.leonardobishop.quests.quests.tasktypes.types; import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -13,16 +14,16 @@ import com.leonardobishop.quests.quests.tasktypes.TaskType; import com.leonardobishop.quests.quests.tasktypes.TaskUtils; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryDragEvent; -import org.bukkit.event.inventory.InventoryInteractEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.player.PlayerPickupItemEvent; import org.bukkit.inventory.ItemStack; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class InventoryTaskType extends TaskType { @@ -33,6 +34,7 @@ public final class InventoryTaskType extends TaskType { super("inventory", "LMBishop", "Obtain a set of items."); this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of item to retrieve.")); this.creatorConfigValues.add(new ConfigValue("item", true, "Name or ID of item.")); + this.creatorConfigValues.add(new ConfigValue("data", false, "Data of item.")); this.creatorConfigValues.add(new ConfigValue("remove-items-when-complete", false, "Take the items away from the player on completion (true/false, " + "default = false).")); this.creatorConfigValues.add(new ConfigValue("update-progress", false, "Update the displayed progress (if this causes lag then disable it).")); @@ -40,6 +42,43 @@ public final class InventoryTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".item", config.get("item"), problems, "item", super.getType())) { + Object configBlock = config.get("item"); + if (configBlock instanceof ConfigurationSection) { + ConfigurationSection section = (ConfigurationSection) configBlock; + String itemloc = "item"; + if (!section.contains("item")) { + itemloc = "type"; + } + if (!section.contains(itemloc)) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.WARNING, + QuestsConfigLoader.ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(""), root + ".item.type")); + } else { + String type = String.valueOf(section.get(itemloc)); + if (!Quests.get().getItemGetter().isValidMaterial(type)) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.WARNING, + QuestsConfigLoader.ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(type), root + ".item." + itemloc)); + } + } + } else { + if (Material.getMaterial(String.valueOf(configBlock)) == null) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.WARNING, + QuestsConfigLoader.ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(String.valueOf(configBlock)), root + ".item.item")); + } + } + } + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + TaskUtils.configValidateInt(root + ".data", config.get("data"), problems, true, false, "data"); + TaskUtils.configValidateBoolean(root + ".remove-items-when-complete", config.get("remove-items-when-complete"), problems, true, "remove-items-when-complete", super.getType()); + TaskUtils.configValidateBoolean(root + ".update-progress", config.get("update-progress"), problems, true, "update-progress", super.getType()); + return problems; + } + + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } @@ -50,13 +89,17 @@ public final class InventoryTaskType extends TaskType { Bukkit.getScheduler().runTaskLater(Quests.get(), () -> this.checkInventory(event.getPlayer()), 1L); } - @EventHandler(priority = EventPriority.MONITOR/*, ignoreCancelled = true*/) - public void onInventoryClick(InventoryClickEvent event) { - Bukkit.getScheduler().runTaskLater(Quests.get(), () -> checkInventory((Player) event.getWhoClicked()), 1L); //Still some work to do as it doesn't really work + @EventHandler(priority = EventPriority.MONITOR) + public void onInventoryClick(InventoryCloseEvent event) { + Bukkit.getScheduler().runTaskLater(Quests.get(), () -> checkInventory((Player) event.getPlayer()), 1L); //Still some work to do as it doesn't really work } @SuppressWarnings("deprecation") private void checkInventory(Player player) { + if (player == null || !player.isOnline()) { + return; + } + QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(player.getUniqueId(), true); if (qPlayer == null) { return; @@ -83,21 +126,28 @@ public final class InventoryTaskType extends TaskType { Object configData = task.getConfigValue("data"); Object remove = task.getConfigValue("remove-items-when-complete"); - material = Material.getMaterial(String.valueOf(configBlock)); - - - if (material == null) { - continue; - } ItemStack is; - if (configData != null) { - is = new ItemStack(material, 1, ((Integer) configData).shortValue()); + if (configBlock instanceof ConfigurationSection) { + is = Quests.get().getItemStack("", (org.bukkit.configuration.ConfigurationSection) configBlock); } else { - is = new ItemStack(material, 1); + material = Material.getMaterial(String.valueOf(configBlock)); + + if (material == null) { + continue; + } + if (configData != null) { + is = new ItemStack(material, 1, ((Integer) configData).shortValue()); + } else { + is = new ItemStack(material, 1); + } } - if (task.getConfigValue("update-progress") != null && (Boolean) task.getConfigValue("update-progress")) { - taskProgress.setProgress(getAmount(player, is, amount)); + if (task.getConfigValue("update-progress") != null + && (Boolean) task.getConfigValue("update-progress")) { + int inInv = getAmount(player, is, amount); + if (taskProgress.getProgress() != null && (int) taskProgress.getProgress() != inInv) { + taskProgress.setProgress(inInv); + } } if (player.getInventory().containsAtLeast(is, amount)) { diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/IridiumSkyblockValueType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/IridiumSkyblockValueType.java deleted file mode 100644 index 028ae2c1..00000000 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/IridiumSkyblockValueType.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.leonardobishop.quests.quests.tasktypes.types; - -import com.iridium.iridiumskyblock.Island; -import com.iridium.iridiumskyblock.User; -import com.leonardobishop.quests.Quests; -import com.leonardobishop.quests.api.QuestsAPI; -import com.leonardobishop.quests.player.QPlayer; -import com.leonardobishop.quests.player.questprogressfile.QuestProgress; -import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; -import com.leonardobishop.quests.player.questprogressfile.TaskProgress; -import com.leonardobishop.quests.quests.Quest; -import com.leonardobishop.quests.quests.Task; -import com.leonardobishop.quests.quests.tasktypes.ConfigValue; -import com.leonardobishop.quests.quests.tasktypes.TaskType; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.scheduler.BukkitTask; - -import java.util.ArrayList; -import java.util.List; - -public final class IridiumSkyblockValueType extends TaskType { - - private List<ConfigValue> creatorConfigValues = new ArrayList<>(); - private BukkitTask poll; - - public IridiumSkyblockValueType() { - super("iridiumskyblock_value", "LMBishop", "Reach a certain island value for Iridium Skyblock."); - this.creatorConfigValues.add(new ConfigValue("value", true, "Minimum island value needed.")); - } - - @Override - public void onReady() { - this.poll = new BukkitRunnable() { - @Override - public void run() { - for (Player player : Bukkit.getOnlinePlayers()) { - Island island = null; - if ((island = User.getUser(player).getIsland()) == null) { - return; - } - - QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(player.getUniqueId(), true); - if (qPlayer == null) { - return; - } - - QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); - - for (Quest quest : IridiumSkyblockValueType.super.getRegisteredQuests()) { - if (questProgressFile.hasStartedQuest(quest)) { - QuestProgress questProgress = questProgressFile.getQuestProgress(quest); - - for (Task task : quest.getTasksOfType(IridiumSkyblockValueType.super.getType())) { - TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); - - if (taskProgress.isCompleted() - || (taskProgress.getProgress() != null && (int) taskProgress.getProgress() == island.getValue())) { - continue; - } - - int islandValueNeeded = (int) task.getConfigValue("value"); - - taskProgress.setProgress(island.getValue()); - - if (((int) taskProgress.getProgress()) >= islandValueNeeded) { - taskProgress.setCompleted(true); - } - } - } - } - } - } - }.runTaskTimer(Quests.get(), 50L, 50L); - } - - @Override - public void onDisable() { - if (this.poll != null) { - this.poll.cancel(); - } - } - - @Override - public List<ConfigValue> getCreatorConfigValues() { - return creatorConfigValues; - } - -} diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MilkingTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MilkingTaskType.java index 6d81ba4c..e1edbaa3 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MilkingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MilkingTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -18,6 +19,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerInteractEntityEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class MilkingTaskType extends TaskType { @@ -31,6 +33,14 @@ public final class MilkingTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MiningCertainTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MiningCertainTaskType.java index 9e28035b..3772b401 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MiningCertainTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MiningCertainTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -10,7 +11,6 @@ import com.leonardobishop.quests.quests.Task; import com.leonardobishop.quests.quests.tasktypes.ConfigValue; import com.leonardobishop.quests.quests.tasktypes.TaskType; import com.leonardobishop.quests.quests.tasktypes.TaskUtils; -import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.event.EventHandler; @@ -19,6 +19,7 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class MiningCertainTaskType extends TaskType { @@ -28,8 +29,8 @@ public final class MiningCertainTaskType extends TaskType { public MiningCertainTaskType() { super("blockbreakcertain", "LMBishop", "Break a set amount of a specific block."); this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of blocks to be broken.")); - this.creatorConfigValues.add(new ConfigValue("block", false, "Name or ID of block.")); // Can use name:datacode - this.creatorConfigValues.add(new ConfigValue("blocks", false, "List of blocks (alias for block for config readability).")); + this.creatorConfigValues.add(new ConfigValue("block", true, "Name or ID of block.", "block")); // Can use name:datacode + this.creatorConfigValues.add(new ConfigValue("blocks", true, "List of blocks (alias for block for config readability).", "block")); this.creatorConfigValues.add(new ConfigValue("data", false, "Data code for block.")); // only used if no datacode provided in block or blocks this.creatorConfigValues.add(new ConfigValue("reverse-if-placed", false, "Will reverse progression if block of same type is placed.")); this.creatorConfigValues.add(new ConfigValue("use-similar-blocks", false, "(Deprecated) If true, this will ignore orientation of doors, logs etc.")); @@ -37,6 +38,43 @@ public final class MiningCertainTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + if (config.get("block") == null && config.get("blocks") == null) { + TaskUtils.configValidateExists(root + ".block", config.get("block"), problems, "block", super.getType()); + } else { + Object configBlock; + String source; + if (config.containsKey("block")) { + source = "block"; + } else { + source = "blocks"; + } + configBlock = config.get(source); + List<String> checkBlocks = new ArrayList<>(); + if (configBlock instanceof List) { + checkBlocks.addAll((List) configBlock); + } else { + checkBlocks.add(String.valueOf(configBlock)); + } + + for (String materialName : checkBlocks) { + String[] split = materialName.split(":"); + if (Material.getMaterial(String.valueOf(split[0])) == null) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.WARNING, + QuestsConfigLoader.ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(materialName), root + "." + source)); + } + } + } + TaskUtils.configValidateBoolean(root + ".reverse-if-broken", config.get("reverse-if-broken"), problems, true,"reverse-if-broken"); + TaskUtils.configValidateBoolean(root + ".use-similar-blocks", config.get("use-similar-blocks"), problems, true,"use-similar-blocks"); + TaskUtils.configValidateInt(root + ".data", config.get("data"), problems, true,true, "data"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } @@ -125,8 +163,9 @@ public final class MiningCertainTaskType extends TaskType { short blockData = block.getData(); - if (blockType.equals(material)) { - return configData == null || ((int) blockData) == comparableData; + if (blockType == material) { + if (((split.length == 1 && configData == null) || ((int) blockData) == comparableData)) + return true; } } return false; diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MiningTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MiningTaskType.java index 60712235..462fcdf9 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MiningTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MiningTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -15,6 +16,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockBreakEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class MiningTaskType extends TaskType { @@ -31,6 +33,14 @@ public final class MiningTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MobkillingCertainTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MobkillingCertainTaskType.java index 61a0a557..b703f216 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MobkillingCertainTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MobkillingCertainTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -19,6 +20,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDeathEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class MobkillingCertainTaskType extends TaskType { @@ -33,6 +35,23 @@ public final class MobkillingCertainTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".mob", config.get("mob"), problems, "mob", super.getType())) { + try { + EntityType.valueOf(String.valueOf(config.get("mob"))); + } catch (IllegalArgumentException ex) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.WARNING, + QuestsConfigLoader.ConfigProblemDescriptions.UNKNOWN_ENTITY_TYPE.getDescription(String.valueOf(config.get("mob"))), root + ".mob")); + } + } + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } @@ -79,7 +98,7 @@ public final class MobkillingCertainTaskType extends TaskType { if (configName != null) { configName = ChatColor.translateAlternateColorCodes('&', configName); if (mob.getCustomName() == null || !mob.getCustomName().equals(configName)) { - return; + continue; } } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MobkillingTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MobkillingTaskType.java index 6bcd835e..918306b3 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MobkillingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MobkillingTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -19,6 +20,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDeathEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class MobkillingTaskType extends TaskType { @@ -32,6 +34,15 @@ public final class MobkillingTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + TaskUtils.configValidateBoolean(root + ".hostile", config.get("hostile"), problems, true, "hostile"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PlaceholderAPIEvaluateTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PlaceholderAPIEvaluateTaskType.java deleted file mode 100644 index 7e4af335..00000000 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PlaceholderAPIEvaluateTaskType.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.leonardobishop.quests.quests.tasktypes.types; - -import com.leonardobishop.quests.Quests; -import com.leonardobishop.quests.api.QuestsAPI; -import com.leonardobishop.quests.player.QPlayer; -import com.leonardobishop.quests.player.questprogressfile.QuestProgress; -import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; -import com.leonardobishop.quests.player.questprogressfile.TaskProgress; -import com.leonardobishop.quests.quests.Quest; -import com.leonardobishop.quests.quests.Task; -import com.leonardobishop.quests.quests.tasktypes.ConfigValue; -import com.leonardobishop.quests.quests.tasktypes.TaskType; -import com.leonardobishop.quests.quests.tasktypes.TaskUtils; -import me.clip.placeholderapi.PlaceholderAPI; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.scheduler.BukkitTask; - -import java.util.ArrayList; -import java.util.List; - -public final class PlaceholderAPIEvaluateTaskType extends TaskType { - - private BukkitTask poll; - private List<ConfigValue> creatorConfigValues = new ArrayList<>(); - - public PlaceholderAPIEvaluateTaskType() { - super("placeholderapi_evaluate", "LMBishop", "Evaluate the result of a placeholder"); - this.creatorConfigValues.add(new ConfigValue("placeholder", true, "The placeholder string (including %%).")); - this.creatorConfigValues.add(new ConfigValue("evaluates", true, "What it should evaluate to be marked as complete.")); - } - - @Override - public void onReady() { - this.poll = new BukkitRunnable() { - @Override - public void run() { - for (Player player : Bukkit.getOnlinePlayers()) { - QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(player.getUniqueId(), true); - QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); - for (Quest quest : PlaceholderAPIEvaluateTaskType.super.getRegisteredQuests()) { - if (questProgressFile.hasStartedQuest(quest)) { - QuestProgress questProgress = questProgressFile.getQuestProgress(quest); - for (Task task : quest.getTasksOfType(PlaceholderAPIEvaluateTaskType.super.getType())) { - if (!TaskUtils.validateWorld(player, task)) continue; - TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); - if (taskProgress.isCompleted()) { - continue; - } - String placeholder = (String) task.getConfigValue("placeholder"); - String evaluates = (String) task.getConfigValue("evaluates"); - if (placeholder != null) { - if (PlaceholderAPI.setPlaceholders(player, placeholder).equals(evaluates)) { - taskProgress.setCompleted(true); - } - } - } - } - } - } - } - }.runTaskTimer(Quests.get(), 30L, 30L); - } - - @Override - public void onDisable() { - if (this.poll != null) { - this.poll.cancel(); - } - } - - @Override - public List<ConfigValue> getCreatorConfigValues() { - return creatorConfigValues; - } -} diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PlayerkillingTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PlayerkillingTaskType.java index f2ef4981..1b7d8bd2 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PlayerkillingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PlayerkillingTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -17,6 +18,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDeathEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class PlayerkillingTaskType extends TaskType { @@ -25,8 +27,15 @@ public final class PlayerkillingTaskType extends TaskType { public PlayerkillingTaskType() { super("playerkilling", "LMBishop", "Kill a set amount of players."); - this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of mobs to be killed.")); - this.creatorConfigValues.add(new ConfigValue("hostile", false, "Only allow hostile or non-hostile mobs (unspecified = any type allowed).")); + this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of players to be killed.")); + } + + @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; } @Override diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PlaytimeTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PlaytimeTaskType.java index f3940d07..159c1010 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PlaytimeTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PlaytimeTaskType.java @@ -1,6 +1,7 @@ package com.leonardobishop.quests.quests.tasktypes.types; import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -17,6 +18,7 @@ import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitTask; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class PlaytimeTaskType extends TaskType { @@ -30,45 +32,56 @@ public final class PlaytimeTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".minutes", config.get("minutes"), problems, "minutes", super.getType())) + TaskUtils.configValidateInt(root + ".minutes", config.get("minutes"), problems, false, true, "minutes"); + return problems; + } + + + @Override public void onReady() { - this.poll = new BukkitRunnable() { - @Override - public void run() { - for (Player player : Bukkit.getOnlinePlayers()) { - QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(player.getUniqueId(), true); - QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); - for (Quest quest : PlaytimeTaskType.super.getRegisteredQuests()) { - if (questProgressFile.hasStartedQuest(quest)) { - QuestProgress questProgress = questProgressFile.getQuestProgress(quest); - for (Task task : quest.getTasksOfType(PlaytimeTaskType.super.getType())) { - if (!TaskUtils.validateWorld(player, task)) continue; + if (this.poll == null) { + this.poll = new BukkitRunnable() { + @Override + public void run() { + for (Player player : Bukkit.getOnlinePlayers()) { + QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(player.getUniqueId(), true); + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + for (Quest quest : PlaytimeTaskType.super.getRegisteredQuests()) { + if (questProgressFile.hasStartedQuest(quest)) { + QuestProgress questProgress = questProgressFile.getQuestProgress(quest); + for (Task task : quest.getTasksOfType(PlaytimeTaskType.super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; - TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); - if (taskProgress.isCompleted()) { - continue; - } - int minutes = (int) task.getConfigValue("minutes"); - if (taskProgress.getProgress() == null) { - taskProgress.setProgress(1); - } else { - taskProgress.setProgress((int) taskProgress.getProgress() + 1); - } - if (((int) taskProgress.getProgress()) >= minutes) { - taskProgress.setCompleted(true); + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + if (taskProgress.isCompleted()) { + continue; + } + int minutes = (int) task.getConfigValue("minutes"); + if (taskProgress.getProgress() == null) { + taskProgress.setProgress(1); + } else { + taskProgress.setProgress((int) taskProgress.getProgress() + 1); + } + if (((int) taskProgress.getProgress()) >= minutes) { + taskProgress.setCompleted(true); + } } } } } } - } - }.runTaskTimer(Quests.get(), 1200L, 1200L); + }.runTaskTimer(Quests.get(), 1200L, 1200L); + } } @Override public void onDisable() { - if (this.poll != null) { - this.poll.cancel(); - } +// if (this.poll != null) { +// this.poll.cancel(); +// } } @Override diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PositionTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PositionTaskType.java index 2f5d7336..03af06ff 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PositionTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/PositionTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -19,6 +20,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerMoveEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class PositionTaskType extends TaskType { @@ -35,6 +37,20 @@ public final class PositionTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".world", config.get("world"), problems, "world", super.getType()); + if (TaskUtils.configValidateExists(root + ".x", config.get("x"), problems, "x", super.getType())) + TaskUtils.configValidateInt(root + ".x", config.get("x"), problems, false, false, "x"); + if (TaskUtils.configValidateExists(root + ".y", config.get("y"), problems, "y", super.getType())) + TaskUtils.configValidateInt(root + ".y", config.get("y"), problems, false, false, "y"); + if (TaskUtils.configValidateExists(root + ".z", config.get("z"), problems, "z", super.getType())) + TaskUtils.configValidateInt(root + ".z", config.get("z"), problems, false, false, "z"); + TaskUtils.configValidateInt(root + ".distance-padding", config.get("distance-padding"), problems, true, true, "distance-padding"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } @@ -69,15 +85,16 @@ public final class PositionTaskType extends TaskType { if (task.getConfigValue("distance-padding") != null) { padding = (int) task.getConfigValue("distance-padding"); } + int paddingSquared = padding * padding; World world = Bukkit.getWorld(worldString); if (world == null) { - return; + continue; } Location location = new Location(world, x, y, z); if (player.getWorld().equals(world) && player.getLocation().getBlockX() == location.getBlockX() && player.getLocation().getBlockY() == location.getBlockY() && player.getLocation().getBlockZ() == location.getBlockZ()) { taskProgress.setCompleted(true); - } else if (player.getWorld().equals(world) && player.getLocation().distance(location) < padding) { + } else if (padding != 0 && player.getWorld().equals(world) && player.getLocation().distanceSquared(location) < paddingSquared) { taskProgress.setCompleted(true); } } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/ShearingTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/ShearingTaskType.java index 9c78bb2a..2d739214 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/ShearingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/ShearingTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -17,6 +18,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerShearEntityEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class ShearingTaskType extends TaskType { @@ -29,6 +31,15 @@ public final class ShearingTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/TamingTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/TamingTaskType.java index 53428c8f..e5888a49 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/TamingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/TamingTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -16,6 +17,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityTameEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class TamingTaskType extends TaskType { @@ -28,6 +30,15 @@ public final class TamingTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/WalkingTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/WalkingTaskType.java index 62ced7d9..5eb37a6c 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/WalkingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/WalkingTaskType.java @@ -1,5 +1,6 @@ package com.leonardobishop.quests.quests.tasktypes.types; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -16,6 +17,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerMoveEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class WalkingTaskType extends TaskType { @@ -28,6 +30,15 @@ public final class WalkingTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".distance", config.get("distance"), problems, "distance", super.getType())) + TaskUtils.configValidateInt(root + ".distance", config.get("distance"), problems, false, true, "distance"); + return problems; + } + + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/ASkyBlockLevelType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/ASkyBlockLevelType.java index 0e4f3229..cc2089a0 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/ASkyBlockLevelType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/ASkyBlockLevelType.java @@ -1,5 +1,6 @@ -package com.leonardobishop.quests.quests.tasktypes.types; +package com.leonardobishop.quests.quests.tasktypes.types.dependent; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -9,11 +10,13 @@ import com.leonardobishop.quests.quests.Quest; import com.leonardobishop.quests.quests.Task; import com.leonardobishop.quests.quests.tasktypes.ConfigValue; import com.leonardobishop.quests.quests.tasktypes.TaskType; +import com.leonardobishop.quests.quests.tasktypes.TaskUtils; import com.wasteofplastic.askyblock.events.IslandPostLevelEvent; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class ASkyBlockLevelType extends TaskType { @@ -26,6 +29,14 @@ public final class ASkyBlockLevelType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".level", config.get("level"), problems, "level", super.getType())) + TaskUtils.configValidateInt(root + ".level", config.get("level"), problems, false, false, "level"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BentoBoxLevelTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/BentoBoxLevelTaskType.java index 289b2655..2281aecb 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/BentoBoxLevelTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/BentoBoxLevelTaskType.java @@ -1,5 +1,6 @@ -package com.leonardobishop.quests.quests.tasktypes.types; +package com.leonardobishop.quests.quests.tasktypes.types.dependent; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -10,16 +11,14 @@ import com.leonardobishop.quests.quests.Task; import com.leonardobishop.quests.quests.tasktypes.ConfigValue; import com.leonardobishop.quests.quests.tasktypes.TaskType; import com.leonardobishop.quests.quests.tasktypes.TaskTypeManager; +import com.leonardobishop.quests.quests.tasktypes.TaskUtils; import org.bukkit.event.EventHandler; import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.events.BentoBoxEvent; import world.bentobox.bentobox.database.objects.Island; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.concurrent.atomic.AtomicLong; public final class BentoBoxLevelTaskType extends TaskType { @@ -33,6 +32,14 @@ public final class BentoBoxLevelTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".level", config.get("level"), problems, "level", super.getType())) + TaskUtils.configValidateInt(root + ".level", config.get("level"), problems, false, false, "level"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/CitizensDeliverTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/CitizensDeliverTaskType.java index 8a64d0ac..2d70a8cd 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/CitizensDeliverTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/CitizensDeliverTaskType.java @@ -1,6 +1,7 @@ -package com.leonardobishop.quests.quests.tasktypes.types; +package com.leonardobishop.quests.quests.tasktypes.types.dependent; import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; @@ -21,6 +22,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.inventory.ItemStack; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class CitizensDeliverTaskType extends TaskType { @@ -38,6 +40,41 @@ public final class CitizensDeliverTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".item", config.get("item"), problems, "item", super.getType())) { + Object configBlock = config.get("item"); + if (configBlock instanceof ConfigurationSection) { + ConfigurationSection section = (ConfigurationSection) configBlock; + String itemloc = "item"; + if (!section.contains("item")) { + itemloc = "type"; + } + if (!section.contains(itemloc)) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.WARNING, + QuestsConfigLoader.ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(""), root + ".item.type")); + } else { + String type = String.valueOf(section.get(itemloc)); + if (!Quests.get().getItemGetter().isValidMaterial(type)) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.WARNING, + QuestsConfigLoader.ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(type), root + ".item." + itemloc)); + } + } + } else { + if (Material.getMaterial(String.valueOf(configBlock)) == null) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.WARNING, + QuestsConfigLoader.ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(String.valueOf(configBlock)), root + ".item.item")); + } + } + } + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + TaskUtils.configValidateExists(root + ".npc-name", config.get("npc-name"), problems, "npc-name", super.getType()); + TaskUtils.configValidateBoolean(root + ".remove-items-when-complete", config.get("remove-items-when-complete"), problems, true, "remove-items-when-complete", super.getType()); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } @@ -49,6 +86,9 @@ public final class CitizensDeliverTaskType extends TaskType { @SuppressWarnings("deprecation") private void checkInventory(Player player, String citizenName) { + if (player == null || !player.isOnline()) { + return; + } QPlayer qPlayer = Quests.get().getPlayerManager().getPlayer(player.getUniqueId(), true); if (qPlayer == null) { return; diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/CitizensInteractTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/CitizensInteractTaskType.java index ed277996..a5e53ea0 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/CitizensInteractTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/CitizensInteractTaskType.java @@ -1,5 +1,6 @@ -package com.leonardobishop.quests.quests.tasktypes.types; +package com.leonardobishop.quests.quests.tasktypes.types.dependent; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -16,6 +17,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class CitizensInteractTaskType extends TaskType { @@ -29,6 +31,15 @@ public final class CitizensInteractTaskType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".npc-name", config.get("npc-name"), problems, "npc-name", super.getType()); + TaskUtils.configValidateBoolean(root + ".remove-items-when-complete", config.get("remove-items-when-complete"), problems, true, "remove-items-when-complete", super.getType()); + return problems; + } + + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/EssentialsBalanceTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/EssentialsBalanceTaskType.java new file mode 100644 index 00000000..54f972ad --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/EssentialsBalanceTaskType.java @@ -0,0 +1,100 @@ +package com.leonardobishop.quests.quests.tasktypes.types.dependent; + +import com.earth2me.essentials.Essentials; +import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.api.QuestsAPI; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.quests.Quest; +import com.leonardobishop.quests.quests.Task; +import com.leonardobishop.quests.quests.tasktypes.ConfigValue; +import com.leonardobishop.quests.quests.tasktypes.TaskType; +import com.leonardobishop.quests.quests.tasktypes.TaskUtils; +import net.ess3.api.events.UserBalanceUpdateEvent; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +public class EssentialsBalanceTaskType extends TaskType { + + private List<ConfigValue> creatorConfigValues = new ArrayList<>(); + + public EssentialsBalanceTaskType() { + super("essentials_balance", "LMBishop", "Reach a set amount of money."); + this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of money to reach.")); + } + + @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, false, "amount"); + return problems; + } + + @Override + public void onStart(Quest quest, Task task, UUID playerUUID) { + Player player = Bukkit.getPlayer(playerUUID); + Essentials ess = (Essentials) Bukkit.getPluginManager().getPlugin("Essentials"); + if (player != null && player.isOnline() && ess != null) { + QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(playerUUID); + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + QuestProgress questProgress = questProgressFile.getQuestProgress(quest); + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + int earningsNeeded = (int) task.getConfigValue("amount"); + BigDecimal money = ess.getUser(player).getMoney(); + taskProgress.setProgress(money); + if (money.compareTo(BigDecimal.valueOf(earningsNeeded)) > 0) { + taskProgress.setCompleted(true); + } + } + } + + @Override + public List<ConfigValue> getCreatorConfigValues() { + return creatorConfigValues; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMoneyEarn(UserBalanceUpdateEvent event) { + QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(event.getPlayer().getUniqueId(), true); + if (qPlayer == null) { + return; + } + + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + + for (Quest quest : super.getRegisteredQuests()) { + if (questProgressFile.hasStartedQuest(quest)) { + QuestProgress questProgress = questProgressFile.getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int earningsNeeded = (int) task.getConfigValue("amount"); + + taskProgress.setProgress(event.getNewBalance()); + + if (event.getNewBalance().compareTo(BigDecimal.valueOf(earningsNeeded)) > 0) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/EssentialsMoneyEarnTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/EssentialsMoneyEarnTaskType.java new file mode 100644 index 00000000..3d054a86 --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/EssentialsMoneyEarnTaskType.java @@ -0,0 +1,83 @@ +package com.leonardobishop.quests.quests.tasktypes.types.dependent; + +import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.api.QuestsAPI; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.quests.Quest; +import com.leonardobishop.quests.quests.Task; +import com.leonardobishop.quests.quests.tasktypes.ConfigValue; +import com.leonardobishop.quests.quests.tasktypes.TaskType; +import com.leonardobishop.quests.quests.tasktypes.TaskUtils; +import net.ess3.api.events.UserBalanceUpdateEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class EssentialsMoneyEarnTaskType extends TaskType { + + private List<ConfigValue> creatorConfigValues = new ArrayList<>(); + + public EssentialsMoneyEarnTaskType() { + super("essentials_moneyearn", "LMBishop", "Earn a set amount of money."); + this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of money to earn.")); + } + + @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, false, "amount"); + return problems; + } + + + @Override + public List<ConfigValue> getCreatorConfigValues() { + return creatorConfigValues; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMoneyEarn(UserBalanceUpdateEvent event) { + QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(event.getPlayer().getUniqueId(), true); + if (qPlayer == null) { + return; + } + + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + + for (Quest quest : super.getRegisteredQuests()) { + if (questProgressFile.hasStartedQuest(quest)) { + QuestProgress questProgress = questProgressFile.getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int earningsNeeded = (int) task.getConfigValue("amount"); + + BigDecimal current = (BigDecimal) taskProgress.getProgress(); + if (current == null) { + current = new BigDecimal(0); + } + BigDecimal newProgress = current.add(event.getNewBalance().subtract(event.getOldBalance())); + taskProgress.setProgress(newProgress); + + if (newProgress.compareTo(BigDecimal.valueOf(earningsNeeded)) > 0) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/IridiumSkyblockValueType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/IridiumSkyblockValueType.java new file mode 100644 index 00000000..79bb9492 --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/IridiumSkyblockValueType.java @@ -0,0 +1,91 @@ +package com.leonardobishop.quests.quests.tasktypes.types.dependent; + +import com.iridium.iridiumskyblock.Island; +import com.iridium.iridiumskyblock.api.IslandWorthCalculatedEvent; +import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.api.QuestsAPI; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.quests.Quest; +import com.leonardobishop.quests.quests.Task; +import com.leonardobishop.quests.quests.tasktypes.ConfigValue; +import com.leonardobishop.quests.quests.tasktypes.TaskType; +import com.leonardobishop.quests.quests.tasktypes.TaskUtils; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.scheduler.BukkitTask; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +public final class IridiumSkyblockValueType extends TaskType { + + private List<ConfigValue> creatorConfigValues = new ArrayList<>(); + + public IridiumSkyblockValueType() { + super("iridiumskyblock_value", "LMBishop", "Reach a certain island value for Iridium Skyblock."); + this.creatorConfigValues.add(new ConfigValue("value", true, "Minimum island value needed.")); + } + + @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".value", config.get("value"), problems, "value", super.getType())) + TaskUtils.configValidateInt(root + ".value", config.get("value"), problems, false, false, "value"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onIslandLevel(IslandWorthCalculatedEvent event) { + Island island = event.getIsland(); + for (String player : island.members) { + UUID uuid; + try { + uuid = UUID.fromString(player); + } catch (Exception e) { + Quests.get().getQuestsLogger().debug("Cannot convert from String to UUID for IridiumSkyblock"); + continue; + } + QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(uuid, true); + if (qPlayer == null) { + continue; + } + + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + + for (Quest quest : IridiumSkyblockValueType.super.getRegisteredQuests()) { + if (questProgressFile.hasStartedQuest(quest)) { + QuestProgress questProgress = questProgressFile.getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(IridiumSkyblockValueType.super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int islandValueNeeded = (int) task.getConfigValue("value"); + + taskProgress.setProgress(event.getIslandWorth()); + + if (((double) taskProgress.getProgress()) >= islandValueNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + + } + + @Override + public List<ConfigValue> getCreatorConfigValues() { + return creatorConfigValues; + } + +} diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MythicMobsKillingType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/MythicMobsKillingType.java index 75570108..b86fe62d 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/MythicMobsKillingType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/MythicMobsKillingType.java @@ -1,5 +1,6 @@ -package com.leonardobishop.quests.quests.tasktypes.types; +package com.leonardobishop.quests.quests.tasktypes.types.dependent; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -17,6 +18,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class MythicMobsKillingType extends TaskType { @@ -30,6 +32,15 @@ public final class MythicMobsKillingType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".name", config.get("name"), problems, "name", super.getType()); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/PlaceholderAPIEvaluateTaskType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/PlaceholderAPIEvaluateTaskType.java new file mode 100644 index 00000000..639acbd5 --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/PlaceholderAPIEvaluateTaskType.java @@ -0,0 +1,159 @@ +package com.leonardobishop.quests.quests.tasktypes.types.dependent; + +import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.api.QuestsAPI; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.quests.Quest; +import com.leonardobishop.quests.quests.Task; +import com.leonardobishop.quests.quests.tasktypes.ConfigValue; +import com.leonardobishop.quests.quests.tasktypes.TaskType; +import com.leonardobishop.quests.quests.tasktypes.TaskUtils; +import me.clip.placeholderapi.PlaceholderAPI; +import net.objecthunter.exp4j.operator.Operator; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class PlaceholderAPIEvaluateTaskType extends TaskType { + + private BukkitTask poll; + private List<ConfigValue> creatorConfigValues = new ArrayList<>(); + + public PlaceholderAPIEvaluateTaskType() { + super("placeholderapi_evaluate", "LMBishop", "Evaluate the result of a placeholder"); + this.creatorConfigValues.add(new ConfigValue("placeholder", true, "The placeholder string (including %%).")); + this.creatorConfigValues.add(new ConfigValue("evaluates", true, "What it should evaluate to be marked as complete.")); + this.creatorConfigValues.add(new ConfigValue("operator", false, "Comparison method.")); + } + + @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".placeholder", config.get("placeholder"), problems, "placeholder", super.getType()); + boolean evalExists = TaskUtils.configValidateExists(root + ".evaluates", config.get("evaluates"), problems, "evaluates", super.getType()); + + if (config.containsKey("operator")) { + String operatorStr = (String) config.get("operator"); + Operator operator = null; + try { + operator = Operator.valueOf(operatorStr); + } catch (IllegalArgumentException ex) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.WARNING, + "Operator '" + operatorStr + "' does not exist.", root + ".operator")); + } + if (operator != null && evalExists) { + String evalStr = String.valueOf(config.get("evaluates")); + try { + Double.parseDouble(evalStr); + } catch (IllegalArgumentException ex) { + problems.add(new QuestsConfigLoader.ConfigProblem(QuestsConfigLoader.ConfigProblemType.WARNING, + "Numeric operator specified, but placeholder evaluation '" + evalStr + "' is not numeric.", root + ".evaluates")); + } + } + } + return problems; + } + + @Override + public void onReady() { + this.poll = new BukkitRunnable() { + @Override + public void run() { + for (Player player : Bukkit.getOnlinePlayers()) { + QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(player.getUniqueId(), true); + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + for (Quest quest : PlaceholderAPIEvaluateTaskType.super.getRegisteredQuests()) { + if (questProgressFile.hasStartedQuest(quest)) { + QuestProgress questProgress = questProgressFile.getQuestProgress(quest); + for (Task task : quest.getTasksOfType(PlaceholderAPIEvaluateTaskType.super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + if (taskProgress.isCompleted()) { + continue; + } + String placeholder = (String) task.getConfigValue("placeholder"); + String evaluates = String.valueOf(task.getConfigValue("evaluates")); + String configOperator = (String) task.getConfigValue("operator"); + Operator operator = null; + if (configOperator != null) { + try { + operator = Operator.valueOf(configOperator); + } catch (IllegalArgumentException ignored) { } + } + if (placeholder != null && evaluates != null) { + double numericEvaluates = 0; + if (operator != null) { + try { + numericEvaluates = Double.parseDouble(evaluates); + } catch (NumberFormatException ex) { + continue; + } + } + + String evaluated = PlaceholderAPI.setPlaceholders(player, placeholder); + if (operator == null && evaluated.equals(evaluates)) { + taskProgress.setCompleted(true); + } else if (operator != null) { + double numericEvaluated; + try { + numericEvaluated = Double.parseDouble(evaluated); + } catch (NumberFormatException ex) { + continue; + } + switch (operator) { + case GREATER_THAN: + if (numericEvaluated > numericEvaluates) + taskProgress.setCompleted(true); + continue; + case LESS_THAN: + if (numericEvaluated < numericEvaluates) + taskProgress.setCompleted(true); + continue; + case GREATER_THAN_OR_EQUAL_TO: + if (numericEvaluated >= numericEvaluates) + taskProgress.setCompleted(true); + continue; + case LESS_THAN_OR_EQUAL_TO: + if (numericEvaluated <= numericEvaluates) + taskProgress.setCompleted(true); + continue; + } + } + } + + } + } + } + } + } + }.runTaskTimer(Quests.get(), 30L, 30L); + } + + @Override + public void onDisable() { + if (this.poll != null) { + this.poll.cancel(); + } + } + + @Override + public List<ConfigValue> getCreatorConfigValues() { + return creatorConfigValues; + } + + enum Operator { + GREATER_THAN, + LESS_THAN, + GREATER_THAN_OR_EQUAL_TO, + LESS_THAN_OR_EQUAL_TO; + } +} diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/uSkyBlockLevelType.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/uSkyBlockLevelType.java index 2956bf32..81f9138a 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/uSkyBlockLevelType.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/types/dependent/uSkyBlockLevelType.java @@ -1,5 +1,6 @@ -package com.leonardobishop.quests.quests.tasktypes.types; +package com.leonardobishop.quests.quests.tasktypes.types.dependent; +import com.leonardobishop.quests.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -9,11 +10,13 @@ import com.leonardobishop.quests.quests.Quest; import com.leonardobishop.quests.quests.Task; import com.leonardobishop.quests.quests.tasktypes.ConfigValue; import com.leonardobishop.quests.quests.tasktypes.TaskType; +import com.leonardobishop.quests.quests.tasktypes.TaskUtils; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import us.talabrek.ultimateskyblock.api.event.uSkyBlockScoreChangedEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public final class uSkyBlockLevelType extends TaskType { @@ -26,6 +29,15 @@ public final class uSkyBlockLevelType extends TaskType { } @Override + public List<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { + ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".level", config.get("level"), problems, "level", super.getType())) + TaskUtils.configValidateInt(root + ".level", config.get("level"), problems, false, false, "level"); + return problems; + } + + + @Override public List<ConfigValue> getCreatorConfigValues() { return creatorConfigValues; } diff --git a/src/main/java/com/leonardobishop/quests/updater/Updater.java b/src/main/java/com/leonardobishop/quests/updater/Updater.java index f0705d1e..6c197b88 100644 --- a/src/main/java/com/leonardobishop/quests/updater/Updater.java +++ b/src/main/java/com/leonardobishop/quests/updater/Updater.java @@ -14,10 +14,12 @@ import java.util.concurrent.TimeUnit; public class Updater { private static final int PROJECT_ID = 23696; - private String installedVersion; + + private final String installedVersion; + private final Quests plugin; + private String returnedVersion; private URL api; - private Quests plugin; private boolean updateReady; private long lastCheck; |
