From 29d72e31e7e672ad67f4bf15902534020bf857d8 Mon Sep 17 00:00:00 2001 From: LMBishop <13875753+LMBishop@users.noreply.github.com> Date: Mon, 14 Jun 2021 13:14:01 +0100 Subject: Add quest controllers --- .../com/leonardobishop/quests/QuestCompleter.java | 98 ----- .../java/com/leonardobishop/quests/Quests.java | 27 ++ .../quests/QuestsAutosaveRunnable.java | 44 -- .../leonardobishop/quests/QuestsConfigLoader.java | 440 -------------------- .../com/leonardobishop/quests/QuestsLogger.java | 83 ---- .../quests/command/QuestsCommand.java | 12 +- .../com/leonardobishop/quests/menu/DailyQMenu.java | 204 +++++---- .../quests/menu/element/QuestMenuElement.java | 8 +- .../com/leonardobishop/quests/player/QPlayer.java | 274 +++---------- .../quests/player/QPlayerManager.java | 29 +- .../quest/controller/DailyQuestController.java | 186 +++++++++ .../quest/controller/NormalQuestController.java | 239 +++++++++++ .../quests/quest/controller/QuestController.java | 15 + .../quests/quest/tasktype/TaskType.java | 2 +- .../quests/quest/tasktype/TaskUtils.java | 2 +- .../quest/tasktype/type/BreedingTaskType.java | 2 +- .../quest/tasktype/type/BrewingTaskType.java | 2 +- .../tasktype/type/BuildingCertainTaskType.java | 2 +- .../quest/tasktype/type/BuildingTaskType.java | 2 +- .../quest/tasktype/type/CommandTaskType.java | 2 +- .../quest/tasktype/type/DealDamageTaskType.java | 2 +- .../quest/tasktype/type/DistancefromTaskType.java | 2 +- .../quest/tasktype/type/EnchantingTaskType.java | 2 +- .../quest/tasktype/type/ExpEarnTaskType.java | 2 +- .../quest/tasktype/type/FishingTaskType.java | 2 +- .../quest/tasktype/type/InventoryTaskType.java | 2 +- .../quest/tasktype/type/MilkingTaskType.java | 2 +- .../quest/tasktype/type/MiningCertainTaskType.java | 2 +- .../quests/quest/tasktype/type/MiningTaskType.java | 2 +- .../tasktype/type/MobkillingCertainTaskType.java | 4 +- .../quest/tasktype/type/MobkillingTaskType.java | 2 +- .../quest/tasktype/type/PlayerkillingTaskType.java | 2 +- .../quest/tasktype/type/PlaytimeTaskType.java | 2 +- .../quest/tasktype/type/PositionTaskType.java | 2 +- .../quest/tasktype/type/ShearingTaskType.java | 2 +- .../quests/quest/tasktype/type/TamingTaskType.java | 2 +- .../quest/tasktype/type/WalkingTaskType.java | 2 +- .../type/dependent/ASkyBlockLevelType.java | 2 +- .../type/dependent/BentoBoxLevelTaskType.java | 2 +- .../type/dependent/CitizensDeliverTaskType.java | 2 +- .../type/dependent/CitizensInteractTaskType.java | 2 +- .../type/dependent/EssentialsBalanceTaskType.java | 2 +- .../dependent/EssentialsMoneyEarnTaskType.java | 2 +- .../type/dependent/IridiumSkyblockValueType.java | 2 +- .../type/dependent/MythicMobsKillingType.java | 2 +- .../dependent/PlaceholderAPIEvaluateTaskType.java | 2 +- .../dependent/ShopGUIPlusBuyCertainTaskType.java | 2 +- .../dependent/ShopGUIPlusSellCertainTaskType.java | 2 +- .../type/dependent/uSkyBlockLevelType.java | 2 +- .../leonardobishop/quests/util/QuestCompleter.java | 99 +++++ .../com/leonardobishop/quests/util/QuestMode.java | 8 + .../quests/util/QuestsAutosaveRunnable.java | 45 ++ .../quests/util/QuestsConfigLoader.java | 454 +++++++++++++++++++++ .../leonardobishop/quests/util/QuestsLogger.java | 85 ++++ src/main/resources/config.yml | 14 +- 55 files changed, 1371 insertions(+), 1067 deletions(-) delete mode 100644 src/main/java/com/leonardobishop/quests/QuestCompleter.java delete mode 100644 src/main/java/com/leonardobishop/quests/QuestsAutosaveRunnable.java delete mode 100644 src/main/java/com/leonardobishop/quests/QuestsConfigLoader.java delete mode 100644 src/main/java/com/leonardobishop/quests/QuestsLogger.java create mode 100644 src/main/java/com/leonardobishop/quests/quest/controller/DailyQuestController.java create mode 100644 src/main/java/com/leonardobishop/quests/quest/controller/NormalQuestController.java create mode 100644 src/main/java/com/leonardobishop/quests/quest/controller/QuestController.java create mode 100644 src/main/java/com/leonardobishop/quests/util/QuestCompleter.java create mode 100644 src/main/java/com/leonardobishop/quests/util/QuestMode.java create mode 100644 src/main/java/com/leonardobishop/quests/util/QuestsAutosaveRunnable.java create mode 100644 src/main/java/com/leonardobishop/quests/util/QuestsConfigLoader.java create mode 100644 src/main/java/com/leonardobishop/quests/util/QuestsLogger.java (limited to 'src') diff --git a/src/main/java/com/leonardobishop/quests/QuestCompleter.java b/src/main/java/com/leonardobishop/quests/QuestCompleter.java deleted file mode 100644 index d3ff8cf1..00000000 --- a/src/main/java/com/leonardobishop/quests/QuestCompleter.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.leonardobishop.quests; - -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.quest.Quest; -import com.leonardobishop.quests.quest.Task; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -import java.util.LinkedList; -import java.util.Queue; - -public class QuestCompleter implements Runnable { - - private final Queue completionQueue = new LinkedList<>(); - private final Queue fullCheckQueue = new LinkedList<>(); - private final Quests plugin; - - public QuestCompleter(Quests plugin) { - this.plugin = plugin; - } - - @Override - public void run() { - 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()); - if (qPlayer == null) return; - - Quest quest = plugin.getQuestManager().getQuestById(questProgress.getQuestId()); - - if (!qPlayer.hasStartedQuest(quest)) return; - - if (checkComplete(quest, questProgress)) { - qPlayer.completeQuest(quest); - } - } - } - - private void processFullCheckQueue() { - QuestProgressFile questProgressFile = fullCheckQueue.poll(); - if (questProgressFile == null) return; - - Player player = Bukkit.getPlayer(questProgressFile.getPlayerUUID()); - if (player != null && player.isOnline()) { - QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); - if (qPlayer == null) return; - for (QuestProgress questProgress : questProgressFile.getAllQuestProgress()) { - Quest quest = plugin.getQuestManager().getQuestById(questProgress.getQuestId()); - if (quest == null) continue; - if (!qPlayer.hasStartedQuest(quest)) continue; - - boolean complete = true; - for (Task task : quest.getTasks()) { - TaskProgress taskProgress; - if ((taskProgress = questProgress.getTaskProgress(task.getId())) == null || !taskProgress.isCompleted()) { - complete = false; - break; - } - } - if (complete) { - qPlayer.completeQuest(quest); - } - } - } - } - - 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 6308f9de..074e6e9b 100644 --- a/src/main/java/com/leonardobishop/quests/Quests.java +++ b/src/main/java/com/leonardobishop/quests/Quests.java @@ -20,6 +20,7 @@ import com.leonardobishop.quests.hook.title.Title_Other; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.QPlayerManager; import com.leonardobishop.quests.quest.QuestManager; +import com.leonardobishop.quests.quest.controller.NormalQuestController; import com.leonardobishop.quests.quest.tasktype.TaskType; import com.leonardobishop.quests.quest.tasktype.TaskTypeManager; import com.leonardobishop.quests.quest.tasktype.type.BreedingTaskType; @@ -59,6 +60,11 @@ import com.leonardobishop.quests.quest.tasktype.type.dependent.ShopGUIPlusSellCe import com.leonardobishop.quests.quest.tasktype.type.dependent.uSkyBlockLevelType; import com.leonardobishop.quests.updater.Updater; import com.leonardobishop.quests.util.Messages; +import com.leonardobishop.quests.util.QuestCompleter; +import com.leonardobishop.quests.util.QuestMode; +import com.leonardobishop.quests.util.QuestsAutosaveRunnable; +import com.leonardobishop.quests.util.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsLogger; import org.bstats.bukkit.MetricsLite; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; @@ -107,6 +113,7 @@ public class Quests extends JavaPlugin { private boolean brokenConfig = false; private BukkitTask questAutosaveTask; private BukkitTask questQueuePollTask; + private QuestMode questMode; public static Quests get() { return instance; @@ -148,6 +155,14 @@ public class Quests extends JavaPlugin { return menuController; } + public QuestMode getQuestMode() { + return questMode; + } + + protected void setQuestMode(QuestMode questMode) { + this.questMode = questMode; + } + public String convertToFormat(long m) { //seconds please long hours = m / 3600; long minutes = (m % 3600) / 60; @@ -162,6 +177,7 @@ public class Quests extends JavaPlugin { @Override public void onEnable() { instance = this; + questMode = QuestMode.NORMAL; questsLogger = new QuestsLogger(this, QuestsLogger.LoggingLevel.INFO); questCompleter = new QuestCompleter(this); @@ -312,6 +328,17 @@ public class Quests extends JavaPlugin { questsConfigLoader.loadConfig(); + switch (this.questMode) { +// TODO +// case DAILY: +// qPlayerManager.setActiveQuestController(new DailyQuestController(this)); +// break; + default: + case NORMAL: + qPlayerManager.setActiveQuestController(new NormalQuestController(this)); + break; + } + long autosaveInterval = 12000; if (!isBrokenConfig()) { autosaveInterval = this.getConfig().getLong("options.performance-tweaking.quest-autosave-interval", 12000); diff --git a/src/main/java/com/leonardobishop/quests/QuestsAutosaveRunnable.java b/src/main/java/com/leonardobishop/quests/QuestsAutosaveRunnable.java deleted file mode 100644 index eaa37d87..00000000 --- a/src/main/java/com/leonardobishop/quests/QuestsAutosaveRunnable.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.leonardobishop.quests; - -import com.leonardobishop.quests.player.QPlayer; -import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; -import com.leonardobishop.quests.util.Options; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; - -import java.util.LinkedList; -import java.util.Queue; -import java.util.UUID; - -public class QuestsAutosaveRunnable extends BukkitRunnable { - - private final Queue queue = new LinkedList<>(); - private final Quests plugin; - - public QuestsAutosaveRunnable(Quests plugin) { - for (Player player : Bukkit.getOnlinePlayers()) { - queue.add(player.getUniqueId()); - } - - this.plugin = plugin; - - this.runTaskTimer(plugin, 2L, 2L); - } - - @Override - public void run() { - UUID player = queue.poll(); - if (player == null) { - try { - super.cancel(); - } catch (Exception ignored) {} - return; - } - - if (Bukkit.getPlayer(player) != null) { - plugin.getPlayerManager().savePlayer(player); - } - } - -} diff --git a/src/main/java/com/leonardobishop/quests/QuestsConfigLoader.java b/src/main/java/com/leonardobishop/quests/QuestsConfigLoader.java deleted file mode 100644 index 8a5e10d8..00000000 --- a/src/main/java/com/leonardobishop/quests/QuestsConfigLoader.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.leonardobishop.quests; - -import com.leonardobishop.quests.hook.itemgetter.ItemGetter; -import com.leonardobishop.quests.menu.QItemStack; -import com.leonardobishop.quests.quest.Category; -import com.leonardobishop.quests.quest.Quest; -import com.leonardobishop.quests.quest.Task; -import com.leonardobishop.quests.quest.tasktype.TaskType; -import com.leonardobishop.quests.util.Options; -import org.apache.commons.lang.StringUtils; -import org.bukkit.ChatColor; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.inventory.ItemStack; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class QuestsConfigLoader { - - private final Map> filesWithProblems = new HashMap<>(); - private final Quests plugin; - private int problemsCount; - - public QuestsConfigLoader(Quests plugin) { - this.plugin = plugin; - } - - /** - * Loads and parses config into memory including the quests folder. - */ - public void loadConfig() { - plugin.reloadConfig(); - Options.invalidateCaches(); - filesWithProblems.clear(); - plugin.setBrokenConfig(false); - - // test CONFIG file integrity - try { - YamlConfiguration config = new YamlConfiguration(); - config.load(new File(plugin.getDataFolder() + File.separator + "config.yml")); - } catch (Exception ex) { - filesWithProblems.put("
config.yml", Collections.singletonList(new ConfigProblem(ConfigProblemType.ERROR, ConfigProblemDescriptions.MALFORMED_YAML.getDescription()))); - plugin.setBrokenConfig(true); - } - - - if (!plugin.isBrokenConfig()) { - HashMap> globalTaskConfig = new HashMap<>(); - 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(QuestsLogger.LoggingLevel.fromNumber(plugin.getConfig().getInt("options.verbose-logging-level", 2))); - - HashMap pathToQuest = new HashMap<>(); - - if (plugin.getConfig().isConfigurationSection("global-task-configuration.types")) { - for (String type : plugin.getConfig().getConfigurationSection("global-task-configuration.types").getKeys(false)) { - HashMap configValues = new HashMap<>(); - for (String key : plugin.getConfig().getConfigurationSection("global-task-configuration.types." + type).getKeys(false)) { - configValues.put(key, plugin.getConfig().get("global-task-configuration.types." + type + "." + key)); - } - globalTaskConfig.putIfAbsent(type, configValues); - } - } - - FileVisitor fileVisitor = new SimpleFileVisitor() { - final URI questsRoot = Paths.get(plugin.getDataFolder() + File.separator + "quests").toUri(); - - @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attributes) { - try { - File questFile = new File(path.toUri()); - URI relativeLocation = questsRoot.relativize(path.toUri()); - - if (!questFile.getName().toLowerCase().endsWith(".yml")) return FileVisitResult.CONTINUE; - - 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; - } - - String id = questFile.getName().replace(".yml", ""); - - List 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 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")); - } - } - - boolean error = false; - for (ConfigProblem problem : configProblems) { - if (problem.getType() == ConfigProblemType.ERROR) { - error = true; - break; - } - } - - // END OF THE CHECKING - if (!error && !Options.ERROR_CHECKING_OVERRIDE.getBooleanValue(false)) { - QItemStack displayItem = getQItemStack("display", config); - List rewards = config.getStringList("rewards"); - List requirements = config.getStringList("options.requires"); - List rewardString = config.getStringList("rewardstring"); - List 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"); - Map placeholders = new HashMap<>(); - - if (category == null) category = ""; - - Quest quest; - if (category.equals("")) { - quest = new Quest(id, displayItem, rewards, requirements, repeatable, cooldown, cooldownTime, permissionRequired, rewardString, startString, placeholders, sortOrder); - } else { - quest = new Quest(id, displayItem, rewards, requirements, repeatable, cooldown, cooldownTime, permissionRequired, rewardString, startString, placeholders, 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")); - } - } - - 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 (globalTaskConfig.containsKey(taskType)) { - for (Map.Entry entry : globalTaskConfig.get(taskType).entrySet()) { - if (Options.GLOBAL_TASK_CONFIGURATION_OVERRIDE.getBooleanValue() && task.getConfigValue(entry.getKey()) != null) - continue; - task.addConfigValue(entry.getKey(), entry.getValue()); - } - } - - quest.registerTask(task); - } - - - for (String line : displayItem.getLoreNormal()) { - findInvalidTaskReferences(quest, line, configProblems, "display.lore-normal"); - } - for (String line : displayItem.getLoreStarted()) { - findInvalidTaskReferences(quest, line, configProblems, "display.lore-started"); - } - - if (config.isConfigurationSection("placeholders")) { - for (String p : config.getConfigurationSection("placeholders").getKeys(false)) { - placeholders.put(p, config.getString("placeholders." + p)); - findInvalidTaskReferences(quest, config.getString("placeholders." + p), configProblems, "placeholders." + p); - } - } - 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); - pathToQuest.put(relativeLocation.getPath(), quest); - } - if (!configProblems.isEmpty()) { - filesWithProblems.put(relativeLocation.getPath(), configProblems); - } - } catch (Exception e) { - plugin.getQuestsLogger().severe("An exception occurred when attempting to load quest '" + path + "' (will be ignored)"); - e.printStackTrace(); - } - return FileVisitResult.CONTINUE; - } - }; - - try { - Files.walkFileTree(Paths.get(plugin.getDataFolder() + File.separator + "quests"), fileVisitor); - } catch (IOException e) { - e.printStackTrace(); - } - - // post-load checks - for (Map.Entry loadedQuest : pathToQuest.entrySet()) { - List 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")); - } - } - - if (!configProblems.isEmpty()) { - if (filesWithProblems.containsKey(loadedQuest.getKey())) { - filesWithProblems.get(loadedQuest.getKey()).addAll(configProblems); - } else { - filesWithProblems.put(loadedQuest.getKey(), configProblems); - } - } - } - - for (TaskType taskType : plugin.getTaskTypeManager().getTaskTypes()) { - try { - taskType.onReady(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - problemsCount = 0; - for (List problemList : plugin.getQuestsConfigLoader().getFilesWithProblems().values()) { - problemsCount = problemsCount + problemList.size(); - } - } - - public Map> getFilesWithProblems() { - return filesWithProblems; - } - - public int getProblemsCount() { - return problemsCount; - } - - private void findInvalidTaskReferences(Quest quest, String s, List configProblems, String location) { - Pattern pattern = Pattern.compile("\\{([^}]+)}"); - - Matcher matcher = pattern.matcher(s); - 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]), location)); - } - } - - private QItemStack getQItemStack(String path, FileConfiguration config) { - String cName = config.getString(path + ".name", path + ".name"); - List cLoreNormal = config.getStringList(path + ".lore-normal"); - List cLoreStarted = config.getStringList(path + ".lore-started"); - - List loreNormal = translateColoursInList(cLoreNormal); - List loreStarted = translateColoursInList(cLoreStarted); - - String name; - name = ChatColor.translateAlternateColorCodes('&', cName); - - ItemStack is = plugin.getItemStack(path, config, - ItemGetter.Filter.DISPLAY_NAME, ItemGetter.Filter.LORE, ItemGetter.Filter.ENCHANTMENTS, ItemGetter.Filter.ITEM_FLAGS); - - return new QItemStack(plugin, name, loreNormal, loreStarted, is); - } - - private List translateColoursInList(List list) { - List coloured = new ArrayList<>(); - for (String s : list) { - coloured.add(ChatColor.translateAlternateColorCodes('&', s)); - } - return coloured; - } - - 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 ConfigProblemType { - - ERROR("Error", "E", ChatColor.RED, 1), - WARNING("Warning", "W", ChatColor.YELLOW, 2); - - private final String title; - private final String shortened; - private final ChatColor color; - private final int priority; - - ConfigProblemType(String title, String shortened, ChatColor color, int priority) { - this.title = title; - this.shortened = shortened; - this.color = color; - this.priority = priority; - } - - public String getTitle() { - return title; - } - - public String getShortened() { - return shortened; - } - - public ChatColor getColor() { - return color; - } - - public int getPriority() { - return priority; - } - - } - - 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 ConfigProblem(ConfigProblemType type, String description) { - this.type = type; - this.description = description == null ? "?" : description; - ; - this.location = "?"; - } - - public ConfigProblemType getType() { - return type; - } - - public String getDescription() { - return description; - } - - 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 deleted file mode 100644 index 895b03dd..00000000 --- a/src/main/java/com/leonardobishop/quests/QuestsLogger.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.leonardobishop.quests; - -public class QuestsLogger { - - private final Quests plugin; - private LoggingLevel serverLoggingLevel; - - public QuestsLogger(Quests plugin, LoggingLevel serverLoggingLevel) { - this.plugin = plugin; - this.serverLoggingLevel = serverLoggingLevel; - } - - public LoggingLevel getServerLoggingLevel() { - return serverLoggingLevel; - } - - public void setServerLoggingLevel(LoggingLevel serverLoggingLevel) { - this.serverLoggingLevel = serverLoggingLevel; - } - - public void log(String str, LoggingLevel level) { - if (serverLoggingLevel.getNumericVerbosity() < level.getNumericVerbosity()) { - return; - } - switch (level) { - case DEBUG: - plugin.getLogger().info("Debug: " + str); - break; - case INFO: - plugin.getLogger().info(str); - break; - case ERROR: - plugin.getLogger().severe(str); - break; - case WARNING: - plugin.getLogger().warning(str); - break; - } - } - - public void debug(String str) { - log(str, LoggingLevel.DEBUG); - } - - public void info(String str) { - log(str, LoggingLevel.INFO); - } - - public void warning(String str) { - log(str, LoggingLevel.WARNING); - } - - public void severe(String str) { - log(str, LoggingLevel.ERROR); - } - - public enum LoggingLevel { - ERROR(0), - WARNING(1), - INFO(2), - DEBUG(3); - - private int numericVerbosity; - - LoggingLevel(int number) { - numericVerbosity = number; - } - - public int getNumericVerbosity() { - return numericVerbosity; - } - - static LoggingLevel fromNumber(int number) { - for (LoggingLevel level : LoggingLevel.values()) { - if (level.getNumericVerbosity() == number) { - return level; - } - } - return LoggingLevel.INFO; - } - } - -} diff --git a/src/main/java/com/leonardobishop/quests/command/QuestsCommand.java b/src/main/java/com/leonardobishop/quests/command/QuestsCommand.java index 8113fe05..0906b3c9 100644 --- a/src/main/java/com/leonardobishop/quests/command/QuestsCommand.java +++ b/src/main/java/com/leonardobishop/quests/command/QuestsCommand.java @@ -1,7 +1,7 @@ package com.leonardobishop.quests.command; import com.leonardobishop.quests.Quests; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.enums.QuestStartResult; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; @@ -22,15 +22,6 @@ import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.File; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -126,6 +117,7 @@ public class QuestsCommand implements TabExecutor { sender.sendMessage(ChatColor.DARK_GRAY + "View info using /q a types [type]."); return true; } else if (args[1].equalsIgnoreCase("info")) { + sender.sendMessage(ChatColor.RED + "Quest mode: " + plugin.getQuestMode().toString()); sender.sendMessage(ChatColor.GRAY + "Loaded quests:"); for (Quest quest : plugin.getQuestManager().getQuests().values()) { sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + quest.getId() + ChatColor.GRAY + " [" + quest.getTasks().size() + " tasks]"); diff --git a/src/main/java/com/leonardobishop/quests/menu/DailyQMenu.java b/src/main/java/com/leonardobishop/quests/menu/DailyQMenu.java index a89765e4..0d6080cd 100644 --- a/src/main/java/com/leonardobishop/quests/menu/DailyQMenu.java +++ b/src/main/java/com/leonardobishop/quests/menu/DailyQMenu.java @@ -1,106 +1,98 @@ -//package com.leonardobishop.quests.menu; -// -//import com.leonardobishop.quests.util.Options; -//import com.leonardobishop.quests.player.QPlayer; -//import com.leonardobishop.quests.quests.Quest; -//import org.bukkit.Bukkit; -//import org.bukkit.inventory.Inventory; -// -//import java.util.HashMap; -//import java.util.List; -// -//public class QMenuDaily implements QMenu { -// -// private final HashMap slotsToQuestIds = new HashMap<>(); -// private int backButtonLocation = -1; -// private boolean backButtonEnabled = true; -// private final QMenuCategory superMenu; -// private String categoryName; -// private final int pageSize = 45; -// private final QPlayer owner; -// -// public QMenuDaily(QPlayer owner, QMenuCategory superMenu) { -// this.owner = owner; -// this.superMenu = superMenu; -// } -// -// public void populate(List quests) { -// int slot = 11; -// for (Quest quest : quests) { -// slotsToQuestIds.put(slot, quest.getId()); -// slot++; -// if (slot == 16) { -// break; -// } -// } -// } -// -// @Override -// public HashMap getSlotsToMenu() { -// return slotsToQuestIds; -// } -// -// @Override -// public QPlayer getOwner() { -// return owner; -// } -// -// public String getCategoryName() { -// return categoryName; -// } -// -// public Inventory toInventory(int page) { -// int pageMin = pageSize * (page - 1); -// int pageMax = pageSize * page; -// String title = Options.GUITITLE_DAILY_QUESTS.toString(); -// -// // Inventory inventory = Bukkit.createInventory(null, 27, title); -// -// //TODO daily quests -// -//// int invSlot = 11; -//// for (int pointer = pageMin; pointer < pageMax; pointer++) { -//// if (slotsToQuestIds.containsKey(pointer)) { -//// Quest quest = Quests.getQuestManager().getQuestById(slotsToQuestIds.get(pointer)); -//// QuestProgress questProgress = owner.getQuestProgressFile().getQuestProgress(quest); -//// long cooldown = owner.getQuestProgressFile().getCooldownFor(quest); -//// if (!owner.getQuestProgressFile().hasMetRequirements(quest)) { -//// List quests = new ArrayList<>(); -//// for (String requirement : quest.getRequirements()) { -//// quests.add(Quests.getQuestManager().getQuestById(requirement).getDisplayNameStripped()); -//// } -//// Map placeholders = new HashMap<>(); -//// placeholders.put("{quest}", quest.getDisplayNameStripped()); -//// placeholders.put("{requirements}", String.join(", ", quests)); -//// ItemStack is = replaceItemStack(Items.QUEST_LOCKED.getItem(), placeholders); -//// inventory.setItem(invSlot, is); -//// } else if (!quest.isRepeatable() && questProgress.isCompletedBefore()) { -//// Map placeholders = new HashMap<>(); -//// placeholders.put("{quest}", quest.getDisplayNameStripped()); -//// ItemStack is = replaceItemStack(Items.QUEST_COMPLETED.getItem(), placeholders); -//// inventory.setItem(invSlot, is); -//// } else if (cooldown > 0) { -//// Map placeholders = new HashMap<>(); -//// placeholders.put("{time}", Quests.convertToFormat(TimeUnit.MINUTES.convert(cooldown, TimeUnit.MILLISECONDS))); -//// placeholders.put("{quest}", quest.getDisplayNameStripped()); -//// ItemStack is = replaceItemStack(Items.QUEST_COOLDOWN.getItem(), placeholders); -//// inventory.setItem(invSlot, is); -//// } else { -//// inventory.setItem(invSlot, Quests.getQuestManager().getQuestById(quest.getId()).getDisplayItem().toItemStack(questProgress)); -//// } -//// } -//// invSlot++; -//// } -//// return inventory; -// return Bukkit.createInventory(null, 27, title); -// } -// -// //Implement too -// public QMenuCategory getSuperMenu() { -// return this.superMenu; -// } -// -// public int getPageSize() { -// return this.pageSize; -// } -//} +package com.leonardobishop.quests.menu; + +import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.api.enums.QuestStartResult; +import com.leonardobishop.quests.listener.MenuController; +import com.leonardobishop.quests.menu.element.MenuElement; +import com.leonardobishop.quests.menu.element.QuestMenuElement; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.quest.Quest; +import com.leonardobishop.quests.quest.controller.DailyQuestController; +import com.leonardobishop.quests.quest.controller.QuestController; +import com.leonardobishop.quests.util.Items; +import com.leonardobishop.quests.util.Options; +import org.bukkit.Bukkit; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents a cancellation confirmation menu for a specific quest. + */ +public class DailyQMenu implements QMenu { + + private final Map menuElements = new HashMap<>(); + private final Quests plugin; + private final QPlayer owner; + + public DailyQMenu(Quests plugin, QPlayer owner) { + this.plugin = plugin; + this.owner = owner; + } + + @Override + public QPlayer getOwner() { + return owner; + } + + public void populate() { + if (!(owner.getQuestController() instanceof DailyQuestController)) { + return; + } + DailyQuestController dailyQuestController = (DailyQuestController) owner.getQuestController(); + List quests = dailyQuestController.getQuests(); + for (int i = 0; i < quests.size(); i++) { + menuElements.put(11 + i, new QuestMenuElement(plugin, owner, quests.get(i))); + } + } + + public Inventory toInventory(int page) { + String title = Options.color(Options.GUITITLE_DAILY_QUESTS.getStringValue()); + + ItemStack background = Items.QUEST_CANCEL_BACKGROUND.getItem(); + ItemMeta backgroundMeta = background.getItemMeta(); + backgroundMeta.setDisplayName(" "); + background.setItemMeta(backgroundMeta); + + Inventory inventory = Bukkit.createInventory(null, 27, title); + + for (int i = 0; i < inventory.getSize(); i++) { + inventory.setItem(i, background); + } + + for (int pointer = 0; pointer < 27; pointer++) { + if (menuElements.containsKey(pointer)) { + inventory.setItem(pointer, menuElements.get(pointer).asItemStack()); + } + } + + return inventory; + } + + @Override + public void handleClick(InventoryClickEvent event, MenuController controller) { + if (menuElements.containsKey(event.getSlot())) { + MenuElement menuElement = menuElements.get(event.getSlot()); + if (menuElement instanceof QuestMenuElement) { + QuestMenuElement questMenuElement = (QuestMenuElement) menuElement; + Quest quest = plugin.getQuestManager().getQuestById(questMenuElement.getQuestId()); + if (event.getClick() == ClickType.LEFT) { + if (Options.QUEST_AUTOSTART.getBooleanValue()) return; + if (owner.startQuest(quest) == QuestStartResult.QUEST_SUCCESS) { + event.getWhoClicked().closeInventory(); //TODO Option to keep the menu open + } + } else if (event.getClick() == ClickType.MIDDLE && Options.ALLOW_QUEST_TRACK.getBooleanValue()) { + MenuUtil.handleMiddleClick(this, quest, Bukkit.getPlayer(owner.getPlayerUUID()), controller); + } + } + } + } + + +} diff --git a/src/main/java/com/leonardobishop/quests/menu/element/QuestMenuElement.java b/src/main/java/com/leonardobishop/quests/menu/element/QuestMenuElement.java index 96c358a4..6d13c0c5 100644 --- a/src/main/java/com/leonardobishop/quests/menu/element/QuestMenuElement.java +++ b/src/main/java/com/leonardobishop/quests/menu/element/QuestMenuElement.java @@ -1,6 +1,7 @@ package com.leonardobishop.quests.menu.element; import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.api.enums.QuestStartResult; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; import com.leonardobishop.quests.quest.Quest; @@ -42,8 +43,9 @@ public class QuestMenuElement extends MenuElement { public ItemStack asItemStack() { Quest quest = plugin.getQuestManager().getQuestById(questId); QuestProgress questProgress = owner.getQuestProgressFile().getQuestProgress(quest); + QuestStartResult status = owner.canStartQuest(quest); long cooldown = owner.getQuestProgressFile().getCooldownFor(quest); - if (!owner.getQuestProgressFile().hasMetRequirements(quest)) { + if (status == QuestStartResult.QUEST_LOCKED) { List quests = new ArrayList<>(); for (String requirement : quest.getRequirements()) { Quest requirementQuest = Quests.get().getQuestManager().getQuestById(requirement); @@ -57,12 +59,12 @@ public class QuestMenuElement extends MenuElement { placeholders.put("{requirements}", String.join(", ", quests)); ItemStack is = replaceItemStack(Items.QUEST_LOCKED.getItem(), placeholders); return is; - } else if (!quest.isRepeatable() && questProgress.isCompletedBefore()) { + } else if (status == QuestStartResult.QUEST_ALREADY_COMPLETED) { Map placeholders = new HashMap<>(); placeholders.put("{quest}", quest.getDisplayNameStripped()); ItemStack is = replaceItemStack(Items.QUEST_COMPLETED.getItem(), placeholders); return is; - } else if (quest.isPermissionRequired() && !Bukkit.getPlayer(owner.getPlayerUUID()).hasPermission("quests.quest." + quest.getId())) { + } else if (status == QuestStartResult.QUEST_NO_PERMISSION) { Map placeholders = new HashMap<>(); placeholders.put("{quest}", quest.getDisplayNameStripped()); ItemStack is = replaceItemStack(Items.QUEST_PERMISSION.getItem(), placeholders); diff --git a/src/main/java/com/leonardobishop/quests/player/QPlayer.java b/src/main/java/com/leonardobishop/quests/player/QPlayer.java index 44472217..e8dc3306 100644 --- a/src/main/java/com/leonardobishop/quests/player/QPlayer.java +++ b/src/main/java/com/leonardobishop/quests/player/QPlayer.java @@ -1,52 +1,48 @@ package com.leonardobishop.quests.player; +import com.leonardobishop.quests.util.QuestMode; import com.leonardobishop.quests.Quests; -import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.api.enums.QuestStartResult; -import com.leonardobishop.quests.api.events.PlayerCancelQuestEvent; import com.leonardobishop.quests.api.events.PlayerFinishQuestEvent; -import com.leonardobishop.quests.api.events.PlayerStartQuestEvent; import com.leonardobishop.quests.api.events.PlayerStartTrackQuestEvent; import com.leonardobishop.quests.api.events.PlayerStopTrackQuestEvent; -import com.leonardobishop.quests.api.events.PreStartQuestEvent; import com.leonardobishop.quests.menu.CategoryQMenu; +import com.leonardobishop.quests.menu.DailyQMenu; import com.leonardobishop.quests.menu.QuestQMenu; import com.leonardobishop.quests.menu.QuestSortWrapper; import com.leonardobishop.quests.menu.StartedQMenu; import com.leonardobishop.quests.player.questprogressfile.QPlayerPreferences; -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.quest.Category; import com.leonardobishop.quests.quest.Quest; -import com.leonardobishop.quests.quest.Task; +import com.leonardobishop.quests.quest.controller.QuestController; import com.leonardobishop.quests.util.Messages; import com.leonardobishop.quests.util.Options; import org.bukkit.Bukkit; -import org.bukkit.ChatColor; import org.bukkit.entity.Player; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.concurrent.TimeUnit; /** * Represents a player. */ public class QPlayer { + private final Quests plugin; private final UUID uuid; private final QPlayerPreferences playerPreferences; private final QuestProgressFile questProgressFile; - private final Quests plugin; + private QuestController questController; - public QPlayer(UUID uuid, QuestProgressFile questProgressFile, QPlayerPreferences playerPreferences, Quests plugin) { + public QPlayer(Quests plugin, UUID uuid, QPlayerPreferences playerPreferences, QuestProgressFile questProgressFile, QuestController questController) { + this.plugin = plugin; this.uuid = uuid; this.playerPreferences = playerPreferences; this.questProgressFile = questProgressFile; - this.plugin = plugin; + this.questController = questController; } public UUID getPlayerUUID() { @@ -64,50 +60,7 @@ public class QPlayer { * @return true (always) */ public boolean completeQuest(Quest quest) { - QuestProgress questProgress = questProgressFile.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()); - if (Options.ALLOW_QUEST_TRACK.getBooleanValue() && Options.QUEST_AUTOTRACK.getBooleanValue() && !(quest.isRepeatable() && !quest.isCooldownEnabled())) { - trackQuest(null); - } - Player player = Bukkit.getPlayer(uuid); - if (player != null) { - String questFinishMessage = Messages.QUEST_COMPLETE.getMessage().replace("{quest}", quest.getDisplayNameStripped()); - // PlayerFinishQuestEvent -- start - PlayerFinishQuestEvent questFinishEvent = new PlayerFinishQuestEvent(player, this, questProgress, questFinishMessage); - Bukkit.getPluginManager().callEvent(questFinishEvent); - // PlayerFinishQuestEvent -- end - Bukkit.getServer().getScheduler().runTask(plugin, () -> { - for (String s : quest.getRewards()) { - Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), s.replace("{player}", player.getName())); //TODO PlaceholderAPI support - } - }); - if (questFinishEvent.getQuestFinishMessage() != null) - player.sendMessage(questFinishEvent.getQuestFinishMessage()); - if (Options.TITLES_ENABLED.getBooleanValue()) { - plugin.getTitleHandle().sendTitle(player, Messages.TITLE_QUEST_COMPLETE_TITLE.getMessage().replace("{quest}", quest - .getDisplayNameStripped()), Messages.TITLE_QUEST_COMPLETE_SUBTITLE.getMessage().replace("{quest}", quest - .getDisplayNameStripped())); - } - for (String s : quest.getRewardString()) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', s)); - } - } - if ((Options.ALLOW_QUEST_TRACK.getBooleanValue() && Options.QUEST_AUTOTRACK.getBooleanValue() && !(quest.isRepeatable() && !quest.isCooldownEnabled())) - || (!Options.ALLOW_QUEST_TRACK.getBooleanValue() && Options.QUEST_AUTOTRACK.getBooleanValue())) { - Quest nextQuest; - if (questProgressFile.getStartedQuests().size() > 0) { - nextQuest = questProgressFile.getStartedQuests().get(0); - trackQuest(nextQuest); - } - } - return true; + return questController.completeQuestForPlayer(this, quest); } /** @@ -145,12 +98,7 @@ public class QPlayer { * @return true if the quest is started or quest autostart is enabled and the quest is ready to start, false otherwise */ public boolean hasStartedQuest(Quest quest) { - if (Options.QUEST_AUTOSTART.getBooleanValue()) { - QuestStartResult response = canStartQuest(quest); - return response == QuestStartResult.QUEST_SUCCESS || response == QuestStartResult.QUEST_ALREADY_STARTED; - } else { - return questProgressFile.hasQuestProgress(quest) && questProgressFile.getQuestProgress(quest).isStarted(); - } + return questController.hasPlayerStartedQuest(this, quest); } /** @@ -163,82 +111,7 @@ public class QPlayer { */ // TODO PlaceholderAPI support public QuestStartResult startQuest(Quest quest) { - Player player = Bukkit.getPlayer(uuid); - QuestStartResult code = canStartQuest(quest); - if (player != null) { - String questResultMessage = null; - switch (code) { - case QUEST_SUCCESS: - // This one is hacky - break; - case QUEST_LIMIT_REACHED: - questResultMessage = Messages.QUEST_START_LIMIT.getMessage().replace("{limit}", String.valueOf(Options.QUESTS_START_LIMIT.getIntValue())); - break; - case QUEST_ALREADY_COMPLETED: - questResultMessage = Messages.QUEST_START_DISABLED.getMessage(); - break; - case QUEST_COOLDOWN: - long cooldown = questProgressFile.getCooldownFor(quest); - questResultMessage = Messages.QUEST_START_COOLDOWN.getMessage().replace("{time}", String.valueOf(plugin.convertToFormat(TimeUnit.SECONDS.convert - (cooldown, TimeUnit.MILLISECONDS)))); - break; - case QUEST_LOCKED: - questResultMessage = Messages.QUEST_START_LOCKED.getMessage(); - break; - case QUEST_ALREADY_STARTED: - questResultMessage = Messages.QUEST_START_STARTED.getMessage(); - break; - case QUEST_NO_PERMISSION: - questResultMessage = Messages.QUEST_START_PERMISSION.getMessage(); - break; - case NO_PERMISSION_FOR_CATEGORY: - questResultMessage = Messages.QUEST_CATEGORY_QUEST_PERMISSION.getMessage(); - break; - } - // PreStartQuestEvent -- start - PreStartQuestEvent preStartQuestEvent = new PreStartQuestEvent(player, this, questResultMessage, code); - Bukkit.getPluginManager().callEvent(preStartQuestEvent); - // PreStartQuestEvent -- end - if (preStartQuestEvent.getQuestResultMessage() != null && code != QuestStartResult.QUEST_SUCCESS) - player.sendMessage(preStartQuestEvent.getQuestResultMessage()); - } - if (code == QuestStartResult.QUEST_SUCCESS) { - QuestProgress questProgress = questProgressFile.getQuestProgress(quest); - questProgress.setStarted(true); - for (TaskProgress taskProgress : questProgress.getTaskProgress()) { - taskProgress.setCompleted(false); - taskProgress.setProgress(null); - } - if (Options.ALLOW_QUEST_TRACK.getBooleanValue() && Options.QUEST_AUTOTRACK.getBooleanValue()) { - trackQuest(quest); - } - questProgress.setCompleted(false); - if (player != null) { - String questStartMessage = Messages.QUEST_START.getMessage().replace("{quest}", quest.getDisplayNameStripped()); - // PlayerStartQuestEvent -- start - PlayerStartQuestEvent questStartEvent = new PlayerStartQuestEvent(player, this, questProgress, questStartMessage); - Bukkit.getPluginManager().callEvent(questStartEvent); - // PlayerStartQuestEvent -- end - if (questStartEvent.getQuestStartMessage() != null) - player.sendMessage(questStartEvent.getQuestStartMessage()); //Don't send a message if the event message is null - if (Options.TITLES_ENABLED.getBooleanValue()) { - plugin.getTitleHandle().sendTitle(player, Messages.TITLE_QUEST_START_TITLE.getMessage().replace("{quest}", quest - .getDisplayNameStripped()), Messages.TITLE_QUEST_START_SUBTITLE.getMessage().replace("{quest}", quest - .getDisplayNameStripped())); - } - for (String s : quest.getStartString()) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', s)); - } - } - for (Task task : quest.getTasks()) { - try { - plugin.getTaskTypeManager().getTaskType(task.getType()).onStart(quest, task, uuid); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - return code; + return questController.startQuestForPlayer(this, quest); } /** @@ -248,28 +121,7 @@ public class QPlayer { * @return true if the quest was cancelled, false otherwise */ public boolean cancelQuest(Quest quest) { - QuestProgress questProgress = questProgressFile.getQuestProgress(quest); - Player player = Bukkit.getPlayer(uuid); - if (!questProgress.isStarted()) { - if (player != null) { - player.sendMessage(Messages.QUEST_CANCEL_NOTSTARTED.getMessage()); - } - return false; - } - questProgress.setStarted(false); - for (TaskProgress taskProgress : questProgress.getTaskProgress()) { - taskProgress.setProgress(null); - } - if (player != null) { - String questCancelMessage = Messages.QUEST_CANCEL.getMessage().replace("{quest}", quest.getDisplayNameStripped()); - // PlayerCancelQuestEvent -- start - PlayerCancelQuestEvent questCancelEvent = new PlayerCancelQuestEvent(player, this, questProgress, questCancelMessage); - Bukkit.getPluginManager().callEvent(questCancelEvent); - // PlayerCancelQuestEvent -- end - if (questCancelEvent.getQuestCancelMessage() != null) - player.sendMessage(questCancelEvent.getQuestCancelMessage()); - } - return true; + return questController.cancelQuestForPlayer(this, quest); } /** @@ -281,47 +133,7 @@ public class QPlayer { * @return the quest start result */ public QuestStartResult canStartQuest(Quest quest) { - Player p = Bukkit.getPlayer(uuid); - if (questProgressFile.getStartedQuests().size() >= Options.QUESTS_START_LIMIT.getIntValue() && !Options.QUEST_AUTOSTART.getBooleanValue()) { - return QuestStartResult.QUEST_LIMIT_REACHED; - } - QuestProgress questProgress = questProgressFile.getQuestProgress(quest); - if (!quest.isRepeatable() && questProgress.isCompletedBefore()) { - //if (playerUUID != null) { - // ??? - //} - return QuestStartResult.QUEST_ALREADY_COMPLETED; - } - long cooldown = questProgressFile.getCooldownFor(quest); - if (cooldown > 0) { - return QuestStartResult.QUEST_COOLDOWN; - } - if (!questProgressFile.hasMetRequirements(quest)) { - return QuestStartResult.QUEST_LOCKED; - } - if (questProgress.isStarted()) { - return QuestStartResult.QUEST_ALREADY_STARTED; - } - if (quest.isPermissionRequired()) { - if (p != null) { - if (!p.hasPermission("quests.quest." + quest.getId())) { - return QuestStartResult.QUEST_NO_PERMISSION; - } - } else { - return QuestStartResult.QUEST_NO_PERMISSION; - } - } - if (quest.getCategoryId() != null && plugin.getQuestManager().getCategoryById(quest.getCategoryId()) != null && plugin.getQuestManager() - .getCategoryById(quest.getCategoryId()).isPermissionRequired()) { - if (p != null) { - if (!p.hasPermission("quests.category." + quest.getCategoryId())) { - return QuestStartResult.NO_PERMISSION_FOR_CATEGORY; - } - } else { - return QuestStartResult.NO_PERMISSION_FOR_CATEGORY; - } - } - return QuestStartResult.QUEST_SUCCESS; + return questController.canPlayerStartQuest(this, quest); } /** @@ -381,34 +193,40 @@ public class QPlayer { return; } - if (Options.CATEGORIES_ENABLED.getBooleanValue()) { - CategoryQMenu categoryQMenu = new CategoryQMenu(plugin, this); - List questMenus = new ArrayList<>(); - for (Category category : plugin.getQuestManager().getCategories()) { - QuestQMenu questQMenu = new QuestQMenu(plugin, this, category.getId(), categoryQMenu); - List quests = new ArrayList<>(); - for (String questid : category.getRegisteredQuestIds()) { - Quest quest = plugin.getQuestManager().getQuestById(questid); - if (quest != null) { - quests.add(quest); + if (plugin.getQuestMode() == QuestMode.NORMAL) { + if (Options.CATEGORIES_ENABLED.getBooleanValue()) { + CategoryQMenu categoryQMenu = new CategoryQMenu(plugin, this); + List questMenus = new ArrayList<>(); + for (Category category : plugin.getQuestManager().getCategories()) { + QuestQMenu questQMenu = new QuestQMenu(plugin, this, category.getId(), categoryQMenu); + List quests = new ArrayList<>(); + for (String questid : category.getRegisteredQuestIds()) { + Quest quest = plugin.getQuestManager().getQuestById(questid); + if (quest != null) { + quests.add(quest); + } } + questQMenu.populate(quests); + questMenus.add(questQMenu); + } + categoryQMenu.populate(questMenus); + + plugin.getMenuController().openMenu(player, categoryQMenu, 1); + } else { + QuestQMenu questQMenu = new QuestQMenu(plugin, this, "", null); + List quests = new ArrayList<>(); + for (Map.Entry entry : plugin.getQuestManager().getQuests().entrySet()) { + quests.add(entry.getValue()); } questQMenu.populate(quests); - questMenus.add(questQMenu); - } - categoryQMenu.populate(questMenus); + questQMenu.setBackButtonEnabled(false); - plugin.getMenuController().openMenu(player, categoryQMenu, 1); - } else { - QuestQMenu questQMenu = new QuestQMenu(plugin, this, "", null); - List quests = new ArrayList<>(); - for (Map.Entry entry : plugin.getQuestManager().getQuests().entrySet()) { - quests.add(entry.getValue()); + plugin.getMenuController().openMenu(player, questQMenu, 1); } - questQMenu.populate(quests); - questQMenu.setBackButtonEnabled(false); - - plugin.getMenuController().openMenu(player, questQMenu, 1); + } else { + DailyQMenu dailyQMenu = new DailyQMenu(plugin, this); + dailyQMenu.populate(); + plugin.getMenuController().openMenu(player, dailyQMenu, 1); } } @@ -439,6 +257,14 @@ public class QPlayer { return playerPreferences; } + public QuestController getQuestController() { + return questController; + } + + public void setQuestController(QuestController questController) { + this.questController = questController; + } + @Override //Used by java GC public boolean equals(Object o) { if (!(o instanceof QPlayer)) return false; diff --git a/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java b/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java index 41c704e3..182b5666 100644 --- a/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java +++ b/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java @@ -1,19 +1,16 @@ package com.leonardobishop.quests.player; import com.leonardobishop.quests.Quests; -import com.leonardobishop.quests.QuestsLogger; +import com.leonardobishop.quests.util.QuestsLogger; import com.leonardobishop.quests.player.questprogressfile.QPlayerPreferences; -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.quest.controller.NormalQuestController; +import com.leonardobishop.quests.quest.controller.QuestController; import com.leonardobishop.quests.storage.MySqlStorageProvider; import com.leonardobishop.quests.storage.StorageProvider; import com.leonardobishop.quests.storage.YamlStorageProvider; -import com.leonardobishop.quests.util.Options; import org.bukkit.Bukkit; -import org.bukkit.configuration.file.YamlConfiguration; -import java.io.File; import java.util.Collection; import java.util.Map; import java.util.UUID; @@ -21,8 +18,11 @@ import java.util.concurrent.ConcurrentHashMap; public class QPlayerManager { + private final Map qPlayers = new ConcurrentHashMap<>(); private final Quests plugin; private StorageProvider storageProvider; + private QuestController activeQuestController; + public QPlayerManager(Quests plugin) { this.plugin = plugin; @@ -41,9 +41,9 @@ public class QPlayerManager { } catch (Exception ignored) { plugin.getQuestsLogger().severe("An error occurred initialising the storage provider."); } - } - private final Map qPlayers = new ConcurrentHashMap<>(); + this.activeQuestController = new NormalQuestController(plugin); + } /** * Gets the QPlayer from a given UUID. @@ -153,7 +153,7 @@ public class QPlayerManager { qPlayers.computeIfAbsent(uuid, s -> { QuestProgressFile questProgressFile = storageProvider.loadProgressFile(uuid); if (questProgressFile == null) return null; - return new QPlayer(uuid, questProgressFile, new QPlayerPreferences(null), plugin); + return new QPlayer(plugin, uuid, new QPlayerPreferences(null), questProgressFile, activeQuestController); }); } @@ -165,4 +165,15 @@ public class QPlayerManager { public StorageProvider getStorageProvider() { return storageProvider; } + + public QuestController getActiveQuestController() { + return activeQuestController; + } + + public void setActiveQuestController(QuestController activeQuestController) { + this.activeQuestController = activeQuestController; + for (QPlayer qPlayer : qPlayers.values()) { + qPlayer.setQuestController(activeQuestController); + } + } } diff --git a/src/main/java/com/leonardobishop/quests/quest/controller/DailyQuestController.java b/src/main/java/com/leonardobishop/quests/quest/controller/DailyQuestController.java new file mode 100644 index 00000000..d2ffd192 --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/quest/controller/DailyQuestController.java @@ -0,0 +1,186 @@ +package com.leonardobishop.quests.quest.controller; + +import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.api.enums.QuestStartResult; +import com.leonardobishop.quests.api.events.PlayerFinishQuestEvent; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.quest.Quest; +import com.leonardobishop.quests.util.Messages; +import com.leonardobishop.quests.util.Options; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +//TODO finish this +public class DailyQuestController implements QuestController { + + private int refreshTaskId = -1; + private long refreshTime; + private long startTime; + private Quests plugin; + private Random random; + private List quests; + + public DailyQuestController(Quests plugin) { + this.plugin = plugin; + refreshDailyQuests(); + scheduleNewTask(); + } + + public void cancel() { + Bukkit.getScheduler().cancelTask(refreshTaskId); + } + + public List getQuests() { + return quests; + } + + private void scheduleNewTask() { + long diff = refreshTime - System.currentTimeMillis(); + BukkitTask refreshTask; + if (diff <= 10000) { //10 sec + refreshTask = new DailyQuestRefreshTask(true).runTaskTimer(plugin, 1L, 1L); + plugin.getQuestsLogger().debug("DailyQuestRefreshTask set repeating (diff=" + diff + ")"); + } else { + long sleepTime = diff >> 6; + plugin.getQuestsLogger().debug("DailyQuestRefreshTask slept for " + sleepTime + " ticks (diff=" + diff + ")"); + refreshTask = new DailyQuestRefreshTask(false).runTaskLater(plugin, sleepTime); + } + refreshTaskId = refreshTask.getTaskId(); + } + + private void refreshDailyQuests() { +// refreshTime = ((System.currentTimeMillis() / (86400000)) + 1) * 86400000; + refreshTime = ((System.currentTimeMillis() / (300000)) + 1) * 300000; + startTime = (System.currentTimeMillis() / (300000)) * 300000; + random = new Random(refreshTime); + quests = new ArrayList<>(); + + List questIds = new ArrayList<>(plugin.getQuestManager().getQuests().keySet()); + for (int i = 0; i < 5; i++) { + int randInt = random.nextInt(questIds.size()); + quests.add(questIds.get(randInt)); + questIds = questIds.stream().filter(s -> !quests.contains(s)).collect(Collectors.toList()); + } + } + + @Override + public QuestStartResult startQuestForPlayer(QPlayer qPlayer, Quest quest) { + if (quests.contains(quest.getId())) { + return QuestStartResult.QUEST_ALREADY_STARTED; + } else { + return QuestStartResult.QUEST_LIMIT_REACHED; + } + } + + @Override + public QuestStartResult canPlayerStartQuest(QPlayer qPlayer, Quest quest) { + if (!quests.contains(quest.getId())) return QuestStartResult.OTHER; + long completionDate = qPlayer.getQuestProgressFile().getQuestProgress(quest).getCompletionDate(); + if (Options.QUEST_AUTOSTART.getBooleanValue()) { + if (completionDate > startTime && completionDate <= refreshTime) { + return QuestStartResult.QUEST_ALREADY_COMPLETED; + } + } else { + if (qPlayer.getQuestProgressFile().hasQuestProgress(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + if (questProgress.isStarted() && completionDate > startTime && completionDate <= refreshTime) { + return QuestStartResult.QUEST_ALREADY_STARTED; + } + } + } + return QuestStartResult.QUEST_SUCCESS; + } + + @Override + public boolean completeQuestForPlayer(QPlayer qPlayer, Quest quest) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().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()); + + boolean trackedReset = quest.getId().equals(qPlayer.getPlayerPreferences().getTrackedQuestId()); + if (trackedReset) { + qPlayer.trackQuest(null); + } + + Player player = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + if (player != null) { + String questFinishMessage = Messages.QUEST_COMPLETE.getMessage().replace("{quest}", quest.getDisplayNameStripped()); + // PlayerFinishQuestEvent -- start + PlayerFinishQuestEvent questFinishEvent = new PlayerFinishQuestEvent(player, qPlayer, questProgress, questFinishMessage); + Bukkit.getPluginManager().callEvent(questFinishEvent); + // PlayerFinishQuestEvent -- end + Bukkit.getServer().getScheduler().runTask(plugin, () -> { + for (String s : quest.getRewards()) { + Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), s.replace("{player}", player.getName())); //TODO PlaceholderAPI support + } + }); + if (questFinishEvent.getQuestFinishMessage() != null) + player.sendMessage(questFinishEvent.getQuestFinishMessage()); + if (Options.TITLES_ENABLED.getBooleanValue()) { + plugin.getTitleHandle().sendTitle(player, Messages.TITLE_QUEST_COMPLETE_TITLE.getMessage().replace("{quest}", quest + .getDisplayNameStripped()), Messages.TITLE_QUEST_COMPLETE_SUBTITLE.getMessage().replace("{quest}", quest + .getDisplayNameStripped())); + } + for (String s : quest.getRewardString()) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', s)); + } + } + if (Options.QUEST_AUTOTRACK.getBooleanValue() && trackedReset) { + for (String s : quests) { + Quest nextQuest = plugin.getQuestManager().getQuestById(s); + if (nextQuest != null && canPlayerStartQuest(qPlayer, nextQuest) == QuestStartResult.QUEST_SUCCESS) { + qPlayer.trackQuest(nextQuest); + break; + } + } + } + return true; + } + + @Override + public boolean hasPlayerStartedQuest(QPlayer qPlayer, Quest quest) { + return canPlayerStartQuest(qPlayer, quest) == QuestStartResult.QUEST_SUCCESS; + } + + @Override + public boolean cancelQuestForPlayer(QPlayer qPlayer, Quest quest) { + return false; + } + + public class DailyQuestRefreshTask extends BukkitRunnable { + + private final boolean repeating; + + public DailyQuestRefreshTask(boolean repeating) { + this.repeating = repeating; + } + + @Override + public void run() { + if (System.currentTimeMillis() >= refreshTime) { + this.cancel(); + refreshDailyQuests(); + } else { + if (repeating) return; + this.cancel(); + } + scheduleNewTask(); + } + } +} diff --git a/src/main/java/com/leonardobishop/quests/quest/controller/NormalQuestController.java b/src/main/java/com/leonardobishop/quests/quest/controller/NormalQuestController.java new file mode 100644 index 00000000..055bbf97 --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/quest/controller/NormalQuestController.java @@ -0,0 +1,239 @@ +package com.leonardobishop.quests.quest.controller; + +import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.api.enums.QuestStartResult; +import com.leonardobishop.quests.api.events.PlayerCancelQuestEvent; +import com.leonardobishop.quests.api.events.PlayerFinishQuestEvent; +import com.leonardobishop.quests.api.events.PlayerStartQuestEvent; +import com.leonardobishop.quests.api.events.PreStartQuestEvent; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.quest.Quest; +import com.leonardobishop.quests.quest.Task; +import com.leonardobishop.quests.util.Messages; +import com.leonardobishop.quests.util.Options; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import java.util.concurrent.TimeUnit; + +public class NormalQuestController implements QuestController { + + private final Quests plugin; + + public NormalQuestController(Quests plugin) { + this.plugin = plugin; + } + + @Override + public QuestStartResult startQuestForPlayer(QPlayer qPlayer, Quest quest) { + Player player = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + QuestStartResult code = canPlayerStartQuest(qPlayer, quest); + if (player != null) { + String questResultMessage = null; + switch (code) { + case QUEST_SUCCESS: + // This one is hacky + break; + case QUEST_LIMIT_REACHED: + questResultMessage = Messages.QUEST_START_LIMIT.getMessage().replace("{limit}", String.valueOf(Options.QUESTS_START_LIMIT.getIntValue())); + break; + case QUEST_ALREADY_COMPLETED: + questResultMessage = Messages.QUEST_START_DISABLED.getMessage(); + break; + case QUEST_COOLDOWN: + long cooldown = qPlayer.getQuestProgressFile().getCooldownFor(quest); + questResultMessage = Messages.QUEST_START_COOLDOWN.getMessage().replace("{time}", String.valueOf(plugin.convertToFormat(TimeUnit.SECONDS.convert + (cooldown, TimeUnit.MILLISECONDS)))); + break; + case QUEST_LOCKED: + questResultMessage = Messages.QUEST_START_LOCKED.getMessage(); + break; + case QUEST_ALREADY_STARTED: + questResultMessage = Messages.QUEST_START_STARTED.getMessage(); + break; + case QUEST_NO_PERMISSION: + questResultMessage = Messages.QUEST_START_PERMISSION.getMessage(); + break; + case NO_PERMISSION_FOR_CATEGORY: + questResultMessage = Messages.QUEST_CATEGORY_QUEST_PERMISSION.getMessage(); + break; + } + // PreStartQuestEvent -- start + PreStartQuestEvent preStartQuestEvent = new PreStartQuestEvent(player, qPlayer, questResultMessage, code); + Bukkit.getPluginManager().callEvent(preStartQuestEvent); + // PreStartQuestEvent -- end + if (preStartQuestEvent.getQuestResultMessage() != null && code != QuestStartResult.QUEST_SUCCESS) + player.sendMessage(preStartQuestEvent.getQuestResultMessage()); + } + if (code == QuestStartResult.QUEST_SUCCESS) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + questProgress.setStarted(true); + for (TaskProgress taskProgress : questProgress.getTaskProgress()) { + taskProgress.setCompleted(false); + taskProgress.setProgress(null); + } + if (Options.ALLOW_QUEST_TRACK.getBooleanValue() && Options.QUEST_AUTOTRACK.getBooleanValue()) { + qPlayer.trackQuest(quest); + } + questProgress.setCompleted(false); + if (player != null) { + String questStartMessage = Messages.QUEST_START.getMessage().replace("{quest}", quest.getDisplayNameStripped()); + // PlayerStartQuestEvent -- start + PlayerStartQuestEvent questStartEvent = new PlayerStartQuestEvent(player, qPlayer, questProgress, questStartMessage); + Bukkit.getPluginManager().callEvent(questStartEvent); + // PlayerStartQuestEvent -- end + if (questStartEvent.getQuestStartMessage() != null) + player.sendMessage(questStartEvent.getQuestStartMessage()); //Don't send a message if the event message is null + if (Options.TITLES_ENABLED.getBooleanValue()) { + plugin.getTitleHandle().sendTitle(player, Messages.TITLE_QUEST_START_TITLE.getMessage().replace("{quest}", quest + .getDisplayNameStripped()), Messages.TITLE_QUEST_START_SUBTITLE.getMessage().replace("{quest}", quest + .getDisplayNameStripped())); + } + for (String s : quest.getStartString()) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', s)); + } + } + for (Task task : quest.getTasks()) { + try { + plugin.getTaskTypeManager().getTaskType(task.getType()).onStart(quest, task, qPlayer.getPlayerUUID()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return code; + } + + @Override + public QuestStartResult canPlayerStartQuest(QPlayer qPlayer, Quest quest) { + Player p = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + if (qPlayer.getQuestProgressFile().getStartedQuests().size() >= Options.QUESTS_START_LIMIT.getIntValue() && !Options.QUEST_AUTOSTART.getBooleanValue()) { + return QuestStartResult.QUEST_LIMIT_REACHED; + } + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + if (!quest.isRepeatable() && questProgress.isCompletedBefore()) { + //if (playerUUID != null) { + // ??? + //} + return QuestStartResult.QUEST_ALREADY_COMPLETED; + } + long cooldown = qPlayer.getQuestProgressFile().getCooldownFor(quest); + if (cooldown > 0) { + return QuestStartResult.QUEST_COOLDOWN; + } + if (!qPlayer.getQuestProgressFile().hasMetRequirements(quest)) { + return QuestStartResult.QUEST_LOCKED; + } + if (questProgress.isStarted()) { + return QuestStartResult.QUEST_ALREADY_STARTED; + } + if (quest.isPermissionRequired()) { + if (p != null) { + if (!p.hasPermission("quests.quest." + quest.getId())) { + return QuestStartResult.QUEST_NO_PERMISSION; + } + } else { + return QuestStartResult.QUEST_NO_PERMISSION; + } + } + if (quest.getCategoryId() != null && plugin.getQuestManager().getCategoryById(quest.getCategoryId()) != null && plugin.getQuestManager() + .getCategoryById(quest.getCategoryId()).isPermissionRequired()) { + if (p != null) { + if (!p.hasPermission("quests.category." + quest.getCategoryId())) { + return QuestStartResult.NO_PERMISSION_FOR_CATEGORY; + } + } else { + return QuestStartResult.NO_PERMISSION_FOR_CATEGORY; + } + } + return QuestStartResult.QUEST_SUCCESS; + } + + @Override + public boolean completeQuestForPlayer(QPlayer qPlayer, Quest quest) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().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()); + if (Options.ALLOW_QUEST_TRACK.getBooleanValue() && Options.QUEST_AUTOTRACK.getBooleanValue() && !(quest.isRepeatable() && !quest.isCooldownEnabled())) { + qPlayer.trackQuest(null); + } + Player player = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + if (player != null) { + String questFinishMessage = Messages.QUEST_COMPLETE.getMessage().replace("{quest}", quest.getDisplayNameStripped()); + // PlayerFinishQuestEvent -- start + PlayerFinishQuestEvent questFinishEvent = new PlayerFinishQuestEvent(player, qPlayer, questProgress, questFinishMessage); + Bukkit.getPluginManager().callEvent(questFinishEvent); + // PlayerFinishQuestEvent -- end + Bukkit.getServer().getScheduler().runTask(plugin, () -> { + for (String s : quest.getRewards()) { + Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), s.replace("{player}", player.getName())); //TODO PlaceholderAPI support + } + }); + if (questFinishEvent.getQuestFinishMessage() != null) + player.sendMessage(questFinishEvent.getQuestFinishMessage()); + if (Options.TITLES_ENABLED.getBooleanValue()) { + plugin.getTitleHandle().sendTitle(player, Messages.TITLE_QUEST_COMPLETE_TITLE.getMessage().replace("{quest}", quest + .getDisplayNameStripped()), Messages.TITLE_QUEST_COMPLETE_SUBTITLE.getMessage().replace("{quest}", quest + .getDisplayNameStripped())); + } + for (String s : quest.getRewardString()) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', s)); + } + } + if ((Options.ALLOW_QUEST_TRACK.getBooleanValue() && Options.QUEST_AUTOTRACK.getBooleanValue() && !(quest.isRepeatable() && !quest.isCooldownEnabled())) + || (!Options.ALLOW_QUEST_TRACK.getBooleanValue() && Options.QUEST_AUTOTRACK.getBooleanValue())) { + Quest nextQuest; + if (qPlayer.getQuestProgressFile().getStartedQuests().size() > 0) { + nextQuest = qPlayer.getQuestProgressFile().getStartedQuests().get(0); + qPlayer.trackQuest(nextQuest); + } + } + return true; + } + + @Override + public boolean hasPlayerStartedQuest(QPlayer qPlayer, Quest quest) { + if (Options.QUEST_AUTOSTART.getBooleanValue()) { + QuestStartResult response = canPlayerStartQuest(qPlayer, quest); + return response == QuestStartResult.QUEST_SUCCESS || response == QuestStartResult.QUEST_ALREADY_STARTED; + } else { + return qPlayer.getQuestProgressFile().hasQuestProgress(quest) && qPlayer.getQuestProgressFile().getQuestProgress(quest).isStarted(); + } + } + + @Override + public boolean cancelQuestForPlayer(QPlayer qPlayer, Quest quest) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + Player player = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + if (!questProgress.isStarted()) { + if (player != null) { + player.sendMessage(Messages.QUEST_CANCEL_NOTSTARTED.getMessage()); + } + return false; + } + questProgress.setStarted(false); + for (TaskProgress taskProgress : questProgress.getTaskProgress()) { + taskProgress.setProgress(null); + } + if (player != null) { + String questCancelMessage = Messages.QUEST_CANCEL.getMessage().replace("{quest}", quest.getDisplayNameStripped()); + // PlayerCancelQuestEvent -- start + PlayerCancelQuestEvent questCancelEvent = new PlayerCancelQuestEvent(player, qPlayer, questProgress, questCancelMessage); + Bukkit.getPluginManager().callEvent(questCancelEvent); + // PlayerCancelQuestEvent -- end + if (questCancelEvent.getQuestCancelMessage() != null) + player.sendMessage(questCancelEvent.getQuestCancelMessage()); + } + return true; + } + +} diff --git a/src/main/java/com/leonardobishop/quests/quest/controller/QuestController.java b/src/main/java/com/leonardobishop/quests/quest/controller/QuestController.java new file mode 100644 index 00000000..b4b76baa --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/quest/controller/QuestController.java @@ -0,0 +1,15 @@ +package com.leonardobishop.quests.quest.controller; + +import com.leonardobishop.quests.api.enums.QuestStartResult; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.quest.Quest; + +public interface QuestController { + + QuestStartResult startQuestForPlayer(QPlayer qPlayer, Quest quest); + QuestStartResult canPlayerStartQuest(QPlayer qPlayer, Quest quest); + boolean completeQuestForPlayer(QPlayer qPlayer, Quest quest); + boolean hasPlayerStartedQuest(QPlayer qPlayer, Quest quest); + boolean cancelQuestForPlayer(QPlayer qPlayer, Quest quest); + +} diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/TaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/TaskType.java index 0a6147e7..fb7b8b61 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/TaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/TaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.quest.Quest; import com.leonardobishop.quests.quest.Task; import org.bukkit.event.Listener; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/TaskUtils.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/TaskUtils.java index b2dadb63..405db7ff 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/TaskUtils.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/TaskUtils.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.quest.Task; import org.bukkit.entity.Player; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BreedingTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BreedingTaskType.java index 1531df37..501a6aa1 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BreedingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BreedingTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BrewingTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BrewingTaskType.java index f05f8a5b..7a0da7de 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BrewingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BrewingTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BuildingCertainTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BuildingCertainTaskType.java index 6d44ab9d..1e97de3f 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BuildingCertainTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BuildingCertainTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BuildingTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BuildingTaskType.java index 1ca89cea..851c152e 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BuildingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/BuildingTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/CommandTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/CommandTaskType.java index 6823e5af..5e1522fe 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/CommandTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/CommandTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/DealDamageTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/DealDamageTaskType.java index f695b5fb..6affa258 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/DealDamageTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/DealDamageTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/DistancefromTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/DistancefromTaskType.java index bd96760f..604ea556 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/DistancefromTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/DistancefromTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/EnchantingTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/EnchantingTaskType.java index 04754176..fc0b2421 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/EnchantingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/EnchantingTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/ExpEarnTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/ExpEarnTaskType.java index 61147faf..d99688c8 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/ExpEarnTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/ExpEarnTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/FishingTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/FishingTaskType.java index fa6d7780..c35044af 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/FishingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/FishingTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/InventoryTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/InventoryTaskType.java index 4e12ab3c..4ee6e605 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/InventoryTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/InventoryTaskType.java @@ -1,7 +1,7 @@ package com.leonardobishop.quests.quest.tasktype.type; import com.leonardobishop.quests.Quests; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MilkingTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MilkingTaskType.java index 8f8232ed..0d883ac2 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MilkingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MilkingTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningCertainTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningCertainTaskType.java index 125bfecc..7639ad95 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningCertainTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningCertainTaskType.java @@ -1,7 +1,7 @@ package com.leonardobishop.quests.quest.tasktype.type; import com.leonardobishop.quests.Quests; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningTaskType.java index 2007f301..e25adcff 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MobkillingCertainTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MobkillingCertainTaskType.java index da7bd5cb..86bd7fea 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MobkillingCertainTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MobkillingCertainTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; @@ -11,8 +11,6 @@ import com.leonardobishop.quests.quest.tasktype.ConfigValue; import com.leonardobishop.quests.quest.tasktype.TaskType; import com.leonardobishop.quests.quest.tasktype.TaskUtils; import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MobkillingTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MobkillingTaskType.java index 08cd18c4..dd43bd60 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MobkillingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MobkillingTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/PlayerkillingTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/PlayerkillingTaskType.java index c577ac01..60bb1321 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/PlayerkillingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/PlayerkillingTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/PlaytimeTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/PlaytimeTaskType.java index 3b113d01..450365cb 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/PlaytimeTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/PlaytimeTaskType.java @@ -1,7 +1,7 @@ package com.leonardobishop.quests.quest.tasktype.type; import com.leonardobishop.quests.Quests; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/PositionTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/PositionTaskType.java index ffed1476..546cdb10 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/PositionTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/PositionTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/ShearingTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/ShearingTaskType.java index cbf3c175..ca4856a4 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/ShearingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/ShearingTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/TamingTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/TamingTaskType.java index 9f3963e4..663ca403 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/TamingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/TamingTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/WalkingTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/WalkingTaskType.java index 05f10a89..4faebdb0 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/WalkingTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/WalkingTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/ASkyBlockLevelType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/ASkyBlockLevelType.java index 8e621288..bd0aba60 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/ASkyBlockLevelType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/ASkyBlockLevelType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type.dependent; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/BentoBoxLevelTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/BentoBoxLevelTaskType.java index 5e5c53ef..00f4e12f 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/BentoBoxLevelTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/BentoBoxLevelTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type.dependent; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/CitizensDeliverTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/CitizensDeliverTaskType.java index fa64741e..5110d51d 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/CitizensDeliverTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/CitizensDeliverTaskType.java @@ -1,7 +1,7 @@ package com.leonardobishop.quests.quest.tasktype.type.dependent; import com.leonardobishop.quests.Quests; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; import com.leonardobishop.quests.player.questprogressfile.TaskProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/CitizensInteractTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/CitizensInteractTaskType.java index 3e6592b5..08440b05 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/CitizensInteractTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/CitizensInteractTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type.dependent; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsBalanceTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsBalanceTaskType.java index 22cef8a2..eaf6ba13 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsBalanceTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsBalanceTaskType.java @@ -1,7 +1,7 @@ package com.leonardobishop.quests.quest.tasktype.type.dependent; import com.earth2me.essentials.Essentials; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsMoneyEarnTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsMoneyEarnTaskType.java index a6a56623..6b080f13 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsMoneyEarnTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsMoneyEarnTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type.dependent; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/IridiumSkyblockValueType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/IridiumSkyblockValueType.java index e217b8af..3647a3e7 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/IridiumSkyblockValueType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/IridiumSkyblockValueType.java @@ -2,7 +2,7 @@ package com.leonardobishop.quests.quest.tasktype.type.dependent; import com.iridium.iridiumskyblock.Island; import com.iridium.iridiumskyblock.api.IslandWorthCalculatedEvent; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/MythicMobsKillingType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/MythicMobsKillingType.java index 4c6e3bb0..47245665 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/MythicMobsKillingType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/MythicMobsKillingType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type.dependent; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/PlaceholderAPIEvaluateTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/PlaceholderAPIEvaluateTaskType.java index a3508bcc..137844d5 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/PlaceholderAPIEvaluateTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/PlaceholderAPIEvaluateTaskType.java @@ -1,7 +1,7 @@ package com.leonardobishop.quests.quest.tasktype.type.dependent; import com.leonardobishop.quests.Quests; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/ShopGUIPlusBuyCertainTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/ShopGUIPlusBuyCertainTaskType.java index 0b65fb76..664c0ab6 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/ShopGUIPlusBuyCertainTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/ShopGUIPlusBuyCertainTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type.dependent; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/ShopGUIPlusSellCertainTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/ShopGUIPlusSellCertainTaskType.java index 1f16163c..441c306d 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/ShopGUIPlusSellCertainTaskType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/ShopGUIPlusSellCertainTaskType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type.dependent; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/uSkyBlockLevelType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/uSkyBlockLevelType.java index 7e0787cb..a88ca6dc 100644 --- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/uSkyBlockLevelType.java +++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/uSkyBlockLevelType.java @@ -1,6 +1,6 @@ package com.leonardobishop.quests.quest.tasktype.type.dependent; -import com.leonardobishop.quests.QuestsConfigLoader; +import com.leonardobishop.quests.util.QuestsConfigLoader; import com.leonardobishop.quests.api.QuestsAPI; import com.leonardobishop.quests.player.QPlayer; import com.leonardobishop.quests.player.questprogressfile.QuestProgress; diff --git a/src/main/java/com/leonardobishop/quests/util/QuestCompleter.java b/src/main/java/com/leonardobishop/quests/util/QuestCompleter.java new file mode 100644 index 00000000..b6b942fd --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/util/QuestCompleter.java @@ -0,0 +1,99 @@ +package com.leonardobishop.quests.util; + +import com.leonardobishop.quests.Quests; +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.quest.Quest; +import com.leonardobishop.quests.quest.Task; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.LinkedList; +import java.util.Queue; + +public class QuestCompleter implements Runnable { + + private final Queue completionQueue = new LinkedList<>(); + private final Queue fullCheckQueue = new LinkedList<>(); + private final Quests plugin; + + public QuestCompleter(Quests plugin) { + this.plugin = plugin; + } + + @Override + public void run() { + 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()); + if (qPlayer == null) return; + + Quest quest = plugin.getQuestManager().getQuestById(questProgress.getQuestId()); + + if (!qPlayer.hasStartedQuest(quest)) return; + + if (checkComplete(quest, questProgress)) { + qPlayer.completeQuest(quest); + } + } + } + + private void processFullCheckQueue() { + QuestProgressFile questProgressFile = fullCheckQueue.poll(); + if (questProgressFile == null) return; + + Player player = Bukkit.getPlayer(questProgressFile.getPlayerUUID()); + if (player != null && player.isOnline()) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) return; + for (QuestProgress questProgress : questProgressFile.getAllQuestProgress()) { + Quest quest = plugin.getQuestManager().getQuestById(questProgress.getQuestId()); + if (quest == null) continue; + if (!qPlayer.hasStartedQuest(quest)) continue; + + boolean complete = true; + for (Task task : quest.getTasks()) { + TaskProgress taskProgress; + if ((taskProgress = questProgress.getTaskProgress(task.getId())) == null || !taskProgress.isCompleted()) { + complete = false; + break; + } + } + if (complete) { + qPlayer.completeQuest(quest); + } + } + } + } + + 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/util/QuestMode.java b/src/main/java/com/leonardobishop/quests/util/QuestMode.java new file mode 100644 index 00000000..e942d909 --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/util/QuestMode.java @@ -0,0 +1,8 @@ +package com.leonardobishop.quests.util; + +public enum QuestMode { + + NORMAL, + DAILY; + +} diff --git a/src/main/java/com/leonardobishop/quests/util/QuestsAutosaveRunnable.java b/src/main/java/com/leonardobishop/quests/util/QuestsAutosaveRunnable.java new file mode 100644 index 00000000..dbe0b3a9 --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/util/QuestsAutosaveRunnable.java @@ -0,0 +1,45 @@ +package com.leonardobishop.quests.util; + +import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.player.QPlayer; +import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.util.Options; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.UUID; + +public class QuestsAutosaveRunnable extends BukkitRunnable { + + private final Queue queue = new LinkedList<>(); + private final Quests plugin; + + public QuestsAutosaveRunnable(Quests plugin) { + for (Player player : Bukkit.getOnlinePlayers()) { + queue.add(player.getUniqueId()); + } + + this.plugin = plugin; + + this.runTaskTimer(plugin, 2L, 2L); + } + + @Override + public void run() { + UUID player = queue.poll(); + if (player == null) { + try { + super.cancel(); + } catch (Exception ignored) {} + return; + } + + if (Bukkit.getPlayer(player) != null) { + plugin.getPlayerManager().savePlayer(player); + } + } + +} diff --git a/src/main/java/com/leonardobishop/quests/util/QuestsConfigLoader.java b/src/main/java/com/leonardobishop/quests/util/QuestsConfigLoader.java new file mode 100644 index 00000000..9c5215bc --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/util/QuestsConfigLoader.java @@ -0,0 +1,454 @@ +package com.leonardobishop.quests.util; + +import com.leonardobishop.quests.Quests; +import com.leonardobishop.quests.hook.itemgetter.ItemGetter; +import com.leonardobishop.quests.menu.QItemStack; +import com.leonardobishop.quests.quest.Category; +import com.leonardobishop.quests.quest.Quest; +import com.leonardobishop.quests.quest.Task; +import com.leonardobishop.quests.quest.tasktype.TaskType; +import org.apache.commons.lang.StringUtils; +import org.bukkit.ChatColor; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class QuestsConfigLoader { + + private final Map> filesWithProblems = new HashMap<>(); + private final Quests plugin; + private int problemsCount; + + public QuestsConfigLoader(Quests plugin) { + this.plugin = plugin; + } + + /** + * Loads and parses config into memory including the quests folder. + */ + public void loadConfig() { + plugin.reloadConfig(); + Options.invalidateCaches(); + filesWithProblems.clear(); + plugin.setBrokenConfig(false); + + // test CONFIG file integrity + try { + YamlConfiguration config = new YamlConfiguration(); + config.load(new File(plugin.getDataFolder() + File.separator + "config.yml")); + } catch (Exception ex) { + filesWithProblems.put("
config.yml", Collections.singletonList(new ConfigProblem(ConfigProblemType.ERROR, ConfigProblemDescriptions.MALFORMED_YAML.getDescription()))); + plugin.setBrokenConfig(true); + } + + + if (!plugin.isBrokenConfig()) { + HashMap> globalTaskConfig = new HashMap<>(); + 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(QuestsLogger.LoggingLevel.fromNumber(plugin.getConfig().getInt("options.verbose-logging-level", 2))); + + HashMap pathToQuest = new HashMap<>(); + + if (plugin.getConfig().isConfigurationSection("global-task-configuration.types")) { + for (String type : plugin.getConfig().getConfigurationSection("global-task-configuration.types").getKeys(false)) { + HashMap configValues = new HashMap<>(); + for (String key : plugin.getConfig().getConfigurationSection("global-task-configuration.types." + type).getKeys(false)) { + configValues.put(key, plugin.getConfig().get("global-task-configuration.types." + type + "." + key)); + } + globalTaskConfig.putIfAbsent(type, configValues); + } + } + + try { + plugin.setQuestMode(QuestMode.valueOf(plugin.getConfig().getString("quest-mode.mode", "NORMAL").toUpperCase())); + } catch (IllegalArgumentException ex) { + plugin.setQuestMode(QuestMode.NORMAL); + } + + FileVisitor fileVisitor = new SimpleFileVisitor() { + final URI questsRoot = Paths.get(plugin.getDataFolder() + File.separator + "quests").toUri(); + + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attributes) { + try { + File questFile = new File(path.toUri()); + URI relativeLocation = questsRoot.relativize(path.toUri()); + + if (!questFile.getName().toLowerCase().endsWith(".yml")) return FileVisitResult.CONTINUE; + + 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; + } + + String id = questFile.getName().replace(".yml", ""); + + List 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 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")); + } + } + + boolean error = false; + for (ConfigProblem problem : configProblems) { + if (problem.getType() == ConfigProblemType.ERROR) { + error = true; + break; + } + } + + // END OF THE CHECKING + if (!error && !Options.ERROR_CHECKING_OVERRIDE.getBooleanValue(false)) { + QItemStack displayItem = getQItemStack("display", config); + List rewards = config.getStringList("rewards"); + List requirements = config.getStringList("options.requires"); + List rewardString = config.getStringList("rewardstring"); + List 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"); + Map placeholders = new HashMap<>(); + + if (category == null) category = ""; + + if (plugin.getQuestMode() == QuestMode.DAILY) { + repeatable = true; + cooldown = true; + cooldownTime = 0; + requirements = Collections.emptyList(); + permissionRequired = false; + } + + Quest quest; + if (category.equals("")) { + quest = new Quest(id, displayItem, rewards, requirements, repeatable, cooldown, cooldownTime, permissionRequired, rewardString, startString, placeholders, sortOrder); + } else { + quest = new Quest(id, displayItem, rewards, requirements, repeatable, cooldown, cooldownTime, permissionRequired, rewardString, startString, placeholders, 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")); + } + } + + 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 (globalTaskConfig.containsKey(taskType)) { + for (Map.Entry entry : globalTaskConfig.get(taskType).entrySet()) { + if (Options.GLOBAL_TASK_CONFIGURATION_OVERRIDE.getBooleanValue() && task.getConfigValue(entry.getKey()) != null) + continue; + task.addConfigValue(entry.getKey(), entry.getValue()); + } + } + + quest.registerTask(task); + } + + + for (String line : displayItem.getLoreNormal()) { + findInvalidTaskReferences(quest, line, configProblems, "display.lore-normal"); + } + for (String line : displayItem.getLoreStarted()) { + findInvalidTaskReferences(quest, line, configProblems, "display.lore-started"); + } + + if (config.isConfigurationSection("placeholders")) { + for (String p : config.getConfigurationSection("placeholders").getKeys(false)) { + placeholders.put(p, config.getString("placeholders." + p)); + findInvalidTaskReferences(quest, config.getString("placeholders." + p), configProblems, "placeholders." + p); + } + } + 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); + pathToQuest.put(relativeLocation.getPath(), quest); + } + if (!configProblems.isEmpty()) { + filesWithProblems.put(relativeLocation.getPath(), configProblems); + } + } catch (Exception e) { + plugin.getQuestsLogger().severe("An exception occurred when attempting to load quest '" + path + "' (will be ignored)"); + e.printStackTrace(); + } + return FileVisitResult.CONTINUE; + } + }; + + try { + Files.walkFileTree(Paths.get(plugin.getDataFolder() + File.separator + "quests"), fileVisitor); + } catch (IOException e) { + e.printStackTrace(); + } + + // post-load checks + for (Map.Entry loadedQuest : pathToQuest.entrySet()) { + List 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")); + } + } + + if (!configProblems.isEmpty()) { + if (filesWithProblems.containsKey(loadedQuest.getKey())) { + filesWithProblems.get(loadedQuest.getKey()).addAll(configProblems); + } else { + filesWithProblems.put(loadedQuest.getKey(), configProblems); + } + } + } + + for (TaskType taskType : plugin.getTaskTypeManager().getTaskTypes()) { + try { + taskType.onReady(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + problemsCount = 0; + for (List problemList : plugin.getQuestsConfigLoader().getFilesWithProblems().values()) { + problemsCount = problemsCount + problemList.size(); + } + } + + public Map> getFilesWithProblems() { + return filesWithProblems; + } + + public int getProblemsCount() { + return problemsCount; + } + + private void findInvalidTaskReferences(Quest quest, String s, List configProblems, String location) { + Pattern pattern = Pattern.compile("\\{([^}]+)}"); + + Matcher matcher = pattern.matcher(s); + 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]), location)); + } + } + + private QItemStack getQItemStack(String path, FileConfiguration config) { + String cName = config.getString(path + ".name", path + ".name"); + List cLoreNormal = config.getStringList(path + ".lore-normal"); + List cLoreStarted = config.getStringList(path + ".lore-started"); + + List loreNormal = translateColoursInList(cLoreNormal); + List loreStarted = translateColoursInList(cLoreStarted); + + String name; + name = ChatColor.translateAlternateColorCodes('&', cName); + + ItemStack is = plugin.getItemStack(path, config, + ItemGetter.Filter.DISPLAY_NAME, ItemGetter.Filter.LORE, ItemGetter.Filter.ENCHANTMENTS, ItemGetter.Filter.ITEM_FLAGS); + + return new QItemStack(plugin, name, loreNormal, loreStarted, is); + } + + private List translateColoursInList(List list) { + List coloured = new ArrayList<>(); + for (String s : list) { + coloured.add(ChatColor.translateAlternateColorCodes('&', s)); + } + return coloured; + } + + 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 ConfigProblemType { + + ERROR("Error", "E", ChatColor.RED, 1), + WARNING("Warning", "W", ChatColor.YELLOW, 2); + + private final String title; + private final String shortened; + private final ChatColor color; + private final int priority; + + ConfigProblemType(String title, String shortened, ChatColor color, int priority) { + this.title = title; + this.shortened = shortened; + this.color = color; + this.priority = priority; + } + + public String getTitle() { + return title; + } + + public String getShortened() { + return shortened; + } + + public ChatColor getColor() { + return color; + } + + public int getPriority() { + return priority; + } + + } + + 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 ConfigProblem(ConfigProblemType type, String description) { + this.type = type; + this.description = description == null ? "?" : description; + ; + this.location = "?"; + } + + public ConfigProblemType getType() { + return type; + } + + public String getDescription() { + return description; + } + + public String getLocation() { + return location; + } + } +} diff --git a/src/main/java/com/leonardobishop/quests/util/QuestsLogger.java b/src/main/java/com/leonardobishop/quests/util/QuestsLogger.java new file mode 100644 index 00000000..426a2601 --- /dev/null +++ b/src/main/java/com/leonardobishop/quests/util/QuestsLogger.java @@ -0,0 +1,85 @@ +package com.leonardobishop.quests.util; + +import com.leonardobishop.quests.Quests; + +public class QuestsLogger { + + private final Quests plugin; + private LoggingLevel serverLoggingLevel; + + public QuestsLogger(Quests plugin, LoggingLevel serverLoggingLevel) { + this.plugin = plugin; + this.serverLoggingLevel = serverLoggingLevel; + } + + public LoggingLevel getServerLoggingLevel() { + return serverLoggingLevel; + } + + public void setServerLoggingLevel(LoggingLevel serverLoggingLevel) { + this.serverLoggingLevel = serverLoggingLevel; + } + + public void log(String str, LoggingLevel level) { + if (serverLoggingLevel.getNumericVerbosity() < level.getNumericVerbosity()) { + return; + } + switch (level) { + case DEBUG: + plugin.getLogger().info("Debug: " + str); + break; + case INFO: + plugin.getLogger().info(str); + break; + case ERROR: + plugin.getLogger().severe(str); + break; + case WARNING: + plugin.getLogger().warning(str); + break; + } + } + + public void debug(String str) { + log(str, LoggingLevel.DEBUG); + } + + public void info(String str) { + log(str, LoggingLevel.INFO); + } + + public void warning(String str) { + log(str, LoggingLevel.WARNING); + } + + public void severe(String str) { + log(str, LoggingLevel.ERROR); + } + + public enum LoggingLevel { + ERROR(0), + WARNING(1), + INFO(2), + DEBUG(3); + + private int numericVerbosity; + + LoggingLevel(int number) { + numericVerbosity = number; + } + + public int getNumericVerbosity() { + return numericVerbosity; + } + + static LoggingLevel fromNumber(int number) { + for (LoggingLevel level : LoggingLevel.values()) { + if (level.getNumericVerbosity() == number) { + return level; + } + } + return LoggingLevel.INFO; + } + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 2c2e09c7..f7084505 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -262,18 +262,8 @@ options: table-prefix: "quests_" -# This switches up the entire quest system. -# By enabling daily-quests, players will no longer be presented with the standard Quest GUI. -# Instead, they will be presented with 5 random quests. -# The 'requirements' section in each quest does not apply here. -# The 'cooldown' section in each quest does not apply here - if it's done, it's done (and will be repeatable next time they get the quest). -# The 'repeatable' section in each quest does not apply here. It will NOT be repeatable until the next day. -# Enabling this MAY cause previous quest progress to be modified, wiped or changed irreversibly! If you're testing this on a live server, it is wise to backup -# the Quests/playerdata/ folder! You've been warned! -# -# Quests BETA: this feature is a work in progress, it does not work yet! -daily-quests: - enabled: false # <----- NOT YET IMPLEMENTED (THIS WILL NOT DO ANYTHING) +quest-mode: + mode: "NORMAL" # More modes are a work in progress # The global task configuration will apply to the config of each task of a specified type in each quest. # In the example below, every task with a type of "inventory" will have the config option "update-progress" -- cgit v1.2.3-70-g09d2