From af7e1e435f577bbf9742bb526ac00a71a21c219c Mon Sep 17 00:00:00 2001 From: LMBishop <13875753+LMBishop@users.noreply.github.com> Date: Thu, 17 Jun 2021 13:32:02 +0100 Subject: Convert to multi module project - Common module to provide an abstract Quests plugin - Api is still todo --- .../quests/bukkit/BukkitQuestsLogger.java | 66 +++ .../quests/bukkit/BukkitQuestsPlugin.java | 515 ++++++++++++++++ .../bukkit/BukkitServerSchedulerAdapter.java | 22 + .../bukkit/api/event/PlayerCancelQuestEvent.java | 51 ++ .../bukkit/api/event/PlayerFinishQuestEvent.java | 51 ++ .../quests/bukkit/api/event/PlayerQuestEvent.java | 19 + .../bukkit/api/event/PlayerStartQuestEvent.java | 52 ++ .../api/event/PlayerStartTrackQuestEvent.java | 32 + .../api/event/PlayerStopTrackQuestEvent.java | 27 + .../bukkit/api/event/PreStartQuestEvent.java | 57 ++ .../quests/bukkit/command/QuestsCommand.java | 644 +++++++++++++++++++++ .../quests/bukkit/config/BukkitQuestsConfig.java | 91 +++ .../quests/bukkit/config/BukkitQuestsLoader.java | 331 +++++++++++ .../hook/coreprotect/AbstractCoreProtectHook.java | 16 + .../bukkit/hook/coreprotect/CoreProtectHook.java | 29 + .../bukkit/hook/coreprotect/CoreProtectNoHook.java | 10 + .../quests/bukkit/hook/itemgetter/ItemGetter.java | 46 ++ .../bukkit/hook/itemgetter/ItemGetterLatest.java | 240 ++++++++ .../bukkit/hook/itemgetter/ItemGetter_1_13.java | 229 ++++++++ .../hook/itemgetter/ItemGetter_Late_1_8.java | 158 +++++ .../hook/papi/AbstractPlaceholderAPIHook.java | 14 + .../bukkit/hook/papi/PlaceholderAPIHook.java | 27 + .../bukkit/hook/papi/QuestsPlaceholders.java | 346 +++++++++++ .../quests/bukkit/hook/title/Title.java | 8 + .../quests/bukkit/hook/title/Title_Bukkit.java | 12 + .../bukkit/hook/title/Title_BukkitNoTimings.java | 13 + .../quests/bukkit/hook/title/Title_Other.java | 11 + .../quests/bukkit/listener/PlayerJoinListener.java | 51 ++ .../bukkit/listener/PlayerLeaveListener.java | 24 + .../quests/bukkit/menu/CancelQMenu.java | 85 +++ .../quests/bukkit/menu/CategoryQMenu.java | 171 ++++++ .../quests/bukkit/menu/DailyQMenu.java | 97 ++++ .../quests/bukkit/menu/MenuController.java | 176 ++++++ .../leonardobishop/quests/bukkit/menu/QMenu.java | 13 + .../quests/bukkit/menu/QuestQMenu.java | 288 +++++++++ .../quests/bukkit/menu/QuestSortWrapper.java | 44 ++ .../quests/bukkit/menu/StartedQMenu.java | 175 ++++++ .../bukkit/menu/element/CategoryMenuElement.java | 64 ++ .../bukkit/menu/element/CustomMenuElement.java | 17 + .../quests/bukkit/menu/element/MenuElement.java | 9 + .../bukkit/menu/element/QuestMenuElement.java | 120 ++++ .../bukkit/menu/element/SpacerMenuElement.java | 15 + .../quests/bukkit/menu/itemstack/QItemStack.java | 149 +++++ .../bukkit/menu/itemstack/QItemStackRegistry.java | 36 ++ .../questcompleter/BukkitQuestCompleter.java | 106 ++++ .../questcontroller/DailyQuestController.java | 184 ++++++ .../questcontroller/NormalQuestController.java | 285 +++++++++ .../bukkit/runnable/QuestsAutoSaveRunnable.java | 42 ++ .../bukkit/storage/MySqlStorageProvider.java | 276 +++++++++ .../quests/bukkit/storage/YamlStorageProvider.java | 138 +++++ .../quests/bukkit/tasktype/BukkitTaskType.java | 16 + .../bukkit/tasktype/BukkitTaskTypeManager.java | 25 + .../bukkit/tasktype/type/BreedingTaskType.java | 94 +++ .../tasktype/type/BrewingCertainTaskType.java | 114 ++++ .../bukkit/tasktype/type/BrewingTaskType.java | 107 ++++ .../tasktype/type/BuildingCertainTaskType.java | 187 ++++++ .../bukkit/tasktype/type/BuildingTaskType.java | 78 +++ .../bukkit/tasktype/type/CommandTaskType.java | 91 +++ .../bukkit/tasktype/type/DealDamageTaskType.java | 86 +++ .../bukkit/tasktype/type/DistancefromTaskType.java | 108 ++++ .../bukkit/tasktype/type/EnchantingTaskType.java | 80 +++ .../bukkit/tasktype/type/ExpEarnTaskType.java | 78 +++ .../bukkit/tasktype/type/FarmingTaskType.java | 85 +++ .../bukkit/tasktype/type/FishingTaskType.java | 90 +++ .../bukkit/tasktype/type/InventoryTaskType.java | 168 ++++++ .../bukkit/tasktype/type/MilkingTaskType.java | 91 +++ .../tasktype/type/MiningCertainTaskType.java | 195 +++++++ .../bukkit/tasktype/type/MiningTaskType.java | 79 +++ .../tasktype/type/MobkillingCertainTaskType.java | 137 +++++ .../bukkit/tasktype/type/MobkillingTaskType.java | 109 ++++ .../bukkit/tasktype/type/PermissionTaskType.java | 65 +++ .../tasktype/type/PlayerkillingTaskType.java | 91 +++ .../bukkit/tasktype/type/PlaytimeTaskType.java | 87 +++ .../bukkit/tasktype/type/PositionTaskType.java | 98 ++++ .../bukkit/tasktype/type/ShearingTaskType.java | 86 +++ .../bukkit/tasktype/type/TamingTaskType.java | 85 +++ .../bukkit/tasktype/type/WalkingTaskType.java | 85 +++ .../type/dependent/ASkyBlockLevelTaskType.java | 66 +++ .../type/dependent/BentoBoxLevelTaskType.java | 100 ++++ .../type/dependent/CitizensDeliverTaskType.java | 138 +++++ .../type/dependent/CitizensInteractTaskType.java | 68 +++ .../type/dependent/EssentialsBalanceTaskType.java | 95 +++ .../dependent/EssentialsMoneyEarnTaskType.java | 73 +++ .../type/dependent/IridiumSkyblockValueType.java | 87 +++ .../type/dependent/MythicMobsKillingType.java | 107 ++++ .../dependent/PlaceholderAPIEvaluateTaskType.java | 151 +++++ .../dependent/ShopGUIPlusBuyCertainTaskType.java | 85 +++ .../dependent/ShopGUIPlusSellCertainTaskType.java | 85 +++ .../type/dependent/uSkyBlockLevelTaskType.java | 67 +++ .../leonardobishop/quests/bukkit/util/Chat.java | 40 ++ .../quests/bukkit/util/MenuUtils.java | 74 +++ .../quests/bukkit/util/Messages.java | 83 +++ .../quests/bukkit/util/TaskUtils.java | 90 +++ bukkit/src/main/resources/plugin.yml | 30 + .../src/main/resources/resources/bukkit/config.yml | 355 ++++++++++++ .../resources/resources/bukkit/quests/README.txt | 40 ++ .../resources/resources/bukkit/quests/example1.yml | 61 ++ .../resources/resources/bukkit/quests/example2.yml | 47 ++ .../resources/resources/bukkit/quests/example3.yml | 49 ++ .../resources/resources/bukkit/quests/example4.yml | 50 ++ .../resources/resources/bukkit/quests/example5.yml | 38 ++ .../resources/resources/bukkit/quests/example6.yml | 35 ++ .../resources/resources/bukkit/quests/example7.yml | 37 ++ 103 files changed, 10448 insertions(+) create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsLogger.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitServerSchedulerAdapter.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerCancelQuestEvent.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerFinishQuestEvent.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerQuestEvent.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerStartQuestEvent.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerStartTrackQuestEvent.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerStopTrackQuestEvent.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PreStartQuestEvent.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/QuestsCommand.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/config/BukkitQuestsConfig.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/config/BukkitQuestsLoader.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/coreprotect/AbstractCoreProtectHook.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/coreprotect/CoreProtectHook.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/coreprotect/CoreProtectNoHook.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetterLatest.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_1_13.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_Late_1_8.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/AbstractPlaceholderAPIHook.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/PlaceholderAPIHook.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/QuestsPlaceholders.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title_Bukkit.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title_BukkitNoTimings.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title_Other.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/listener/PlayerJoinListener.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/listener/PlayerLeaveListener.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/CancelQMenu.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/CategoryQMenu.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/DailyQMenu.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/MenuController.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/QMenu.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/QuestQMenu.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/QuestSortWrapper.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/StartedQMenu.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/CategoryMenuElement.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/CustomMenuElement.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/MenuElement.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/QuestMenuElement.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/SpacerMenuElement.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/itemstack/QItemStack.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/itemstack/QItemStackRegistry.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcompleter/BukkitQuestCompleter.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/DailyQuestController.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/runnable/QuestsAutoSaveRunnable.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/MySqlStorageProvider.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/YamlStorageProvider.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/BukkitTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/BukkitTaskTypeManager.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BreedingTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BrewingCertainTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BrewingTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BuildingCertainTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BuildingTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/CommandTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DealDamageTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DistancefromTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/EnchantingTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/ExpEarnTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/FarmingTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/FishingTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/InventoryTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MilkingTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MiningCertainTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MiningTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingCertainTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PermissionTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PlayerkillingTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PlaytimeTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PositionTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/ShearingTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/TamingTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/WalkingTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/ASkyBlockLevelTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/BentoBoxLevelTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/CitizensDeliverTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/CitizensInteractTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/EssentialsBalanceTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/EssentialsMoneyEarnTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/IridiumSkyblockValueType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/MythicMobsKillingType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/PlaceholderAPIEvaluateTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/ShopGUIPlusBuyCertainTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/ShopGUIPlusSellCertainTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/uSkyBlockLevelTaskType.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/Chat.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/MenuUtils.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/Messages.java create mode 100644 bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/TaskUtils.java create mode 100644 bukkit/src/main/resources/plugin.yml create mode 100644 bukkit/src/main/resources/resources/bukkit/config.yml create mode 100644 bukkit/src/main/resources/resources/bukkit/quests/README.txt create mode 100644 bukkit/src/main/resources/resources/bukkit/quests/example1.yml create mode 100644 bukkit/src/main/resources/resources/bukkit/quests/example2.yml create mode 100644 bukkit/src/main/resources/resources/bukkit/quests/example3.yml create mode 100644 bukkit/src/main/resources/resources/bukkit/quests/example4.yml create mode 100644 bukkit/src/main/resources/resources/bukkit/quests/example5.yml create mode 100644 bukkit/src/main/resources/resources/bukkit/quests/example6.yml create mode 100644 bukkit/src/main/resources/resources/bukkit/quests/example7.yml (limited to 'bukkit/src/main') diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsLogger.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsLogger.java new file mode 100644 index 00000000..d50752fd --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsLogger.java @@ -0,0 +1,66 @@ +package com.leonardobishop.quests.bukkit; + +import com.leonardobishop.quests.common.logger.QuestsLogger; + +public class BukkitQuestsLogger implements QuestsLogger { + + private final BukkitQuestsPlugin plugin; + private LoggingLevel serverLoggingLevel; + + public BukkitQuestsLogger(BukkitQuestsPlugin plugin) { + this.plugin = plugin; + serverLoggingLevel = LoggingLevel.INFO; + } + + @Override + public LoggingLevel getServerLoggingLevel() { + return serverLoggingLevel; + } + + @Override + public void setServerLoggingLevel(LoggingLevel serverLoggingLevel) { + this.serverLoggingLevel = serverLoggingLevel; + } + + @Override + 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; + } + } + + @Override + public void debug(String str) { + log(str, LoggingLevel.DEBUG); + } + + @Override + public void info(String str) { + log(str, LoggingLevel.INFO); + } + + @Override + public void warning(String str) { + log(str, LoggingLevel.WARNING); + } + + @Override + public void severe(String str) { + log(str, LoggingLevel.ERROR); + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java new file mode 100644 index 00000000..eeb359bc --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java @@ -0,0 +1,515 @@ +package com.leonardobishop.quests.bukkit; + +import com.leonardobishop.quests.bukkit.command.QuestsCommand; +import com.leonardobishop.quests.bukkit.config.BukkitQuestsConfig; +import com.leonardobishop.quests.bukkit.config.BukkitQuestsLoader; +import com.leonardobishop.quests.bukkit.hook.coreprotect.AbstractCoreProtectHook; +import com.leonardobishop.quests.bukkit.hook.coreprotect.CoreProtectHook; +import com.leonardobishop.quests.bukkit.hook.coreprotect.CoreProtectNoHook; +import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetter; +import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetterLatest; +import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetter_1_13; +import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetter_Late_1_8; +import com.leonardobishop.quests.bukkit.hook.papi.AbstractPlaceholderAPIHook; +import com.leonardobishop.quests.bukkit.hook.papi.PlaceholderAPIHook; +import com.leonardobishop.quests.bukkit.hook.title.Title; +import com.leonardobishop.quests.bukkit.hook.title.Title_Bukkit; +import com.leonardobishop.quests.bukkit.hook.title.Title_BukkitNoTimings; +import com.leonardobishop.quests.bukkit.hook.title.Title_Other; +import com.leonardobishop.quests.bukkit.listener.PlayerJoinListener; +import com.leonardobishop.quests.bukkit.listener.PlayerLeaveListener; +import com.leonardobishop.quests.bukkit.questcompleter.BukkitQuestCompleter; +import com.leonardobishop.quests.bukkit.menu.MenuController; +import com.leonardobishop.quests.bukkit.menu.itemstack.QItemStackRegistry; +import com.leonardobishop.quests.bukkit.questcontroller.NormalQuestController; +import com.leonardobishop.quests.bukkit.runnable.QuestsAutoSaveRunnable; +import com.leonardobishop.quests.bukkit.storage.MySqlStorageProvider; +import com.leonardobishop.quests.bukkit.storage.YamlStorageProvider; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskTypeManager; +import com.leonardobishop.quests.bukkit.tasktype.type.BreedingTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.BrewingTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.BuildingCertainTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.BuildingTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.CommandTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.DealDamageTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.DistancefromTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.EnchantingTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.ExpEarnTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.FishingTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.InventoryTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.MilkingTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.MiningCertainTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.MiningTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.MobkillingCertainTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.MobkillingTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.PermissionTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.PlayerkillingTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.PlaytimeTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.PositionTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.ShearingTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.TamingTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.WalkingTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.dependent.ASkyBlockLevelTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.dependent.BentoBoxLevelTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.dependent.CitizensDeliverTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.dependent.CitizensInteractTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.dependent.EssentialsBalanceTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.dependent.EssentialsMoneyEarnTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.dependent.MythicMobsKillingType; +import com.leonardobishop.quests.bukkit.tasktype.type.dependent.PlaceholderAPIEvaluateTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.dependent.ShopGUIPlusBuyCertainTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.dependent.ShopGUIPlusSellCertainTaskType; +import com.leonardobishop.quests.bukkit.tasktype.type.dependent.uSkyBlockLevelTaskType; +import com.leonardobishop.quests.bukkit.util.Messages; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.config.ConfigProblemDescriptions; +import com.leonardobishop.quests.common.config.QuestsConfig; +import com.leonardobishop.quests.common.logger.QuestsLogger; +import com.leonardobishop.quests.common.player.QPlayerManager; +import com.leonardobishop.quests.common.plugin.Quests; +import com.leonardobishop.quests.common.quest.QuestCompleter; +import com.leonardobishop.quests.common.quest.QuestManager; +import com.leonardobishop.quests.common.questcontroller.QuestController; +import com.leonardobishop.quests.common.scheduler.ServerScheduler; +import com.leonardobishop.quests.common.storage.StorageProvider; +import com.leonardobishop.quests.common.tasktype.TaskType; +import com.leonardobishop.quests.common.tasktype.TaskTypeManager; +import com.leonardobishop.quests.common.updater.Updater; +import org.bstats.bukkit.MetricsLite; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class BukkitQuestsPlugin extends JavaPlugin implements Quests { + + private QuestsLogger questsLogger; + private QuestManager questManager; + private TaskTypeManager taskTypeManager; + private QPlayerManager qPlayerManager; + private QuestController questController; + private QuestCompleter questCompleter; + private BukkitQuestsConfig questsConfig; + private Updater updater; + private ServerScheduler serverScheduler; + private StorageProvider storageProvider; + + private boolean validConfiguration; + private Map> configProblems; + + private QItemStackRegistry qItemStackRegistry; + private MenuController menuController; + private AbstractPlaceholderAPIHook placeholderAPIHook; + private AbstractCoreProtectHook coreProtectHook; + private ItemGetter itemGetter; + private Title titleHandle; + + private BukkitTask questAutoSaveTask; + private BukkitTask questQueuePollTask; + + @Override + public QuestsLogger getQuestsLogger() { + return questsLogger; + } + + @Override + public QuestManager getQuestManager() { + return questManager; + } + + @Override + public TaskTypeManager getTaskTypeManager() { + return taskTypeManager; + } + + @Override + public QPlayerManager getPlayerManager() { + return qPlayerManager; + } + + @Override + public QuestController getQuestController() { + return questController; + } + + @Override + public QuestCompleter getQuestCompleter() { + return questCompleter; + } + + @Override + public QuestsConfig getQuestsConfig() { + return questsConfig; + } + + @Override + public Updater getUpdater() { + return updater; + } + + @Override + public StorageProvider getStorageProvider() { + return storageProvider; + } + + @Override + public ServerScheduler getScheduler() { + return serverScheduler; + } + + @Override + public void onEnable() { + this.questsLogger = new BukkitQuestsLogger(this); + this.generateConfigurations(); + this.questsConfig = new BukkitQuestsConfig(new File(super.getDataFolder() + File.separator + "config.yml")); + this.questManager = new QuestManager(this); + this.taskTypeManager = new BukkitTaskTypeManager(this); + this.serverScheduler = new BukkitServerSchedulerAdapter(this); + + if (!this.reloadBaseConfiguration()) { + questsLogger.severe("Plugin cannot start into a stable state as the configuration is broken!"); + super.getServer().getPluginManager().disablePlugin(this); + return; + } + + String configuredProvider = questsConfig.getString("options.storage.provider", "yaml"); + switch (configuredProvider.toLowerCase()) { + default: + questsLogger.warning("No valid storage provider is configured - Quests will use YAML storage as a default"); + case "yaml": + this.storageProvider = new YamlStorageProvider(this); + break; + case "mysql": + this.storageProvider = new MySqlStorageProvider(this, this.getConfig().getConfigurationSection("options.storage.database-settings")); + } + + try { + storageProvider.init(); + } catch (Exception e) { + questsLogger.severe("An error occurred initialising the storage provider."); + e.printStackTrace(); + } + + this.setupVersionSpecific(); + + Messages.setPlugin(this); + this.qPlayerManager = new QPlayerManager(this, storageProvider, questController); + this.menuController = new MenuController(this); + this.qItemStackRegistry = new QItemStackRegistry(); + this.questCompleter = new BukkitQuestCompleter(this); + + MetricsLite metrics = new MetricsLite(this, 3443); + if (metrics.isEnabled()) { + this.getQuestsLogger().info("Metrics started. This can be disabled at /plugins/bStats/config.yml."); + } + + if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { + this.placeholderAPIHook = new PlaceholderAPIHook(); + this.placeholderAPIHook.registerExpansion(this); + } + + if (Bukkit.getPluginManager().isPluginEnabled("CoreProtect")) { + this.coreProtectHook = new CoreProtectHook(); + } else { + this.coreProtectHook = new CoreProtectNoHook(); + } + + boolean ignoreUpdates = false; + try { + ignoreUpdates = new File(this.getDataFolder() + File.separator + "stfuQuestsUpdate").exists(); + } catch (Throwable ignored) { } + + + this.updater = new Updater(this, super.getDescription().getVersion(), !ignoreUpdates); + if (!ignoreUpdates) { + serverScheduler.doAsync(() -> { + updater.check(); + }); + } + + super.getCommand("quests").setExecutor(new QuestsCommand(this)); + + super.getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this); + super.getServer().getPluginManager().registerEvents(menuController, this); + super.getServer().getPluginManager().registerEvents(new PlayerLeaveListener(this), this); + + // register task types after the server has fully started + Bukkit.getScheduler().runTask(this, () -> { + taskTypeManager.registerTaskType(new MiningTaskType(this)); + taskTypeManager.registerTaskType(new MiningCertainTaskType(this)); + taskTypeManager.registerTaskType(new BuildingTaskType(this)); + taskTypeManager.registerTaskType(new BuildingCertainTaskType(this)); + taskTypeManager.registerTaskType(new MobkillingTaskType(this)); + taskTypeManager.registerTaskType(new MobkillingCertainTaskType(this)); + taskTypeManager.registerTaskType(new PlayerkillingTaskType(this)); + taskTypeManager.registerTaskType(new FishingTaskType(this)); + taskTypeManager.registerTaskType(new InventoryTaskType(this)); + taskTypeManager.registerTaskType(new WalkingTaskType(this)); + taskTypeManager.registerTaskType(new TamingTaskType(this)); + taskTypeManager.registerTaskType(new MilkingTaskType(this)); + taskTypeManager.registerTaskType(new ShearingTaskType(this)); + taskTypeManager.registerTaskType(new PositionTaskType(this)); + taskTypeManager.registerTaskType(new PlaytimeTaskType(this)); + taskTypeManager.registerTaskType(new BrewingTaskType(this)); + taskTypeManager.registerTaskType(new ExpEarnTaskType(this)); + taskTypeManager.registerTaskType(new BreedingTaskType(this)); + taskTypeManager.registerTaskType(new EnchantingTaskType(this)); + taskTypeManager.registerTaskType(new DealDamageTaskType(this)); + taskTypeManager.registerTaskType(new PermissionTaskType(this)); + taskTypeManager.registerTaskType(new DistancefromTaskType(this)); + taskTypeManager.registerTaskType(new CommandTaskType(this)); + // TODO: FIX + // taskTypeManager.registerTaskType(new BrewingCertainTaskType()); + if (Bukkit.getPluginManager().isPluginEnabled("ASkyBlock")) { + taskTypeManager.registerTaskType(new ASkyBlockLevelTaskType(this)); + } + if (Bukkit.getPluginManager().isPluginEnabled("BentoBox")) { + BentoBoxLevelTaskType.register(this, taskTypeManager); + } + //TODO FIX +// if (Bukkit.getPluginManager().isPluginEnabled("IridiumSkyblock")) { +// taskTypeManager.registerTaskType(new IridiumSkyblockValueType()); +// } + if (Bukkit.getPluginManager().isPluginEnabled("uSkyBlock")) { + taskTypeManager.registerTaskType(new uSkyBlockLevelTaskType(this)); + } + if (Bukkit.getPluginManager().isPluginEnabled("Citizens")) { + taskTypeManager.registerTaskType(new CitizensDeliverTaskType(this)); + taskTypeManager.registerTaskType(new CitizensInteractTaskType(this)); + } + if (Bukkit.getPluginManager().isPluginEnabled("MythicMobs")) { + taskTypeManager.registerTaskType(new MythicMobsKillingType(this)); + } + if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { + taskTypeManager.registerTaskType(new PlaceholderAPIEvaluateTaskType(this)); + } + if (Bukkit.getPluginManager().isPluginEnabled("Essentials")) { + taskTypeManager.registerTaskType(new EssentialsMoneyEarnTaskType(this)); + taskTypeManager.registerTaskType(new EssentialsBalanceTaskType(this)); + } + if (Bukkit.getPluginManager().isPluginEnabled("ShopGUIPlus")) { + // not tested + taskTypeManager.registerTaskType(new ShopGUIPlusBuyCertainTaskType(this)); + taskTypeManager.registerTaskType(new ShopGUIPlusSellCertainTaskType(this)); + } + + taskTypeManager.closeRegistrations(); + reloadQuests(); + + for (Player player : Bukkit.getOnlinePlayers()) { + qPlayerManager.loadPlayer(player.getUniqueId()); + } + }); + } + + @Override + public void reloadQuests() { + if (this.reloadBaseConfiguration()) { + BukkitQuestsLoader questsLoader = new BukkitQuestsLoader(this); + configProblems = questsLoader.loadQuests(new File(super.getDataFolder() + File.separator + "quests")); + + for (TaskType taskType : taskTypeManager.getTaskTypes()) { + try { + taskType.onReady(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } else { + configProblems = Collections.singletonMap("
config.yml", + Collections.singletonList(new ConfigProblem(ConfigProblem.ConfigProblemType.ERROR, ConfigProblemDescriptions.MALFORMED_YAML.getDescription()))); + } + } + + public ItemStack getItemStack(String path, ConfigurationSection config, ItemGetter.Filter... excludes) { + return itemGetter.getItem(path, config, excludes); + } + + private boolean reloadBaseConfiguration() { + this.validConfiguration = questsConfig.loadConfig(); + + if (validConfiguration) { + int loggingLevel = questsConfig.getInt("options.verbose-logging-level", 2); + questsLogger.setServerLoggingLevel(QuestsLogger.LoggingLevel.fromNumber(loggingLevel)); + + switch (questsConfig.getString("quest-mode.mode", "normal").toLowerCase()) { + default: + case "normal": + questController = new NormalQuestController(this); + //TODO the other one + } + + long autoSaveInterval = this.getConfig().getLong("options.performance-tweaking.quest-autosave-interval", 12000); + try { + if (questAutoSaveTask != null) questAutoSaveTask.cancel(); + questAutoSaveTask = Bukkit.getScheduler().runTaskTimer(this, () -> new QuestsAutoSaveRunnable(this), autoSaveInterval, autoSaveInterval); + } catch (Exception ex) { + questsLogger.debug("Cannot cancel and restart quest autosave task"); + } + + long queueExecuteInterval = this.getConfig().getLong("options.performance-tweaking.quest-queue-executor-interval", 1); + try { + if (questQueuePollTask != null) questQueuePollTask.cancel(); + questQueuePollTask = Bukkit.getScheduler().runTaskTimer(this, (BukkitQuestCompleter) questCompleter, queueExecuteInterval, queueExecuteInterval); + } catch (Exception ex) { + questsLogger.debug("Cannot cancel and restart queue executor task"); + } + } + return validConfiguration; + } + + private void setupVersionSpecific() { + String version; + try { + version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; + } catch (ArrayIndexOutOfBoundsException e) { + getQuestsLogger().warning("Failed to resolve server version - some features will not work!"); + titleHandle = new Title_Other(); + itemGetter = new ItemGetter_Late_1_8(); + return; + } + + getQuestsLogger().info("Your server is running version " + version + "."); + + if (version.startsWith("v1_7")) { + titleHandle = new Title_Other(); + } else if (version.startsWith("v1_8") || version.startsWith("v1_9") || version.startsWith("v1_10")) { + titleHandle = new Title_BukkitNoTimings(); + } else { + titleHandle = new Title_Bukkit(); + } + + if (version.startsWith("v1_7") || version.startsWith("v1_8") || version.startsWith("v1_9") + || version.startsWith("v1_10") || version.startsWith("v1_11") || version.startsWith("v1_12")) { + itemGetter = new ItemGetter_Late_1_8(); + } else if (version.startsWith("v1_13")) { + itemGetter = new ItemGetter_1_13(); + } else { + itemGetter = new ItemGetterLatest(); + } + + questsConfig.setItemGetter(itemGetter); + + if (titleHandle instanceof Title_Bukkit) { + getQuestsLogger().info("Titles have been enabled."); + } else if (titleHandle instanceof Title_BukkitNoTimings) { + getQuestsLogger().info("Titles have been enabled, although they have limited timings."); + } else { + getQuestsLogger().info("Titles are not supported for this version."); + } + } + + private void generateConfigurations() { + File directory = new File(String.valueOf(this.getDataFolder())); + if (!directory.exists() && !directory.isDirectory()) { + directory.mkdir(); + } + + File config = new File(this.getDataFolder() + File.separator + "config.yml"); + if (!config.exists()) { + try { + config.createNewFile(); + try (InputStream in = BukkitQuestsPlugin.class.getClassLoader().getResourceAsStream("resources/bukkit/config.yml"); + OutputStream out = new FileOutputStream(config)) { + byte[] buffer = new byte[1024]; + int lenght = in.read(buffer); + while (lenght != -1) { + out.write(buffer, 0, lenght); + lenght = in.read(buffer); + } + } catch (IOException e) { + e.printStackTrace(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + File questsDirectory = new File(this.getDataFolder() + File.separator + "quests"); + if (!questsDirectory.exists() && !questsDirectory.isDirectory()) { + questsDirectory.mkdir(); + + ArrayList examples = new ArrayList<>(); + examples.add("example1.yml"); + examples.add("example2.yml"); + examples.add("example3.yml"); + examples.add("example4.yml"); + examples.add("example5.yml"); + examples.add("example6.yml"); + examples.add("example7.yml"); + examples.add("README.txt"); + + for (String name : examples) { + File file = new File(this.getDataFolder() + File.separator + "quests" + File.separator + name); + try { + file.createNewFile(); + try (InputStream in = BukkitQuestsPlugin.class.getClassLoader().getResourceAsStream("resources/bukkit/quests/" + name); + OutputStream out = new FileOutputStream(file)) { + byte[] buffer = new byte[1024]; + int lenght = in.read(buffer); + while (lenght != -1) { + out.write(buffer, 0, lenght); + lenght = in.read(buffer); + } + } catch (IOException e) { + e.printStackTrace(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + public boolean isValidConfiguration() { + return validConfiguration; + } + + public Map> getConfigProblems() { + return configProblems; + } + + public AbstractPlaceholderAPIHook getPlaceholderAPIHook() { + return placeholderAPIHook; + } + + public AbstractCoreProtectHook getCoreProtectHook() { + return coreProtectHook; + } + + public ItemGetter getItemGetter() { + return itemGetter; + } + + public Title getTitleHandle() { + return titleHandle; + } + + public QItemStackRegistry getQItemStackRegistry() { + return qItemStackRegistry; + } + + public MenuController getMenuController() { + return menuController; + } + + @NotNull + @Override + public FileConfiguration getConfig() { + return questsConfig.getConfig(); + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitServerSchedulerAdapter.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitServerSchedulerAdapter.java new file mode 100644 index 00000000..8619642b --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitServerSchedulerAdapter.java @@ -0,0 +1,22 @@ +package com.leonardobishop.quests.bukkit; + +import com.leonardobishop.quests.common.scheduler.ServerScheduler; + +public class BukkitServerSchedulerAdapter implements ServerScheduler { + + private final BukkitQuestsPlugin plugin; + + public BukkitServerSchedulerAdapter(BukkitQuestsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void doSync(Runnable runnable) { + plugin.getServer().getScheduler().runTask(plugin, runnable); + } + + @Override + public void doAsync(Runnable runnable) { + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, runnable); + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerCancelQuestEvent.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerCancelQuestEvent.java new file mode 100644 index 00000000..af431626 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerCancelQuestEvent.java @@ -0,0 +1,51 @@ +package com.leonardobishop.quests.bukkit.api.event; + +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class PlayerCancelQuestEvent extends PlayerQuestEvent { + private final static HandlerList handlers = new HandlerList(); + private final QuestProgress questProgress; + private String questCancelMessage; + + public PlayerCancelQuestEvent(@NotNull Player who, @NotNull QPlayer questPlayer, @NotNull QuestProgress questProgress, String questCancelMessage) { + super(who, questPlayer); + this.questProgress = questProgress; + this.questCancelMessage = questCancelMessage; + } + + /** + * @return The quest progress + */ + public QuestProgress getQuestProgress() { + return this.questProgress; + } + + /** + * @return The message sent to the player that cancel the quest + */ + public String getQuestCancelMessage() { + return this.questCancelMessage; + } + + /** + * @param questCancelMessage The quest cancel message + * @return The quest cancel message set + */ + public String setQuestCancelMessage(String questCancelMessage) { + return (this.questCancelMessage = questCancelMessage); + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerFinishQuestEvent.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerFinishQuestEvent.java new file mode 100644 index 00000000..d38d4f78 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerFinishQuestEvent.java @@ -0,0 +1,51 @@ +package com.leonardobishop.quests.bukkit.api.event; + +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class PlayerFinishQuestEvent extends PlayerQuestEvent { + private final static HandlerList handlers = new HandlerList(); + private final QuestProgress questProgress; + private String questFinishMessage; + + public PlayerFinishQuestEvent(@NotNull Player who, @NotNull QPlayer questPlayer, @NotNull QuestProgress questProgress, String questFinishMessage) { + super(who, questPlayer); + this.questProgress = questProgress; + this.questFinishMessage = questFinishMessage; + } + + /** + * @return The quest progress + */ + public QuestProgress getQuestProgress() { + return this.questProgress; + } + + /** + * @return The message sent to the player that finish the quest + */ + public String getQuestFinishMessage() { + return this.questFinishMessage; + } + + /** + * @param questFinishMessage The quest finish message + * @return The quest finish message set + */ + public String setQuestFinishMessage(String questFinishMessage) { + return (this.questFinishMessage = questFinishMessage); + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerQuestEvent.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerQuestEvent.java new file mode 100644 index 00000000..a6a0a26a --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerQuestEvent.java @@ -0,0 +1,19 @@ +package com.leonardobishop.quests.bukkit.api.event; + +import com.leonardobishop.quests.common.player.QPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.NotNull; + +public abstract class PlayerQuestEvent extends PlayerEvent { + private final QPlayer questPlayer; + + public PlayerQuestEvent(@NotNull Player who, @NotNull QPlayer questPlayer) { + super(who); + this.questPlayer = questPlayer; + } + + public QPlayer getQuestPlayer() { + return this.questPlayer; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerStartQuestEvent.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerStartQuestEvent.java new file mode 100644 index 00000000..87f01ce1 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerStartQuestEvent.java @@ -0,0 +1,52 @@ +package com.leonardobishop.quests.bukkit.api.event; + +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class PlayerStartQuestEvent extends PlayerQuestEvent { + + private final static HandlerList handlers = new HandlerList(); + private final QuestProgress questProgress; + private String questStartMessage; + + public PlayerStartQuestEvent(@NotNull Player who, @NotNull QPlayer questPlayer, @NotNull QuestProgress questProgress, String questStartMessage) { + super(who, questPlayer); + this.questProgress = questProgress; + this.questStartMessage = questStartMessage; + } + + /** + * @return The quest progress + */ + public QuestProgress getQuestProgress() { + return this.questProgress; + } + + /** + * @return The message sent to the player that start the quest + */ + public String getQuestStartMessage() { + return this.questStartMessage; + } + + /** + * @param questStartMessage The quest start message + * @return The quest start message set + */ + public String setQuestStartMessage(String questStartMessage) { + return (this.questStartMessage = questStartMessage); + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerStartTrackQuestEvent.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerStartTrackQuestEvent.java new file mode 100644 index 00000000..107924a6 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerStartTrackQuestEvent.java @@ -0,0 +1,32 @@ +package com.leonardobishop.quests.bukkit.api.event; + +import com.leonardobishop.quests.common.player.QPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class PlayerStartTrackQuestEvent extends PlayerQuestEvent { + private final static HandlerList handlers = new HandlerList(); + private final QPlayer qPlayer; + + public PlayerStartTrackQuestEvent(@NotNull Player who, QPlayer qPlayer) { + super(who, qPlayer); + this.qPlayer = qPlayer; + } + + public QPlayer getQPlayer() { + return qPlayer; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerStopTrackQuestEvent.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerStopTrackQuestEvent.java new file mode 100644 index 00000000..288013b7 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PlayerStopTrackQuestEvent.java @@ -0,0 +1,27 @@ +package com.leonardobishop.quests.bukkit.api.event; + +import com.leonardobishop.quests.common.player.QPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class PlayerStopTrackQuestEvent extends PlayerQuestEvent { + + private final static HandlerList handlers = new HandlerList(); + private final QPlayer qPlayer; + + public PlayerStopTrackQuestEvent(@NotNull Player who, QPlayer qPlayer) { + super(who, qPlayer); + this.qPlayer = qPlayer; + } + + public QPlayer getQPlayer() { + return qPlayer; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PreStartQuestEvent.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PreStartQuestEvent.java new file mode 100644 index 00000000..b2513415 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/api/event/PreStartQuestEvent.java @@ -0,0 +1,57 @@ +package com.leonardobishop.quests.bukkit.api.event; + +import com.leonardobishop.quests.common.enums.QuestStartResult; +import com.leonardobishop.quests.common.player.QPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class PreStartQuestEvent extends PlayerQuestEvent { + + private final static HandlerList handlers = new HandlerList(); + private QuestStartResult questStartResult; + private String questResultMessage; + + public PreStartQuestEvent(@NotNull Player who, @NotNull QPlayer questPlayer, String questResultMessage, @NotNull QuestStartResult questStartResult) { + super(who, questPlayer); + this.questStartResult = questStartResult; + this.questResultMessage = questResultMessage; + } + + public QuestStartResult getQuestStartResult() { + return this.questStartResult; + } + + public QuestStartResult setQuestStartResult(QuestStartResult questStartResult) { + return (this.questStartResult = questStartResult); + } + + /** + * @return The message sent to the player of the result of the quest + *

+ * For {@link QuestStartResult#QUEST_SUCCESS} please use {@link PlayerStartQuestEvent} + */ + public String getQuestResultMessage() { + return this.questResultMessage; + } + + /** + * @param questResultMessage The quest result message + * @return The quest result message set + *

+ * For {@link QuestStartResult#QUEST_SUCCESS} please use {@link PlayerStartQuestEvent} + */ + public String setQuestResultMessage(String questResultMessage) { + return (this.questResultMessage = questResultMessage); + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/QuestsCommand.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/QuestsCommand.java new file mode 100644 index 00000000..37a388fb --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/QuestsCommand.java @@ -0,0 +1,644 @@ +package com.leonardobishop.quests.bukkit.command; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.util.Chat; +import com.leonardobishop.quests.bukkit.util.Messages; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.enums.QuestStartResult; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.common.quest.Category; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import com.leonardobishop.quests.common.tasktype.TaskType; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.bukkit.util.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +public class QuestsCommand implements TabExecutor { + + private final BukkitQuestsPlugin plugin; + + public QuestsCommand(BukkitQuestsPlugin plugin) { + this.plugin = plugin; + } + + @SuppressWarnings("deprecation") + @Override + public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { + if (plugin.getTaskTypeManager().areRegistrationsAccepted()) { + sender.sendMessage(ChatColor.RED + "Quests is not ready yet."); + return true; + } + if (!plugin.isValidConfiguration() + && !(args.length >= 2 + && (args[0].equalsIgnoreCase("a") || args[0].equalsIgnoreCase("admin")) + && args[1].equalsIgnoreCase("reload"))) { + sender.sendMessage(ChatColor.RED + "Quests cannot be used right now. Please speak to an administrator."); + if (sender.hasPermission("quests.admin")) { + showProblems(sender); + sender.sendMessage(ChatColor.RED + "The main config (config.yml) must be in tact before quests can be used. " + + "Please use the above information to help rectify the problem."); + } + return true; + } + + if (args.length >= 1 && args[0].equalsIgnoreCase("help")) { + showHelp(sender); + return true; + } + + if (args.length == 0 && sender instanceof Player) { + Player player = (Player) sender; + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + player.sendMessage(Messages.COMMAND_DATA_NOT_LOADED.getMessage()); + return true; + } + plugin.getMenuController().openMainMenu(qPlayer); + return true; + } else if (args.length >= 1) { + if ((args[0].equalsIgnoreCase("a") || args[0].equalsIgnoreCase("admin")) && sender.hasPermission("quests.admin")) { + if (args.length == 2) { + if (args[1].equalsIgnoreCase("opengui")) { + showAdminHelp(sender, "opengui"); + return true; + } else if (args[1].equalsIgnoreCase("moddata")) { + showAdminHelp(sender, "moddata"); + return true; + } else if (args[1].equalsIgnoreCase("reload")) { + sender.sendMessage(ChatColor.GRAY + "Please note that some options, such as storage, require a full restart for chances to take effect."); + plugin.reloadConfig(); + plugin.reloadQuests(); + if (!plugin.getConfigProblems().isEmpty()) showProblems(sender); + sender.sendMessage(ChatColor.GREEN + "Quests successfully reloaded."); + return true; + } else if (args[1].equalsIgnoreCase("config")) { + showProblems(sender); + return true; + //TODO +// } else if (args[1].equalsIgnoreCase("itemstack")) { +// if (!(sender instanceof Player)) { +// sender.sendMessage("You must be a player to use this command."); +// return true; +// } +// Player player = (Player) sender; +// ItemStack is = player.getItemInHand(); +// if (is == null || is.getType() == Material.AIR) { +// sender.sendMessage(ChatColor.GRAY + "There is no information about this ItemStack."); +// return true; +// } +// sender.sendMessage(ToStringBuilder.reflectionToString(is)); +// sender.sendMessage(ToStringBuilder.reflectionToString(is.getItemMeta())); +// return true; + } else if (args[1].equalsIgnoreCase("types")) { + sender.sendMessage(ChatColor.GRAY + "Registered task types:"); + for (TaskType taskType : plugin.getTaskTypeManager().getTaskTypes()) { + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + taskType.getType()); + } + 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 controller: " + plugin.getQuestController().getName()); + 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]"); + } + sender.sendMessage(ChatColor.DARK_GRAY + "View info using /q a info [quest]."); + return true; + } else if (args[1].equalsIgnoreCase("update")) { + sender.sendMessage(ChatColor.GRAY + "Checking for updates..."); + Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> { + plugin.getUpdater().check(); + if (plugin.getUpdater().isUpdateReady()) { + String updateMessage = Messages.QUEST_UPDATER.getMessage() + .replace("{newver}", plugin.getUpdater().getReturnedVersion()) + .replace("{oldver}", plugin.getUpdater().getInstalledVersion()) + .replace("{link}", plugin.getUpdater().getUpdateLink()); + sender.sendMessage(updateMessage); + } else { + sender.sendMessage(ChatColor.GRAY + "No updates were found."); + } + }); + return true; + } else if (args[1].equalsIgnoreCase("wiki")) { + sender.sendMessage(ChatColor.RED + "Link to Quests wiki: " + ChatColor.GRAY + "https://github.com/LMBishop/Quests/wiki"); + return true; + } else if (args[1].equalsIgnoreCase("about")) { + sender.sendMessage(ChatColor.RED + "Quests " + ChatColor.BOLD + "v" + plugin.getDescription().getVersion()); + sender.sendMessage(ChatColor.DARK_GRAY + " - " + ChatColor.RED + "Source code: " + ChatColor.GRAY + "https://github.com/LMBishop/Quests/"); + sender.sendMessage(ChatColor.DARK_GRAY + " - " + ChatColor.RED + "Report an issue: " + ChatColor.GRAY + "https://github.com/LMBishop/Quests/issues"); + sender.sendMessage(ChatColor.DARK_GRAY + " - " + ChatColor.RED + "Wiki: " + ChatColor.GRAY + "https://github.com/LMBishop/Quests/wiki"); + sender.sendMessage(ChatColor.DARK_GRAY + " - " + ChatColor.RED + "Licensed under the GPLv3"); + sender.sendMessage(ChatColor.GRAY + "Many contributors have written source code and task types for Quests," + + " please see the GitHub link for an up-to-date list of contributors."); + return true; + } + } else if (args.length == 3) { + if (args[1].equalsIgnoreCase("opengui")) { + showAdminHelp(sender, "opengui"); + return true; + } else if (args[1].equalsIgnoreCase("moddata")) { + showAdminHelp(sender, "moddata"); + return true; + } else if (args[1].equalsIgnoreCase("types")) { + TaskType taskType = null; + for (TaskType task : plugin.getTaskTypeManager().getTaskTypes()) { + if (task.getType().equals(args[2])) { + taskType = task; + } + } + if (taskType == null) { + sender.sendMessage(Messages.COMMAND_TASKVIEW_ADMIN_FAIL.getMessage().replace("{task}", args[2])); + } else { + sender.sendMessage(ChatColor.RED + "Task type: " + ChatColor.GRAY + taskType.getType()); + sender.sendMessage(ChatColor.RED + "Author: " + ChatColor.GRAY + taskType.getAuthor()); + sender.sendMessage(ChatColor.RED + "Description: " + ChatColor.GRAY + taskType.getDescription()); + } + return true; + } else if (args[1].equalsIgnoreCase("info")) { + Quest quest = plugin.getQuestManager().getQuestById(args[2]); + if (quest == null) { + sender.sendMessage(Messages.COMMAND_QUEST_GENERAL_DOESNTEXIST.getMessage().replace("{quest}", args[2])); + } else { + sender.sendMessage(ChatColor.RED.toString() + ChatColor.BOLD + "Information for quest '" + quest.getId() + "'"); + sender.sendMessage(ChatColor.RED.toString() + ChatColor.UNDERLINE + "Task configurations (" + quest.getTasks().size() + ")"); + for (Task task : quest.getTasks()) { + sender.sendMessage(ChatColor.RED + "Task '" + task.getId() + "':"); + for (Map.Entry config : task.getConfigValues().entrySet()) { + sender.sendMessage(ChatColor.DARK_GRAY + " | " + ChatColor.GRAY + config.getKey() + ": " + ChatColor.GRAY + ChatColor.ITALIC + config.getValue()); + } + } + sender.sendMessage(ChatColor.RED.toString() + ChatColor.UNDERLINE + "Start string"); + for (String s : quest.getStartString()) { + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.GRAY + s); + } + sender.sendMessage(ChatColor.RED.toString() + ChatColor.UNDERLINE + "Reward string"); + for (String s : quest.getRewardString()) { + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.GRAY + s); + } + sender.sendMessage(ChatColor.RED.toString() + ChatColor.UNDERLINE + "Rewards"); + for (String s : quest.getRewards()) { + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.GRAY + s); + } + sender.sendMessage(ChatColor.RED.toString() + ChatColor.UNDERLINE + "Quest options"); + sender.sendMessage(ChatColor.RED + "Category: " + ChatColor.GRAY + quest.getCategoryId()); + sender.sendMessage(ChatColor.RED + "Repeatable: " + ChatColor.GRAY + quest.isRepeatable()); + sender.sendMessage(ChatColor.RED + "Requirements: " + ChatColor.GRAY + String.join(", ", quest.getRequirements())); + sender.sendMessage(ChatColor.RED + "Cooldown enabled: " + ChatColor.GRAY + quest.isCooldownEnabled()); + sender.sendMessage(ChatColor.RED + "Cooldown time: " + ChatColor.GRAY + quest.getCooldown()); + } + return true; + } + } else if (args.length == 4) { + if (args[1].equalsIgnoreCase("opengui")) { + if (args[2].equalsIgnoreCase("q") || args[2].equalsIgnoreCase("resources/bukkit/quests")) { + Player player = Bukkit.getPlayer(args[3]); + if (player != null) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer != null) { + plugin.getMenuController().openMainMenu(qPlayer); + sender.sendMessage(Messages.COMMAND_QUEST_OPENQUESTS_ADMIN_SUCCESS.getMessage().replace("{player}", player.getName())); + return true; + } + } + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_PLAYERNOTFOUND.getMessage().replace("{player}", args[3])); + return true; + } + showAdminHelp(sender, "opengui"); + return true; + } else if (args[1].equalsIgnoreCase("moddata")) { + QPlayer qPlayer = getOtherPlayer(sender, args[3]); + if (qPlayer == null) return true; + if (args[2].equalsIgnoreCase("fullreset")) { + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + questProgressFile.clear(); + plugin.getPlayerManager().savePlayerSync(qPlayer.getPlayerUUID(), questProgressFile); + if (Bukkit.getPlayer(qPlayer.getPlayerUUID()) == null) { + plugin.getPlayerManager().dropPlayer(qPlayer.getPlayerUUID()); + } + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_FULLRESET.getMessage().replace("{player}", args[3])); + return true; + } + showAdminHelp(sender, "moddata"); + return true; + } + } else if (args.length == 5) { + if (args[1].equalsIgnoreCase("opengui")) { + if (args[2].equalsIgnoreCase("c") || args[2].equalsIgnoreCase("category")) { + if (!plugin.getQuestsConfig().getBoolean("options.categories-enabled")) { + sender.sendMessage(Messages.COMMAND_CATEGORY_OPEN_DISABLED.getMessage()); + return true; + } + Category category = plugin.getQuestManager().getCategoryById(args[4]); + if (category == null) { + sender.sendMessage(Messages.COMMAND_CATEGORY_OPEN_DOESNTEXIST.getMessage().replace("{category}", args[4])); + return true; + } + Player player = Bukkit.getPlayer(args[3]); + if (player != null) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer != null) { + if (plugin.getMenuController().openQuestCategory(qPlayer, category, null, false) == 0) { + sender.sendMessage(Messages.COMMAND_QUEST_OPENCATEGORY_ADMIN_SUCCESS.getMessage().replace("{player}", player.getName()) + .replace("{category}", category.getId())); + } else { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_CATEGORY_PERMISSION.getMessage().replace("{player}", player.getName()) + .replace("{category}", category.getId())); + } + return true; + } + } + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_PLAYERNOTFOUND.getMessage().replace("{player}", args[3])); + return true; + } + } else if (args[1].equalsIgnoreCase("moddata")) { + boolean success = false; + QPlayer qPlayer = getOtherPlayer(sender, args[3]); + if (qPlayer == null) return true; + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + Quest quest = plugin.getQuestManager().getQuestById(args[4]); + if (quest == null) { + sender.sendMessage(Messages.COMMAND_QUEST_START_DOESNTEXIST.getMessage().replace("{quest}", args[4])); + //success = true; + return true; + } + if (args[2].equalsIgnoreCase("reset")) { + questProgressFile.generateBlankQuestProgress(quest); + plugin.getPlayerManager().savePlayerSync(qPlayer.getPlayerUUID(), questProgressFile); + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_RESET_SUCCESS.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId())); + success = true; + } else if (args[2].equalsIgnoreCase("start")) { + QuestStartResult response = qPlayer.startQuest(quest); + if (response == QuestStartResult.QUEST_LIMIT_REACHED) { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILLIMIT.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId())); + return true; + } else if (response == QuestStartResult.QUEST_ALREADY_COMPLETED) { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILCOMPLETE.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId())); + return true; + } else if (response == QuestStartResult.QUEST_COOLDOWN) { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILCOOLDOWN.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId())); + return true; + } else if (response == QuestStartResult.QUEST_LOCKED) { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILLOCKED.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId())); + return true; + } else if (response == QuestStartResult.QUEST_ALREADY_STARTED) { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILSTARTED.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId())); + return true; + } else if (response == QuestStartResult.QUEST_NO_PERMISSION) { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILPERMISSION.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId())); + return true; + } else if (response == QuestStartResult.NO_PERMISSION_FOR_CATEGORY) { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILCATEGORYPERMISSION.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId())); + return true; + } + plugin.getPlayerManager().savePlayerSync(qPlayer.getPlayerUUID(), questProgressFile); + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_SUCCESS.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId())); + success = true; + } else if (args[2].equalsIgnoreCase("complete")) { + qPlayer.completeQuest(quest); + plugin.getPlayerManager().savePlayerSync(qPlayer.getPlayerUUID(), questProgressFile); + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_COMPLETE_SUCCESS.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId())); + success = true; + } + if (!success) { + showAdminHelp(sender, "moddata"); + } + if (Bukkit.getPlayer(qPlayer.getPlayerUUID()) == null) { + plugin.getPlayerManager().dropPlayer(qPlayer.getPlayerUUID()); + } + return true; + } + } + showAdminHelp(sender, null); + return true; + } + if (sender instanceof Player && (args[0].equalsIgnoreCase("q") || args[0].equalsIgnoreCase("resources/bukkit/quests") || args[0].equalsIgnoreCase("quest"))) { + Player player = (Player) sender; + if (args.length >= 3) { + Quest quest = plugin.getQuestManager().getQuestById(args[1]); + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + player.sendMessage(Messages.COMMAND_DATA_NOT_LOADED.getMessage()); + return true; + } + if (quest == null) { + sender.sendMessage(Messages.COMMAND_QUEST_GENERAL_DOESNTEXIST.getMessage().replace("{quest}", args[1])); + } + if (args[2].equalsIgnoreCase("s") || args[2].equalsIgnoreCase("start")) { + qPlayer.startQuest(quest); + } else if (args[2].equalsIgnoreCase("c") || args[2].equalsIgnoreCase("cancel")) { + qPlayer.cancelQuest(quest); + } else if (args[2].equalsIgnoreCase("t") || args[2].equalsIgnoreCase("track")) { + qPlayer.trackQuest(quest); + } else { + sender.sendMessage(Messages.COMMAND_SUB_DOESNTEXIST.getMessage().replace("{sub}", args[2])); + } + return true; + } + } else if (sender instanceof Player && (args[0].equalsIgnoreCase("c") || args[0].equalsIgnoreCase("category"))) { + if (!plugin.getQuestsConfig().getBoolean("options.categories-enabled")) { + sender.sendMessage(Messages.COMMAND_CATEGORY_OPEN_DISABLED.getMessage()); + return true; + } + Player player = (Player) sender; + if (args.length >= 2) { + Category category = plugin.getQuestManager().getCategoryById(args[1]); + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + player.sendMessage(Messages.COMMAND_DATA_NOT_LOADED.getMessage()); + return true; + } + if (category == null) { + sender.sendMessage(Messages.COMMAND_CATEGORY_OPEN_DOESNTEXIST.getMessage().replace("{category}", args[1])); + } else { + plugin.getMenuController().openQuestCategory(qPlayer, category, null, false); + return true; + } + return true; + } + } else if (sender instanceof Player && (args[0].equalsIgnoreCase("random")) && sender.hasPermission("quests.command.random")) { + Player player = (Player) sender; + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + player.sendMessage(Messages.COMMAND_DATA_NOT_LOADED.getMessage()); + return true; + } + List validQuests = new ArrayList<>(); + for (Quest quest : plugin.getQuestManager().getQuests().values()) { + if (qPlayer.canStartQuest(quest) == QuestStartResult.QUEST_SUCCESS) { + validQuests.add(quest); + } + } + + if (validQuests.isEmpty()) { + player.sendMessage(Messages.QUEST_RANDOM_NONE.getMessage()); + return true; + } + int random = ThreadLocalRandom.current().nextInt(0, validQuests.size()); + qPlayer.startQuest(validQuests.get(random)); + return true; + } else if (sender instanceof Player && (args[0].equalsIgnoreCase("started"))) { + Player player = (Player) sender; + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + player.sendMessage(Messages.COMMAND_DATA_NOT_LOADED.getMessage()); + return true; + } + plugin.getMenuController().openStartedQuests(qPlayer); + return true; + } + showHelp(sender); + } else { + sender.sendMessage(ChatColor.RED + "Only admin commands are available to non-player senders."); + } + return true; + } + + private QPlayer getOtherPlayer(CommandSender sender, String name) { + OfflinePlayer ofp = Bukkit.getOfflinePlayer(name); + UUID uuid; + String username; + if (ofp.hasPlayedBefore()) { + uuid = ofp.getUniqueId(); + username = ofp.getName(); + } else { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_PLAYERNOTFOUND.getMessage().replace("{player}", name)); + return null; + } + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(uuid); + if (qPlayer == null) { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_LOADDATA.getMessage().replace("{player}", username)); + plugin.getPlayerManager().loadPlayer(uuid); + qPlayer = plugin.getPlayerManager().getPlayer(uuid); + } + if (qPlayer == null) { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_NODATA.getMessage().replace("{player}", username)); + return null; + } + return qPlayer; + } + + private void showProblems(CommandSender sender) { + if (!plugin.getConfigProblems().isEmpty()) { +// sender.sendMessage(ChatColor.DARK_GRAY.toString() + "----"); + sender.sendMessage(ChatColor.GRAY + "Detected problems and potential issues:"); + Set problemTypes = new HashSet<>(); + int count = 0; + for (Map.Entry> entry : plugin.getConfigProblems().entrySet()) { + HashMap> sortedProblems = new HashMap<>(); + for (ConfigProblem problem : entry.getValue()) { + if (sortedProblems.containsKey(problem.getType())) { + sortedProblems.get(problem.getType()).add(problem); + } else { + List specificProblems = new ArrayList<>(); + specificProblems.add(problem); + sortedProblems.put(problem.getType(), specificProblems); + } + problemTypes.add(problem.getType()); + } + ConfigProblem.ConfigProblemType highest = null; + for (ConfigProblem.ConfigProblemType type : ConfigProblem.ConfigProblemType.values()) { + if (sortedProblems.containsKey(type)) { + highest = type; + break; + } + } + ChatColor highestColor = ChatColor.WHITE; + if (highest != null) { + highestColor = Chat.matchConfigProblemToColor(highest); + } + sender.sendMessage(highestColor + entry.getKey() + ChatColor.DARK_GRAY + " ----"); + for (ConfigProblem.ConfigProblemType type : ConfigProblem.ConfigProblemType.values()) { + if (sortedProblems.containsKey(type)) { + for (ConfigProblem problem : sortedProblems.get(type)) { + sender.sendMessage(ChatColor.DARK_GRAY + " | - " + Chat.matchConfigProblemToColor(problem.getType()) + + problem.getType().getShortened() + ChatColor.DARK_GRAY + ": " + + ChatColor.GRAY + problem.getDescription() + ChatColor.DARK_GRAY + " :" + problem.getLocation()); + count++; + } + } + } + } +// sender.sendMessage(ChatColor.DARK_GRAY.toString() + "----"); + List legend = new ArrayList<>(); + for (ConfigProblem.ConfigProblemType type : ConfigProblem.ConfigProblemType.values()) { + if (problemTypes.contains(type)) { + legend.add(Chat.matchConfigProblemToColor(type) + type.getShortened() + ChatColor.DARK_GRAY + " = " + Chat.matchConfigProblemToColor(type) + type.getTitle()); + } + } + sender.sendMessage(ChatColor.DARK_GRAY.toString() + "----"); + + sender.sendMessage(ChatColor.GRAY.toString() + count + " problem(s) | " + String.join(ChatColor.DARK_GRAY + ", ", legend)); + } else { + sender.sendMessage(ChatColor.GRAY + "Quests did not detect any problems with your configuration."); + } + } + + private void showHelp(CommandSender sender) { + sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "------------=[" + ChatColor.RED + " Quests v" + plugin + .getDescription().getVersion() + " " + ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "]=------------"); + sender.sendMessage(ChatColor.GRAY + "The following commands are available: "); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/resources/bukkit/quests " + ChatColor.DARK_GRAY + ": show quests"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests c/category " + ChatColor.DARK_GRAY + ": open category by ID"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests q/quest " + ChatColor.DARK_GRAY + ": start, cancel or track quest by ID"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a/admin " + ChatColor.DARK_GRAY + ": view help for admins"); + sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "--------=[" + ChatColor.RED + " made with <3 by LMBishop " + ChatColor + .GRAY.toString() + ChatColor.STRIKETHROUGH + "]=--------"); + } + + private void showAdminHelp(CommandSender sender, String command) { + if (command != null && command.equalsIgnoreCase("opengui")) { + sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "------------=[" + ChatColor.RED + " Quests Admin: opengui " + ChatColor + .GRAY.toString() + ChatColor.STRIKETHROUGH + "]=------------"); + sender.sendMessage(ChatColor.GRAY + "The following commands are available: "); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a opengui q/quests " + ChatColor.DARK_GRAY + ": forcefully show" + + " quests for player"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a opengui c/category " + ChatColor.DARK_GRAY + ": " + + "forcefully " + + "open category by ID for player"); + sender.sendMessage(ChatColor.GRAY + "These commands are useful for command NPCs. These will bypass the usual quests.command permission."); + } else if (command != null && command.equalsIgnoreCase("moddata")) { + sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "------------=[" + ChatColor.RED + " Quests Admin: moddata " + ChatColor + .GRAY.toString() + ChatColor.STRIKETHROUGH + "]=------------"); + sender.sendMessage(ChatColor.GRAY + "The following commands are available: "); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata fullreset " + ChatColor.DARK_GRAY + ": clear a " + + "players quest data file"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata reset " + ChatColor.DARK_GRAY + ": clear a " + + "players data for specifc quest"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata start " + ChatColor.DARK_GRAY + ": start a " + + "quest for a player"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata complete " + ChatColor.DARK_GRAY + ": " + + "complete a quest for a player"); + sender.sendMessage(ChatColor.GRAY + "These commands modify quest progress for players. Use them cautiously. Changes are irreversible."); + } else { + sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "------------=[" + ChatColor.RED + " Quests Admin " + ChatColor.GRAY + .toString() + ChatColor.STRIKETHROUGH + "]=------------"); + sender.sendMessage(ChatColor.GRAY + "The following commands are available: "); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a opengui " + ChatColor.DARK_GRAY + ": view help for opengui"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata " + ChatColor.DARK_GRAY + ": view help for quest progression"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a types [type]" + ChatColor.DARK_GRAY + ": view registered task types"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a info [quest]" + ChatColor.DARK_GRAY + ": see information about loaded quests"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a reload " + ChatColor.DARK_GRAY + ": reload Quests configuration"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a config " + ChatColor.DARK_GRAY + ": see detected problems in config"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a itemstack " + ChatColor.DARK_GRAY + ": print information about the current held ItemStack"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a update " + ChatColor.DARK_GRAY + ": check for updates"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a wiki " + ChatColor.DARK_GRAY + ": get a link to the Quests wiki"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a about " + ChatColor.DARK_GRAY + ": get information about Quests"); + } + sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "-----=[" + ChatColor.RED + " requires permission: quests.admin " + + ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "]=-----"); + } + + private List matchTabComplete(String arg, List options) { + List completions = new ArrayList<>(); + StringUtil.copyPartialMatches(arg, options, completions); + Collections.sort(completions); + return completions; + } + + private List tabCompleteCategory(String arg) { + List options = new ArrayList<>(); + for (Category c : plugin.getQuestManager().getCategories()) { + options.add(c.getId()); + } + return matchTabComplete(arg, options); + } + + private List tabCompleteQuests(String arg) { + List options = new ArrayList<>(plugin.getQuestManager().getQuests().keySet()); + return matchTabComplete(arg, options); + } + + @Nullable + @Override + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { + if (!plugin.getQuestsConfig().getBoolean("options.tab-completion.enabled")) { + return null; + } + if (sender instanceof Player) { + if (args.length == 1) { + List options = new ArrayList<>(Arrays.asList("quest", "category", "started")); + if (sender.hasPermission("quests.admin")) { + options.add("admin"); + } + if (sender.hasPermission("quests.command.random")) { + options.add("random"); + } + return matchTabComplete(args[0], options); + } else if (args.length == 2) { + if (args[0].equalsIgnoreCase("c") || args[0].equalsIgnoreCase("category")) { + return tabCompleteCategory(args[1]); + } else if (args[0].equalsIgnoreCase("q") || args[0].equalsIgnoreCase("quest")) { + return tabCompleteQuests(args[1]); + } else if (args[0].equalsIgnoreCase("a") || args[0].equalsIgnoreCase("admin") + && sender.hasPermission("quests.admin")) { + List options = Arrays.asList("opengui", "moddata", "types", "reload", "update", "config", "info", "wiki", "about"); + return matchTabComplete(args[1], options); + } + } else if (args.length == 3) { + if (args[0].equalsIgnoreCase("q") || args[0].equalsIgnoreCase("quest") + && sender.hasPermission("quests.admin")) { + Quest q = plugin.getQuestManager().getQuestById(args[1]); + if (q != null) { + List options = Arrays.asList("start", "cancel", "track"); + return matchTabComplete(args[2], options); + } + } else if (args[0].equalsIgnoreCase("a") || args[0].equalsIgnoreCase("admin") + && sender.hasPermission("quests.admin")) { + if (args[1].equalsIgnoreCase("types")) { + List options = new ArrayList<>(); + for (TaskType taskType : plugin.getTaskTypeManager().getTaskTypes()) { + options.add(taskType.getType()); + } + return matchTabComplete(args[2], options); + } else if (args[1].equalsIgnoreCase("opengui")) { + List options = Arrays.asList("resources/bukkit/quests", "category"); + return matchTabComplete(args[2], options); + } else if (args[1].equalsIgnoreCase("moddata")) { + List options = Arrays.asList("fullreset", "reset", "start", "complete"); + return matchTabComplete(args[2], options); + } else if (args[1].equalsIgnoreCase("info")) { + return tabCompleteQuests(args[2]); + } + } + } else if (args.length == 4) { + if (sender.hasPermission("quests.admin")) return null; + } else if (args.length == 5) { + if (args[0].equalsIgnoreCase("a") || args[0].equalsIgnoreCase("admin") + && sender.hasPermission("quests.admin")) { + if (args[1].equalsIgnoreCase("opengui")) { + if (args[2].equalsIgnoreCase("c") || args[2].equalsIgnoreCase("category")) { + return tabCompleteCategory(args[4]); + } + } else if (args[1].equalsIgnoreCase("moddata")) { + if (args[2].equalsIgnoreCase("start") + || args[2].equalsIgnoreCase("complete") + || args[2].equalsIgnoreCase("reset")) { + return tabCompleteQuests(args[4]); + } + } + } + } + } + return Collections.emptyList(); + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/config/BukkitQuestsConfig.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/config/BukkitQuestsConfig.java new file mode 100644 index 00000000..add7c33e --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/config/BukkitQuestsConfig.java @@ -0,0 +1,91 @@ +package com.leonardobishop.quests.bukkit.config; + +import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetter; +import com.leonardobishop.quests.common.config.QuestsConfig; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class BukkitQuestsConfig implements QuestsConfig { + + private final Map cachedItemStacks = new HashMap<>(); + // this is faster than just relying on the YamlConfiguration to cache it for some reason + private final Map cachedBooleans = new HashMap<>(); + private YamlConfiguration config; + private File file; + private ItemGetter itemGetter; + + public BukkitQuestsConfig(File file) { + this.file = file; + } + + public void setItemGetter(ItemGetter itemGetter) { + this.itemGetter = itemGetter; + } + + @Override + public boolean loadConfig() { + this.cachedBooleans.clear(); + this.cachedItemStacks.clear(); + try { + config = YamlConfiguration.loadConfiguration(file); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public YamlConfiguration getConfig() { + return config; + } + + @Override + public String getString(String path) { + return config.getString(path); + } + + @Override + public String getString(String path, String def) { + return config.getString(path, def); + } + + @Override + public boolean getBoolean(String path) { + return config.getBoolean(path); + } + + @Override + public boolean getBoolean(String path, boolean def) { + return config.getBoolean(path, def); + } + + @Override + public int getInt(String path) { + return config.getInt(path); + } + + @Override + public int getInt(String path, int def) { + return config.getInt(path, def); + } + + @Override + public List getStringList(String path) { + return config.getStringList(path); + } + + @Override + public List getStringList(String path, List def) { + List list = config.getStringList(path); + return list.isEmpty() ? def : list; + } + + public ItemStack getItem(String path) { + return new ItemStack(cachedItemStacks.computeIfAbsent(path, s -> itemGetter.getItem(path, config))); + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/config/BukkitQuestsLoader.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/config/BukkitQuestsLoader.java new file mode 100644 index 00000000..f80ec3f0 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/config/BukkitQuestsLoader.java @@ -0,0 +1,331 @@ +package com.leonardobishop.quests.bukkit.config; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetter; +import com.leonardobishop.quests.bukkit.menu.itemstack.QItemStack; +import com.leonardobishop.quests.bukkit.menu.itemstack.QItemStackRegistry; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.config.ConfigProblemDescriptions; +import com.leonardobishop.quests.common.config.QuestsLoader; +import com.leonardobishop.quests.common.logger.QuestsLogger; +import com.leonardobishop.quests.common.quest.Category; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.QuestManager; +import com.leonardobishop.quests.common.quest.Task; +import com.leonardobishop.quests.common.questcontroller.QuestController; +import com.leonardobishop.quests.common.tasktype.TaskType; +import com.leonardobishop.quests.common.tasktype.TaskTypeManager; +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.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 BukkitQuestsLoader implements QuestsLoader { + + private final BukkitQuestsPlugin plugin; + private final BukkitQuestsConfig questsConfig; + private final QuestManager questManager; + private final TaskTypeManager taskTypeManager; + private final QuestController questController; + private final QuestsLogger questsLogger; + private final QItemStackRegistry qItemStackRegistry; + + public BukkitQuestsLoader(BukkitQuestsPlugin plugin) { + this.plugin = plugin; + this.questsConfig = (BukkitQuestsConfig) plugin.getQuestsConfig(); + this.questManager = plugin.getQuestManager(); + this.taskTypeManager = plugin.getTaskTypeManager(); + this.questController = plugin.getQuestController(); + this.questsLogger = plugin.getQuestsLogger(); + this.qItemStackRegistry = plugin.getQItemStackRegistry(); + } + + @Override + public Map> loadQuests(File root) { + qItemStackRegistry.clearRegistry(); + questManager.getQuests().clear(); + questManager.getCategories().clear(); + taskTypeManager.resetTaskTypes(); + + Map> configProblems = new HashMap<>(); + HashMap pathToQuest = new HashMap<>(); + HashMap> globalTaskConfig = new HashMap<>(); + + if (questsConfig.getConfig().isConfigurationSection("global-task-configuration.types")) { + for (String type : questsConfig.getConfig().getConfigurationSection("global-task-configuration.types").getKeys(false)) { + HashMap configValues = new HashMap<>(); + for (String key : questsConfig.getConfig().getConfigurationSection("global-task-configuration.types." + type).getKeys(false)) { + configValues.put(key, questsConfig.getConfig().get("global-task-configuration.types." + type + "." + key)); + } + globalTaskConfig.putIfAbsent(type, configValues); + } + } + + 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, permissionRequired); + questManager.registerCategory(category); + qItemStackRegistry.register(category, displayItem); + } + + FileVisitor fileVisitor = new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attributes) { + try { + File questFile = new File(path.toUri()); + URI relativeLocation = root.toURI().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) { + configProblems.put(relativeLocation.getPath(), Collections.singletonList(new ConfigProblem(ConfigProblem.ConfigProblemType.ERROR, ConfigProblemDescriptions.MALFORMED_YAML.getDescription()))); + return FileVisitResult.CONTINUE; + } + + String id = questFile.getName().replace(".yml", ""); + + List problems = new ArrayList<>(); + + if (!StringUtils.isAlphanumeric(id)) { + problems.add(new ConfigProblem(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")) { + problems.add(new ConfigProblem(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)) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, ConfigProblemDescriptions.TASK_MALFORMED_NOT_SECTION.getDescription(taskId), taskRoot)); + continue; + } + + if (taskType == null) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, ConfigProblemDescriptions.NO_TASK_TYPE.getDescription(), taskRoot)); + continue; + } + + // check the tasks + TaskType t = taskTypeManager.getTaskType(taskType); + if (t != null) { + HashMap configValues = new HashMap<>(); + for (String key : config.getConfigurationSection(taskRoot).getKeys(false)) { + configValues.put(key, config.get(taskRoot + "." + key)); + } + + problems.addAll(t.validateConfig(taskRoot, configValues)); + } else { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, ConfigProblemDescriptions.UNKNOWN_TASK_TYPE.getDescription(taskType), taskRoot)); + isValid = false; + } + + if (isValid) { + validTasks++; + } + } + if (validTasks == 0) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.ERROR, ConfigProblemDescriptions.NO_TASKS.getDescription(), "tasks")); + } + } + + boolean error = false; + for (ConfigProblem problem : problems) { + if (problem.getType() == ConfigProblem.ConfigProblemType.ERROR) { + error = true; + break; + } + } + + // END OF THE CHECKING + if (!error && !questsConfig.getBoolean("options.error-checking.override-errors", 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 (questController.getName().equals("daily")) { + repeatable = true; + cooldown = true; + cooldownTime = 0; + requirements = Collections.emptyList(); + permissionRequired = false; + } + + Quest quest; + if (category.equals("")) { + quest = new Quest(id, rewards, requirements, repeatable, cooldown, cooldownTime, permissionRequired, rewardString, startString, placeholders, sortOrder); + } else { + quest = new Quest(id, rewards, requirements, repeatable, cooldown, cooldownTime, permissionRequired, rewardString, startString, placeholders, category, sortOrder); + Category c = questManager.getCategoryById(category); + if (c != null) { + c.registerQuestId(id); + } else { + problems.add(new ConfigProblem(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 (questsConfig.getBoolean("options.global-task-configuration-override") && task.getConfigValue(entry.getKey()) != null) + continue; + task.addConfigValue(entry.getKey(), entry.getValue()); + } + } + + quest.registerTask(task); + } + + + for (String line : displayItem.getLoreNormal()) { + findInvalidTaskReferences(quest, line, problems, "display.lore-normal"); + } + for (String line : displayItem.getLoreStarted()) { + findInvalidTaskReferences(quest, line, problems, "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), problems, "placeholders." + p); + } + } + if (questsConfig.getBoolean("options.show-quest-registrations")) { + questsLogger.info("Registering quest " + quest.getId() + " with " + quest.getTasks().size() + " tasks."); + } + questManager.registerQuest(quest); + taskTypeManager.registerQuestTasksWithTaskTypes(quest); + qItemStackRegistry.register(quest, displayItem); + pathToQuest.put(relativeLocation.getPath(), quest); + } + if (!problems.isEmpty()) { + configProblems.put(relativeLocation.getPath(), problems); + } + } catch (Exception e) { + questsLogger.severe("An exception occurred when attempting to load quest '" + path + "' (will be ignored)"); + e.printStackTrace(); + } + return FileVisitResult.CONTINUE; + } + }; + + try { + Files.walkFileTree(root.toPath(), fileVisitor); + } catch (IOException e) { + e.printStackTrace(); + } + + // post-load checks + for (Map.Entry loadedQuest : pathToQuest.entrySet()) { + List problems = new ArrayList<>(); + for (String req : loadedQuest.getValue().getRequirements()) { + if (questManager.getQuestById(req) == null) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, ConfigProblemDescriptions.UNKNOWN_REQUIREMENT.getDescription(req), "options.requires")); + } + } + + if (!problems.isEmpty()) { + if (configProblems.containsKey(loadedQuest.getKey())) { + configProblems.get(loadedQuest.getKey()).addAll(problems); + } else { + configProblems.put(loadedQuest.getKey(), problems); + } + } + } + + return configProblems; + } + + 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(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; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/coreprotect/AbstractCoreProtectHook.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/coreprotect/AbstractCoreProtectHook.java new file mode 100644 index 00000000..75f96ecd --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/coreprotect/AbstractCoreProtectHook.java @@ -0,0 +1,16 @@ +package com.leonardobishop.quests.bukkit.hook.coreprotect; + +import org.bukkit.block.Block; + +public interface AbstractCoreProtectHook { + + /** + * Check whether or not the most recent edit to a block was the result of a player. + * + * @param block the block + * @param time the time to look back in seconds + * @return true if from a player + */ + boolean checkBlock(Block block, int time); + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/coreprotect/CoreProtectHook.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/coreprotect/CoreProtectHook.java new file mode 100644 index 00000000..1dbfe3bd --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/coreprotect/CoreProtectHook.java @@ -0,0 +1,29 @@ +package com.leonardobishop.quests.bukkit.hook.coreprotect; + +import net.coreprotect.CoreProtect; +import net.coreprotect.CoreProtectAPI; +import org.bukkit.Bukkit; +import org.bukkit.block.Block; + +import java.util.List; + +public class CoreProtectHook implements AbstractCoreProtectHook { + + private final CoreProtectAPI api; + + public CoreProtectHook() { + api = ((CoreProtect) Bukkit.getPluginManager().getPlugin("CoreProtect")).getAPI(); + } + + @Override + public boolean checkBlock(Block block, int time) { + List lookup = api.blockLookup(block, time); + if (lookup.isEmpty()) return false; + + String[] result = lookup.get(0); + CoreProtectAPI.ParseResult parseResult = api.parseResult(result); + + return !parseResult.getPlayer().isEmpty() && parseResult.getActionId() == 1; + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/coreprotect/CoreProtectNoHook.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/coreprotect/CoreProtectNoHook.java new file mode 100644 index 00000000..4fc0eae9 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/coreprotect/CoreProtectNoHook.java @@ -0,0 +1,10 @@ +package com.leonardobishop.quests.bukkit.hook.coreprotect; + +import org.bukkit.block.Block; + +public class CoreProtectNoHook implements AbstractCoreProtectHook { + @Override + public boolean checkBlock(Block block, int time) { + return false; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter.java new file mode 100644 index 00000000..efbd1a36 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter.java @@ -0,0 +1,46 @@ +package com.leonardobishop.quests.bukkit.hook.itemgetter; + +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.inventory.ItemStack; + +public interface ItemGetter { + + /** + * Gets an ItemStack from a configuration. + * Implementations should specific to the server version. + * + * @param path the path to where the item is defined in the config (null if item is defined in second param) + * @param config the configuration file + * @param excludes exclude certain fields in the configuration + * @return {@link ItemStack} + */ + ItemStack getItem(String path, ConfigurationSection config, Filter... excludes); + + /** + * Gets an ItemStack from a given string (which represents a material). + * For pre-1.13 server implementations, the string may use a data code. + * + * @param material the string + * @return {@link ItemStack} + */ + ItemStack getItemStack(String material); + + /** + * Validates a material from a string. + * For pre-1.13 server implementations, the string may use a data code. + * + * @param material the string + * @return true if it a material + */ + boolean isValidMaterial(String material); + + enum Filter { + DISPLAY_NAME, + LORE, + ENCHANTMENTS, + ITEM_FLAGS, + UNBREAKABLE, + ATTRIBUTE_MODIFIER, + CUSTOM_MODEL_DATA; + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetterLatest.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetterLatest.java new file mode 100644 index 00000000..4f87c2ac --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetterLatest.java @@ -0,0 +1,240 @@ +package com.leonardobishop.quests.bukkit.hook.itemgetter; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class ItemGetterLatest implements ItemGetter { + + /* + supporting: + - name + - material + - lore + - enchantments (NamespacedKey) + - itemflags + - unbreakable + - attribute modifier + - custom model data + + requires at least API version 1.14 + */ + @Override + public ItemStack getItem(String path, ConfigurationSection config, ItemGetter.Filter... excludes) { + if (path != null && !path.equals("")) { + path = path + "."; + } + List filters = Arrays.asList(excludes); + + String cName = config.getString(path + "name", path + "name"); + String cType = config.getString(path + "item", config.getString(path + "type", path + "item")); + boolean hasCustomModelData = config.contains(path + "custommodeldata"); + int customModelData = config.getInt(path + "custommodeldata", 0); + boolean unbreakable = config.getBoolean(path + "unbreakable", false); + List cLore = config.getStringList(path + "lore"); + List cItemFlags = config.getStringList(path + "itemflags"); + boolean hasAttributeModifiers = config.contains(path + "attributemodifiers"); + List> cAttributeModifiers = config.getMapList(path + "attributemodifiers"); + + String name; + Material type = null; + int data = 0; + + // material + ItemStack is = getItemStack(cType); + ItemMeta ism = is.getItemMeta(); + + // name + if (!filters.contains(Filter.DISPLAY_NAME)) { + name = ChatColor.translateAlternateColorCodes('&', cName); + ism.setDisplayName(name); + } + + // lore + if (!filters.contains(Filter.LORE)) { + List lore = new ArrayList<>(); + if (cLore != null) { + for (String s : cLore) { + lore.add(ChatColor.translateAlternateColorCodes('&', s)); + } + } + ism.setLore(lore); + } + + // attribute modifiers + if (!filters.contains(Filter.ATTRIBUTE_MODIFIER)) { + if (hasAttributeModifiers) { + for (Map attr : cAttributeModifiers) { + String cAttribute = (String) attr.get("attribute"); + Attribute attribute = null; + for (Attribute enumattr : Attribute.values()) { + if (enumattr.toString().equals(cAttribute)) { + attribute = enumattr; + break; + } + } + + if (attribute == null) continue; + + Map configurationSection = (Map) attr.get("modifier"); + + String cUUID = (String) configurationSection.get("uuid"); + String cModifierName = (String) configurationSection.get("name"); + String cModifierOperation = (String) configurationSection.get("operation"); + double cAmount; + try { + Object cAmountObj = configurationSection.get("amount"); + if (cAmountObj instanceof Integer) { + cAmount = ((Integer) cAmountObj).doubleValue(); + } else { + cAmount = (Double) cAmountObj; + } + } catch (Exception e) { + cAmount = 1; + } + String cEquipmentSlot = (String) configurationSection.get("equipmentslot"); + + UUID uuid = null; + if (cUUID != null) { + try { + uuid = UUID.fromString(cUUID); + } catch (Exception ignored) { + // ignored + } + } + EquipmentSlot equipmentSlot = null; + if (cEquipmentSlot != null) { + try { + equipmentSlot = EquipmentSlot.valueOf(cEquipmentSlot); + } catch (Exception ignored) { + // ignored + } + } + AttributeModifier.Operation operation = AttributeModifier.Operation.ADD_NUMBER; + try { + operation = AttributeModifier.Operation.valueOf(cModifierOperation); + } catch (Exception ignored) { + // ignored + } + + AttributeModifier modifier; + if (uuid == null) { + modifier = new AttributeModifier(cModifierName, cAmount, operation); + } else if (equipmentSlot == null) { + modifier = new AttributeModifier(uuid, cModifierName, cAmount, operation); + } else { + modifier = new AttributeModifier(uuid, cModifierName, cAmount, operation, equipmentSlot); + } + + ism.addAttributeModifier(attribute, modifier); + } + } + } + + // item flags + if (!filters.contains(Filter.ITEM_FLAGS)) { + if (config.isSet(path + "itemflags")) { + for (String flag : cItemFlags) { + for (ItemFlag iflag : ItemFlag.values()) { + if (iflag.toString().equals(flag)) { + ism.addItemFlags(iflag); + break; + } + } + } + } + } + + // custom model data + if (!filters.contains(Filter.CUSTOM_MODEL_DATA)) { + if (hasCustomModelData) { + ism.setCustomModelData(customModelData); + } + } + + // unbreakable + if (!filters.contains(Filter.UNBREAKABLE)) { + ism.setUnbreakable(unbreakable); + } + + // enchantments + if (!filters.contains(Filter.ENCHANTMENTS)) { + if (config.isSet(path + "enchantments")) { + for (String key : config.getStringList(path + "enchantments")) { + String[] split = key.split(":"); + if (split.length < 2) { + continue; + } + String namespace = split[0]; + String ench = split[1]; + String levelName; + if (split.length >= 3) { + levelName = split[2]; + } else { + levelName = "1"; + } + + // TODO i don't know how these namespaces work +// NamespacedKey namespacedKey; +// try { +// namespacedKey = new NamespacedKey(namespace, ench); +// } catch (Exception e) { +// plugin.getQuestsLogger().debug("Unrecognised namespace: " + namespace); +// e.printStackTrace(); +// continue; +// } + Enchantment enchantment; + if ((enchantment = Enchantment.getByName(ench)) == null) { + continue; + } + + int level; + try { + level = Integer.parseInt(levelName); + } catch (NumberFormatException e) { + level = 1; + } + + ism.addEnchant(enchantment, level, true); + } + } + } + + is.setItemMeta(ism); + return is; + } + + @Override + public ItemStack getItemStack(String material) { + Material type; + try { + type = Material.valueOf(material); + } catch (Exception e) { + type = Material.STONE; + } + return new ItemStack(type, 1); + } + + @Override + public boolean isValidMaterial(String material) { + try { + Material.valueOf(material); + return true; + } catch (IllegalArgumentException ex) { + return false; + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_1_13.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_1_13.java new file mode 100644 index 00000000..a645f810 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_1_13.java @@ -0,0 +1,229 @@ +package com.leonardobishop.quests.bukkit.hook.itemgetter; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class ItemGetter_1_13 implements ItemGetter { + /* + reads the following: + - name + - material + - lore + - enchantments (NamespacedKey) + - itemflags + - unbreakable + - attribute modifier + + requires at least API version 1.13 + */ + @Override + public ItemStack getItem(String path, ConfigurationSection config, ItemGetter.Filter... excludes) { + if (path != null && !path.equals("")) { + path = path + "."; + } + List filters = Arrays.asList(excludes); + + String cName = config.getString(path + "name", path + "name"); + String cType = config.getString(path + "item", config.getString(path + "type", path + "item")); + boolean unbreakable = config.getBoolean(path + "unbreakable", false); + List cLore = config.getStringList(path + "lore"); + List cItemFlags = config.getStringList(path + "itemflags"); + boolean hasAttributeModifiers = config.contains(path + "attributemodifiers"); + List> cAttributeModifiers = config.getMapList(path + "attributemodifiers"); + + String name; + Material type = null; + int data = 0; + + // material + ItemStack is = getItemStack(cType); + ItemMeta ism = is.getItemMeta(); + + // name + if (!filters.contains(Filter.DISPLAY_NAME)) { + name = ChatColor.translateAlternateColorCodes('&', cName); + ism.setDisplayName(name); + } + + // lore + if (!filters.contains(Filter.LORE)) { + List lore = new ArrayList<>(); + if (cLore != null) { + for (String s : cLore) { + lore.add(ChatColor.translateAlternateColorCodes('&', s)); + } + } + ism.setLore(lore); + } + + // attribute modifiers + if (!filters.contains(Filter.ATTRIBUTE_MODIFIER)) { + if (hasAttributeModifiers) { + for (Map attr : cAttributeModifiers) { + String cAttribute = (String) attr.get("attribute"); + Attribute attribute = null; + for (Attribute enumattr : Attribute.values()) { + if (enumattr.toString().equals(cAttribute)) { + attribute = enumattr; + break; + } + } + + if (attribute == null) continue; + + Map configurationSection = (Map) attr.get("modifier"); + + String cUUID = (String) configurationSection.get("uuid"); + String cModifierName = (String) configurationSection.get("name"); + String cModifierOperation = (String) configurationSection.get("operation"); + double cAmount; + try { + Object cAmountObj = configurationSection.get("amount"); + if (cAmountObj instanceof Integer) { + cAmount = ((Integer) cAmountObj).doubleValue(); + } else { + cAmount = (Double) cAmountObj; + } + } catch (Exception e) { + cAmount = 1; + } + String cEquipmentSlot = (String) configurationSection.get("equipmentslot"); + + UUID uuid = null; + if (cUUID != null) { + try { + uuid = UUID.fromString(cUUID); + } catch (Exception ignored) { + // ignored + } + } + EquipmentSlot equipmentSlot = null; + if (cEquipmentSlot != null) { + try { + equipmentSlot = EquipmentSlot.valueOf(cEquipmentSlot); + } catch (Exception ignored) { + // ignored + } + } + AttributeModifier.Operation operation = AttributeModifier.Operation.ADD_NUMBER; + try { + operation = AttributeModifier.Operation.valueOf(cModifierOperation); + } catch (Exception ignored) { + // ignored + } + + AttributeModifier modifier; + if (uuid == null) { + modifier = new AttributeModifier(cModifierName, cAmount, operation); + } else if (equipmentSlot == null) { + modifier = new AttributeModifier(uuid, cModifierName, cAmount, operation); + } else { + modifier = new AttributeModifier(uuid, cModifierName, cAmount, operation, equipmentSlot); + } + + ism.addAttributeModifier(attribute, modifier); + } + } + } + + // item flags + if (!filters.contains(Filter.ITEM_FLAGS)) { + if (config.isSet(path + "itemflags")) { + for (String flag : cItemFlags) { + for (ItemFlag iflag : ItemFlag.values()) { + if (iflag.toString().equals(flag)) { + ism.addItemFlags(iflag); + break; + } + } + } + } + } + + // unbreakable + if (!filters.contains(Filter.UNBREAKABLE)) { + ism.setUnbreakable(unbreakable); + } + + // enchantments + if (!filters.contains(Filter.ENCHANTMENTS)) { + if (config.isSet(path + "enchantments")) { + for (String key : config.getStringList(path + "enchantments")) { + String[] split = key.split(":"); + if (split.length < 2) { + continue; + } + String namespace = split[0]; + String ench = split[1]; + String levelName; + if (split.length >= 3) { + levelName = split[2]; + } else { + levelName = "1"; + } + + // TODO i don't know how these namespaces work +// NamespacedKey namespacedKey; +// try { +// namespacedKey = new NamespacedKey(namespace, ench); +// } catch (Exception e) { +// plugin.getQuestsLogger().debug("Unrecognised namespace: " + namespace); +// e.printStackTrace(); +// continue; +// } + Enchantment enchantment; + if ((enchantment = Enchantment.getByName(ench)) == null) { + continue; + } + + int level; + try { + level = Integer.parseInt(levelName); + } catch (NumberFormatException e) { + level = 1; + } + + is.addUnsafeEnchantment(enchantment, level); + } + } + } + + is.setItemMeta(ism); + return is; + } + + @Override + public ItemStack getItemStack(String material) { + Material type; + try { + type = Material.valueOf(material); + } catch (Exception e) { + type = Material.STONE; + } + return new ItemStack(type, 1); + } + + @Override + public boolean isValidMaterial(String material) { + try { + Material.valueOf(material); + return true; + } catch (IllegalArgumentException ex) { + return false; + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_Late_1_8.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_Late_1_8.java new file mode 100644 index 00000000..ea80deea --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_Late_1_8.java @@ -0,0 +1,158 @@ +package com.leonardobishop.quests.bukkit.hook.itemgetter; + +import org.apache.commons.lang.StringUtils; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +public class ItemGetter_Late_1_8 implements ItemGetter { + /* + reads the following: + - name + - material (+ DATA) + - lore + - enchantments (NOT NamespacedKey) + - itemflags + + requires at least API version 1.8 (?) + */ + @Override + public ItemStack getItem(String path, ConfigurationSection config, Filter... excludes) { + if (path != null && !path.equals("")) { + path = path + "."; + } + List filters = Arrays.asList(excludes); + + + String cName = config.getString(path + "name", path + "name"); + String cType = config.getString(path + "item", config.getString(path + "type", path + "item")); + List cLore = config.getStringList(path + "lore"); + List cItemFlags = config.getStringList(path + "itemflags"); + + String name; + Material type = null; + int data = 0; + + // material + ItemStack is = getItemStack(cType); + ItemMeta ism = is.getItemMeta(); + + // lore + if (!filters.contains(Filter.LORE)) { + List lore = new ArrayList<>(); + if (cLore != null) { + for (String s : cLore) { + lore.add(ChatColor.translateAlternateColorCodes('&', s)); + } + } + ism.setLore(lore); + } + + // name + if (!filters.contains(Filter.DISPLAY_NAME)) { + name = ChatColor.translateAlternateColorCodes('&', cName); + ism.setDisplayName(name); + } + + + // item flags + if (!filters.contains(Filter.ITEM_FLAGS)) { + if (config.isSet(path + "itemflags")) { + for (String flag : cItemFlags) { + for (ItemFlag iflag : ItemFlag.values()) { + if (iflag.toString().equals(flag)) { + ism.addItemFlags(iflag); + break; + } + } + } + } + } + + // enchantments + if (!filters.contains(Filter.ENCHANTMENTS)) { + if (config.isSet(path + "enchantments")) { + for (String key : config.getStringList(path + "enchantments")) { + String[] split = key.split(":"); + String ench = split[0]; + String levelName; + if (split.length >= 2) { + levelName = split[1]; + } else { + levelName = "1"; + } + + Enchantment enchantment; + if ((enchantment = Enchantment.getByName(ench)) == null) { + continue; + } + + int level; + try { + level = Integer.parseInt(levelName); + } catch (NumberFormatException e) { + level = 1; + } + + ism.addEnchant(enchantment, level, true); + } + } + } + + is.setItemMeta(ism); + return is; + } + + + @Override + public ItemStack getItemStack(String material) { + Material type = null; + int data = 0; + + if (Material.getMaterial(material) != null) { + type = Material.getMaterial(material); + } else if (material.contains(":")) { + String[] parts = material.split(Pattern.quote(":")); + if (parts.length > 1) { + if (Material.getMaterial(parts[0]) != null) { + type = Material.getMaterial(parts[0]); + } + if (StringUtils.isNumeric(parts[1])) { + data = Integer.parseInt(parts[1]); + } + } + } + + if (type == null) { + type = Material.STONE; + } + return new ItemStack(type, 1, (short) data); + } + + @Override + public boolean isValidMaterial(String material) { + Material type = null; + + if (Material.getMaterial(material) != null) { + type = Material.getMaterial(material); + } else if (material.contains(":")) { + String[] parts = material.split(Pattern.quote(":")); + if (parts.length > 1) { + if (Material.getMaterial(parts[0]) != null) { + type = Material.getMaterial(parts[0]); + } + } + } + + return !(type == null); + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/AbstractPlaceholderAPIHook.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/AbstractPlaceholderAPIHook.java new file mode 100644 index 00000000..144c2ecd --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/AbstractPlaceholderAPIHook.java @@ -0,0 +1,14 @@ +package com.leonardobishop.quests.bukkit.hook.papi; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import org.bukkit.entity.Player; + +public interface AbstractPlaceholderAPIHook { + + String replacePlaceholders(Player player, String text); + + void registerExpansion(BukkitQuestsPlugin plugin); + + void unregisterExpansion(); + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/PlaceholderAPIHook.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/PlaceholderAPIHook.java new file mode 100644 index 00000000..c9102127 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/PlaceholderAPIHook.java @@ -0,0 +1,27 @@ +package com.leonardobishop.quests.bukkit.hook.papi; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import me.clip.placeholderapi.PlaceholderAPI; +import org.bukkit.entity.Player; + +public class PlaceholderAPIHook implements AbstractPlaceholderAPIHook { + + private QuestsPlaceholders placeholder; + + public String replacePlaceholders(Player player, String text) { + return PlaceholderAPI.setPlaceholders(player, text); + } + + @Override + public void registerExpansion(BukkitQuestsPlugin plugin) { + placeholder = new QuestsPlaceholders(plugin); + placeholder.register(); + } + + @Override + public void unregisterExpansion() { + placeholder.unregister(); + } + + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/QuestsPlaceholders.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/QuestsPlaceholders.java new file mode 100644 index 00000000..7428d860 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/QuestsPlaceholders.java @@ -0,0 +1,346 @@ +package com.leonardobishop.quests.bukkit.hook.papi; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.menu.itemstack.QItemStack; +import com.leonardobishop.quests.bukkit.util.Chat; +import com.leonardobishop.quests.common.enums.QuestStartResult; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.common.quest.Category; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.util.Format; +import me.clip.placeholderapi.expansion.Cacheable; +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class QuestsPlaceholders extends PlaceholderExpansion implements Cacheable { + + private final BukkitQuestsPlugin plugin; + private final Map> cache = new HashMap<>(); + private final Map formats = new HashMap<>(); + + public QuestsPlaceholders(BukkitQuestsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void clear() { + cache.clear(); + formats.clear(); + } + + @Override + public String getIdentifier() { + return "resources/bukkit/quests"; + } + + @Override + public String getAuthor() { + return plugin.getDescription().getAuthors().toString(); + } + + @Override + public String getVersion() { + return plugin.getDescription().getVersion(); + } + + @Override + public boolean persist() { + return true; + } + + @Override + public String onPlaceholderRequest(Player p, String params) { + if (p == null || !p.isOnline()) return null; + if (cache.containsKey(p.getName()) && cache.get(p.getName()).containsKey(params)) + return cache.get(p.getName()).get(params); + + String[] args = params.split("_", 4); + if (args.length < 1) return "Invalid Placeholder"; + + final boolean save = args[args.length - 1].toLowerCase().equals("cache"); + if (save) args = Arrays.copyOf(args, args.length - 1); + + final QPlayer qPlayer = plugin.getPlayerManager().getPlayer(p.getUniqueId()); + if (qPlayer == null) return "Data not loaded"; + String split = args[args.length - 1]; + + String result = "null"; + if (!args[0].contains(":") && !args[0].equalsIgnoreCase("tracked")) { + if (args.length > 1 && split.equals(args[1])) split = ","; + + switch (args[0].toLowerCase()) { + case "all": + case "a": + final List listAll = new ArrayList<>(plugin.getQuestManager().getQuests().values()); + result = (args.length == 1 ? String.valueOf(listAll.size()) : parseList((List) listAll, args[1], split)); + break; + case "completed": + case "c": + final List listCompleted = qPlayer.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.COMPLETED); + result = (args.length == 1 ? String.valueOf(listCompleted.size()) : parseList(listCompleted, args[1], split)); + break; + case "completedbefore": + case "cb": + final List listCompletedB = qPlayer.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.COMPLETED_BEFORE); + result = (args.length == 1 ? String.valueOf(listCompletedB.size()) : parseList(listCompletedB, args[1], split)); + break; + case "started": + case "s": + final List listStarted = qPlayer.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.STARTED); + result = (args.length == 1 ? String.valueOf(listStarted.size()) : parseList(listStarted, args[1], split)); + break; + case "categories": + if (args.length == 1) { + result = String.valueOf(plugin.getQuestManager().getCategories().size()); + } else { + final List listCategories = new ArrayList<>(); + switch (args[1].toLowerCase()) { + case "list": + case "l": + plugin.getQuestManager().getCategories().forEach(c -> { + ItemStack itemStack = plugin.getQItemStackRegistry().getCategoryItemStack(c); + listCategories.add(Chat.strip(itemStack.getItemMeta().getDisplayName())); + }); + break; + case "listid": + case "lid": + plugin.getQuestManager().getCategories().forEach(c -> listCategories.add(c.getId())); + break; + default: + return args[0] + "_" + args[1] + " is not a valid placeholder"; + } + result = String.join(split, listCategories); + } + break; + default: + return args[0] + " is not a valid placeholder"; + } + } else { + final String[] key = args[0].split(":"); + switch (key[0].toLowerCase()) { + case "quest": + case "q": + case "tracked": + if (!key[0].equalsIgnoreCase("tracked") && key.length == 1) return "Please specify quest name"; + + final Quest quest; + if (!key[0].equalsIgnoreCase("tracked")) { + quest = plugin.getQuestManager().getQuestById(key[1]); + if (quest == null) return key[1] + " is not a quest"; + } else { + quest = plugin.getQuestManager().getQuestById(qPlayer.getPlayerPreferences().getTrackedQuestId()); + if (quest == null) { + if (args.length == 1) { + return "No tracked quest"; + } else { + return ""; + } + } + } + + if (args.length == 1) { + result = getQuestDisplayNameStripped(quest); + } else { + switch (args[1].toLowerCase()) { + case "started": + case "s": + result = (qPlayer.getQuestProgressFile().getQuestProgress(quest).isStarted() ? "true" : "false"); + break; + case "completed": + case "c": + result = (qPlayer.getQuestProgressFile().getQuestProgress(quest).isCompleted() ? "true" : "false"); + break; + case "completedbefore": + case "cb": + result = (qPlayer.getQuestProgressFile().getQuestProgress(quest).isCompletedBefore() ? "true" : "false"); + break; + case "completiondate": + case "cd": + if (qPlayer.getQuestProgressFile().getQuestProgress(quest).isCompleted()) { + result = parseDate(args, qPlayer.getQuestProgressFile().getQuestProgress(quest).getCompletionDate()); + } else { + result = "Never"; + } + break; + case "cooldown": + if (qPlayer.getQuestProgressFile().getQuestProgress(quest).isCompleted()) { + final String time = Format.formatTime(TimeUnit.SECONDS.convert(qPlayer.getQuestProgressFile().getCooldownFor(quest), TimeUnit.MILLISECONDS)); + if (!time.startsWith("-")) result = time; + } else { + result = "0"; + } + break; + case "canaccept": + result = (qPlayer.canStartQuest(quest) == QuestStartResult.QUEST_SUCCESS ? "true" : "false"); + break; + case "meetsrequirements": + result = (qPlayer.getQuestProgressFile().hasMetRequirements(quest) ? "true" : "false"); + break; + default: + if (!args[1].contains(":")) + return args[0] + "_" + args[1] + " is not a valid placeholder"; + + final String[] t = args[1].split(":"); + if (t[0].equalsIgnoreCase("task") || t[0].equalsIgnoreCase("t")) { + if (t.length == 1) return "Please specify task name"; + + if (args.length == 2) { + result = qPlayer.getQuestProgressFile().getQuestProgress(quest).getTaskProgress(t[1]).getTaskId(); + } else { + switch (args[2].toLowerCase()) { + case "progress": + case "p": + final Object progress = qPlayer.getQuestProgressFile().getQuestProgress(quest).getTaskProgress(t[1]).getProgress(); + result = (progress == null ? "0" : String.valueOf(progress)); + break; + case "completed": + case "c": + result = String.valueOf(qPlayer.getQuestProgressFile().getQuestProgress(quest).getTaskProgress(t[1]).isCompleted()); + break; + default: + return args[0] + "_" + args[1] + "_" + args[2] + " is not a valid placeholder"; + } + } + } else if (t[0].equalsIgnoreCase("placeholder") || t[0].equalsIgnoreCase("p")) { + if (t.length == 1) return "Please specify placeholder name"; + + String placeholder = quest.getPlaceholders().get(t[1]); + if (placeholder == null) { + return t[1] + " is not a valid placeholder within quest " + quest.getId(); + } + placeholder = QItemStack.processPlaceholders(Chat.color(placeholder), qPlayer.getQuestProgressFile().getQuestProgress(quest)); + return placeholder; + } else { + return args[0] + "_" + args[1] + " is not a valid placeholder"; + } + } + } + break; + case "category": + case "c": + if (!plugin.getQuestsConfig().getBoolean("options.categories-enabled")) return "Categories Disabled"; + if (key.length == 1) return "Please specify category name"; + + final Category category = plugin.getQuestManager().getCategoryById(key[1]); + if (category == null) return key[1] + " is not a category"; + + if (args.length == 1) { + ItemStack itemStack = plugin.getQItemStackRegistry().getCategoryItemStack(category); + result = Chat.strip(itemStack.getItemMeta().getDisplayName()); + } else { + if (args.length > 2 && split.equals(args[2])) split = ","; + switch (args[1].toLowerCase()) { + case "all": + case "a": + final List listAll = getCategoryQuests(qPlayer, category, QuestProgressFile.QuestsProgressFilter.ALL); + result = (args.length == 2 ? String.valueOf(listAll.size()) : parseList(listAll, args[2], split)); + break; + case "completed": + case "c": + final List listCompleted = getCategoryQuests(qPlayer, category, QuestProgressFile.QuestsProgressFilter.COMPLETED); + result = (args.length == 2 ? String.valueOf(listCompleted.size()) : parseList(listCompleted, args[2], split)); + break; + case "completedbefore": + case "cb": + final List listCompletedB = getCategoryQuests(qPlayer, category, QuestProgressFile.QuestsProgressFilter.COMPLETED_BEFORE); + result = (args.length == 2 ? String.valueOf(listCompletedB.size()) : parseList(listCompletedB, args[2], split)); + break; + case "started": + case "s": + final List listStarted = getCategoryQuests(qPlayer, category, QuestProgressFile.QuestsProgressFilter.STARTED); + result = (args.length == 2 ? String.valueOf(listStarted.size()) : parseList(listStarted, args[2], split)); + break; + default: + return args[0] + "_" + args[1] + " is not a valid placeholder"; + } + } + break; + default: + return args[0] + " is not a valid placeholder"; + } + } + return (save ? cache(p.getName(), params, result) : result); + } + + private String cache(String player, String params, String result) { + if (!cache.containsKey(player) || !cache.get(player).containsKey(params)) { + final Map map = new HashMap<>(); + map.put(params, result); + cache.put(player, map); + Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> cache.get(player).remove(params), plugin.getConfig().getInt("options.placeholder-cache-time", 10) * 20); + } + return result; + } + + private String parseDate(String[] args, Long date) { + final String format = (args[args.length - 1].equals(args[1]) ? "dd/MM/yyyy" : args[args.length - 1]); + SimpleDateFormat sdf; + if (formats.containsKey(format)) { + sdf = formats.get(format); + } else { + sdf = new SimpleDateFormat(format); + formats.put(format, sdf); + } + return sdf.format(date); + } + + private String parseList(List list, String type, String separator) { + final List quests = new ArrayList<>(); + switch (type.toLowerCase()) { + case "list": + case "l": + list.forEach(q -> quests.add(getQuestDisplayNameStripped(q))); + break; + case "listid": + case "lid": + list.forEach(q -> quests.add(q.getId())); + break; + default: + return type + "is not a valid placeholder"; + } + return String.join(separator, quests); + } + + private String getQuestDisplayNameStripped(Quest quest) { + QItemStack qItemStack = plugin.getQItemStackRegistry().getQuestItemStack(quest); + if (qItemStack != null) return Chat.strip(qItemStack.getName()); + return null; + } + + private List getCategoryQuests(QPlayer questP, Category category, QuestProgressFile.QuestsProgressFilter filter) { + final List categoryQuests = new ArrayList<>(); + category.getRegisteredQuestIds().forEach(q -> { + Quest quest = plugin.getQuestManager().getQuestById(q); + if (quest != null) { + switch (filter) { + case STARTED: + if (questP.getQuestProgressFile().getQuestProgress(quest).isStarted()) + categoryQuests.add(quest); + break; + case COMPLETED: + if (questP.getQuestProgressFile().getQuestProgress(quest).isCompleted()) + categoryQuests.add(quest); + break; + case COMPLETED_BEFORE: + if (questP.getQuestProgressFile().getQuestProgress(quest).isCompletedBefore()) + categoryQuests.add(quest); + break; + default: + categoryQuests.add(quest); + } + } + }); + return categoryQuests; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title.java new file mode 100644 index 00000000..49c4613b --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title.java @@ -0,0 +1,8 @@ +package com.leonardobishop.quests.bukkit.hook.title; + +import org.bukkit.entity.Player; + +public interface Title { + + void sendTitle(Player player, String message, String submessage); +} \ No newline at end of file diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title_Bukkit.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title_Bukkit.java new file mode 100644 index 00000000..6975700e --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title_Bukkit.java @@ -0,0 +1,12 @@ +package com.leonardobishop.quests.bukkit.hook.title; + +import org.bukkit.entity.Player; + +public class Title_Bukkit implements Title { + + // new title function with timings + @Override + public void sendTitle(Player player, String message, String submessage) { + player.sendTitle(message, submessage, 10, 100, 10); + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title_BukkitNoTimings.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title_BukkitNoTimings.java new file mode 100644 index 00000000..64c91ea6 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title_BukkitNoTimings.java @@ -0,0 +1,13 @@ +package com.leonardobishop.quests.bukkit.hook.title; + +import org.bukkit.entity.Player; + +public class Title_BukkitNoTimings implements Title { + + // this one is for 1.8, 1.9 and 1.10 where there was no timings method + @Override + public void sendTitle(Player player, String message, String submessage) { + player.sendTitle(message, submessage); + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title_Other.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title_Other.java new file mode 100644 index 00000000..cdc8d7bf --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/title/Title_Other.java @@ -0,0 +1,11 @@ +package com.leonardobishop.quests.bukkit.hook.title; + +import org.bukkit.entity.Player; + +public class Title_Other implements Title { + + @Override + public void sendTitle(Player player, String message, String submessage) { + // title function does not exist + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/listener/PlayerJoinListener.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/listener/PlayerJoinListener.java new file mode 100644 index 00000000..2fe15860 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/listener/PlayerJoinListener.java @@ -0,0 +1,51 @@ +package com.leonardobishop.quests.bukkit.listener; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.util.Messages; +import com.leonardobishop.quests.common.player.QPlayer; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; +import org.bukkit.event.player.PlayerJoinEvent; + +import java.util.UUID; + +public class PlayerJoinListener implements Listener { + + private final BukkitQuestsPlugin plugin; + + public PlayerJoinListener(BukkitQuestsPlugin plugin) { + this.plugin = plugin; + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onAsyncJoin(AsyncPlayerPreLoginEvent event) { + plugin.getPlayerManager().loadPlayer(event.getUniqueId()); + } + + @EventHandler + public void onEvent(PlayerJoinEvent event) { + UUID playerUuid = event.getPlayer().getUniqueId(); + plugin.getPlayerManager().loadPlayer(playerUuid); + if (plugin.getDescription().getVersion().contains("beta") && event.getPlayer().hasPermission("quests.admin")) { + event.getPlayer().sendMessage(Messages.BETA_REMINDER.getMessage()); + } + if (plugin.getUpdater().isUpdateReady() && event.getPlayer().hasPermission("quests.admin")) { + // delay for a bit so they actually see the message + String updateMessage = Messages.QUEST_UPDATER.getMessage() + .replace("{newver}", plugin.getUpdater().getReturnedVersion()) + .replace("{oldver}", plugin.getUpdater().getInstalledVersion()) + .replace("{link}", plugin.getUpdater().getUpdateLink()); + Bukkit.getScheduler().runTaskLater(this.plugin, () -> event.getPlayer().sendMessage(updateMessage), 50L); + } + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(playerUuid); + if (qPlayer == null) return; + + // run a full check to check for any missed quest completions + plugin.getQuestCompleter().queueFullCheck(qPlayer.getQuestProgressFile()); + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/listener/PlayerLeaveListener.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/listener/PlayerLeaveListener.java new file mode 100644 index 00000000..1f41344a --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/listener/PlayerLeaveListener.java @@ -0,0 +1,24 @@ +package com.leonardobishop.quests.bukkit.listener; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.common.player.QPlayer; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +public class PlayerLeaveListener implements Listener { + + private final BukkitQuestsPlugin plugin; + + public PlayerLeaveListener(BukkitQuestsPlugin plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onEvent(PlayerQuitEvent event) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) return; + plugin.getPlayerManager().removePlayer(qPlayer.getPlayerUUID()); + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/CancelQMenu.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/CancelQMenu.java new file mode 100644 index 00000000..3c811bff --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/CancelQMenu.java @@ -0,0 +1,85 @@ +package com.leonardobishop.quests.bukkit.menu; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.config.BukkitQuestsConfig; +import com.leonardobishop.quests.bukkit.util.Chat; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.quest.Quest; +import org.bukkit.Bukkit; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +/** + * Represents a cancellation confirmation menu for a specific quest. + */ +public class CancelQMenu implements QMenu { + + private final BukkitQuestsPlugin plugin; + private final BukkitQuestsConfig config; + private final QMenu superMenu; + private final QPlayer owner; + private final Quest quest; + + public CancelQMenu(BukkitQuestsPlugin plugin, QMenu superMenu, QPlayer owner, Quest quest) { + this.plugin = plugin; + this.config = (BukkitQuestsConfig) plugin.getQuestsConfig(); + this.superMenu = superMenu; + this.owner = owner; + this.quest = quest; + } + + public Quest getQuest() { + return quest; + } + + @Override + public QPlayer getOwner() { + return owner; + } + + public Inventory toInventory(int page) { + String title = Chat.color(config.getString("options.guinames.quest-cancel")); + + ItemStack yes = config.getItem("gui.quest-cancel-yes"); + ItemStack no = config.getItem("gui.quest-cancel-no"); + + ItemStack background = config.getItem("gui.quest-cancel-background"); + 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); + } + + inventory.setItem(10, no); + inventory.setItem(11, no); + inventory.setItem(12, no); + inventory.setItem(13, plugin.getQItemStackRegistry().getQuestItemStack(quest).toItemStack(quest, owner, owner.getQuestProgressFile().getQuestProgress(quest))); + inventory.setItem(14, yes); + inventory.setItem(15, yes); + inventory.setItem(16, yes); + + return inventory; + } + + @Override + public void handleClick(InventoryClickEvent event, MenuController controller) { + if (event.getSlot() == 10 || event.getSlot() == 11 || event.getSlot() == 12) { + controller.openMenu(event.getWhoClicked(), superMenu, 1); + } else if (event.getSlot() == 14 || event.getSlot() == 15 || event.getSlot() == 16) { + if (owner.cancelQuest(quest)) { + event.getWhoClicked().closeInventory(); + } + } + } + + public QMenu getSuperMenu() { + return superMenu; + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/CategoryQMenu.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/CategoryQMenu.java new file mode 100644 index 00000000..03693657 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/CategoryQMenu.java @@ -0,0 +1,171 @@ +package com.leonardobishop.quests.bukkit.menu; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.config.BukkitQuestsConfig; +import com.leonardobishop.quests.bukkit.menu.element.CategoryMenuElement; +import com.leonardobishop.quests.bukkit.menu.element.CustomMenuElement; +import com.leonardobishop.quests.bukkit.menu.element.MenuElement; +import com.leonardobishop.quests.bukkit.menu.element.SpacerMenuElement; +import com.leonardobishop.quests.bukkit.util.Chat; +import com.leonardobishop.quests.bukkit.util.MenuUtils; +import com.leonardobishop.quests.bukkit.util.Messages; +import com.leonardobishop.quests.common.player.QPlayer; +import org.apache.commons.lang.math.NumberUtils; +import org.bukkit.Bukkit; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents a menu which contains a listing of different categories. + */ +public class CategoryQMenu implements QMenu { + + private final BukkitQuestsPlugin plugin; + private final BukkitQuestsConfig config; + private final HashMap menuElements = new HashMap<>(); + private final QPlayer owner; + + private int pageSize = 45; + private int maxElement = 0; + private int pagePrevLocation = -1; + private int pageNextLocation = -1; + private int currentPage = -1; + + public CategoryQMenu(BukkitQuestsPlugin plugin, QPlayer owner) { + this.plugin = plugin; + this.config = (BukkitQuestsConfig) plugin.getQuestsConfig(); + this.owner = owner; + } + + public void populate(List menuQuests) { + if (config.getConfig().isConfigurationSection("custom-elements.categories")) { + for (String s : config.getConfig().getConfigurationSection("custom-elements.categories").getKeys(false)) { + if (!NumberUtils.isNumber(s)) continue; + int slot = Integer.parseInt(s); + int repeat = config.getInt("custom-elements.categories." + s + ".repeat"); + MenuElement menuElement; + if (config.getConfig().contains("custom-elements.categories." + s + ".display")) { + ItemStack is = config.getItem("custom-elements.categories." + s + ".display"); + menuElement = new CustomMenuElement(is); + } else if (config.getBoolean("custom-elements.categories." + s + ".spacer", false)) { + menuElement = new SpacerMenuElement(); + } else continue; // user = idiot + + for (int i = 0; i <= repeat; i++) { + menuElements.put(slot + i, menuElement); + } + } + } + int slot = 0; + for (QuestQMenu questQMenu : menuQuests) { + while (menuElements.containsKey(slot)) slot++; + if (config.getBoolean("options.gui-hide-categories-nopermission") && plugin.getQuestManager().getCategoryById(questQMenu.getCategoryName()).isPermissionRequired()) { + if (!Bukkit.getPlayer(owner.getPlayerUUID()).hasPermission("quests.category." + questQMenu.getCategoryName())) { + continue; + } + } + menuElements.put(slot, new CategoryMenuElement(plugin, owner.getPlayerUUID(), questQMenu)); + slot++; + } + + for (Integer integer : menuElements.keySet()) { + if (integer + 1 > maxElement) maxElement = integer + 1; + } + + // stop bottom row of pg1 going to pg2 if entire inv contents would fit on pg1 perfectly + if (maxElement > 45 && maxElement <= 54) { + pageSize = 54; + } else { + pageSize = 45; + } + } + + @Override + public QPlayer getOwner() { + return owner; + } + + public Inventory toInventory(int page) { + currentPage = page; + int pageMin = pageSize * (page - 1); + int pageMax = pageSize * page; + String title = Chat.color(config.getString("options.guinames.quests-category")); + + ItemStack pageIs; + ItemStack pagePrevIs; + ItemStack pageNextIs; + Inventory inventory = Bukkit.createInventory(null, 54, title); + + int highestOnPage = 0; + for (int pointer = pageMin; pointer < pageMax; pointer++) { + if (menuElements.containsKey(pointer)) { + inventory.setItem(pointer - ((page - 1) * pageSize), menuElements.get(pointer).asItemStack()); + if (pointer + 1 > highestOnPage) highestOnPage = pointer + 1; + } + } + + pageNextLocation = -1; + pagePrevLocation = -1; + + Map pageplaceholders = new HashMap<>(); + pageplaceholders.put("{prevpage}", String.valueOf(page - 1)); + pageplaceholders.put("{nextpage}", String.valueOf(page + 1)); + pageplaceholders.put("{page}", String.valueOf(page)); + pageIs = MenuUtils.applyPlaceholders(plugin, owner.getPlayerUUID(), config.getItem("gui.page-desc"), pageplaceholders); + pageIs.setAmount(Math.min(page, 64)); + pagePrevIs = MenuUtils.applyPlaceholders(plugin, owner.getPlayerUUID(), config.getItem("gui.page-prev"), pageplaceholders); + pageNextIs = MenuUtils.applyPlaceholders(plugin, owner.getPlayerUUID(), config.getItem("gui.page-next"), pageplaceholders); + + if (maxElement > pageSize) { + inventory.setItem(49, pageIs); + if (page != 1) { + inventory.setItem(48, pagePrevIs); + pagePrevLocation = 48; + } + if (Math.ceil((double) maxElement / ((double) pageSize)) != page) { + inventory.setItem(50, pageNextIs); + pageNextLocation = 50; + } + } else if (config.getBoolean("options.trim-gui-size") && page == 1) { + int inventorySize = highestOnPage + (9 - highestOnPage % 9) * Math.min(1, highestOnPage % 9); + inventorySize = inventorySize <= 0 ? 9 : inventorySize; + if (inventorySize == 54) { + return inventory; + } + + Inventory trimmedInventory = Bukkit.createInventory(null, inventorySize, title); + + for (int slot = 0; slot < trimmedInventory.getSize(); slot++) { + trimmedInventory.setItem(slot, inventory.getItem(slot)); + } + return trimmedInventory; + } + return inventory; + } + + @Override + public void handleClick(InventoryClickEvent event, MenuController controller) { + if (pagePrevLocation == event.getSlot()) { + controller.openMenu(event.getWhoClicked(), this, currentPage - 1); + + } else if (pageNextLocation == event.getSlot()) { + controller.openMenu(event.getWhoClicked(), this, currentPage + 1); + + } else if (event.getSlot() < pageSize && menuElements.containsKey(event.getSlot() + (((currentPage) - 1) * pageSize))) { + MenuElement element = menuElements.get(event.getSlot() + ((currentPage - 1) * pageSize)); + if (element instanceof CategoryMenuElement) { + CategoryMenuElement categoryMenuElement = (CategoryMenuElement) element; + QuestQMenu questQMenu = categoryMenuElement.getQuestMenu(); + if (plugin.getMenuController().openQuestCategory(owner, + plugin.getQuestManager().getCategoryById(questQMenu.getCategoryName()), questQMenu) != 0) { + event.getWhoClicked().sendMessage(Messages.QUEST_CATEGORY_PERMISSION.getMessage()); + } + } + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/DailyQMenu.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/DailyQMenu.java new file mode 100644 index 00000000..622137a4 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/DailyQMenu.java @@ -0,0 +1,97 @@ +//package com.leonardobishop.quests.bukkit.menu; +// +//import com.leonardobishop.quests.Quests; +//import com.leonardobishop.quests.common.enums.QuestStartResult; +//import com.leonardobishop.quests.common.player.QPlayer; +//import com.leonardobishop.quests.common.quest.Quest; +//import com.leonardobishop.quests.listener.MenuController; +//import com.leonardobishop.quests.menu.element.MenuElement; +//import com.leonardobishop.quests.menu.element.QuestMenuElement; +//import com.leonardobishop.quests.quest.controller.DailyQuestController; +//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/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/MenuController.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/MenuController.java new file mode 100644 index 00000000..aeb543d6 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/MenuController.java @@ -0,0 +1,176 @@ +package com.leonardobishop.quests.bukkit.menu; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.quest.Category; +import com.leonardobishop.quests.common.quest.Quest; +import org.bukkit.Bukkit; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryType; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class MenuController implements Listener { + + private final HashMap tracker = new HashMap<>(); + private final BukkitQuestsPlugin plugin; + + public MenuController(BukkitQuestsPlugin plugin) { + this.plugin = plugin; + } + + public void openMenu(HumanEntity player, QMenu qMenu, int page) { + player.openInventory(qMenu.toInventory(page)); + tracker.put(player.getUniqueId(), qMenu); + } + + @EventHandler + private void onClose(InventoryCloseEvent event) { + tracker.remove(event.getPlayer().getUniqueId()); + } + + @EventHandler + private void onClick(InventoryClickEvent event) { + // check if the player has a quest menu open + if (tracker.containsKey(event.getWhoClicked().getUniqueId())) { + event.setCancelled(true); + if (event.getClickedInventory() == null) + return; //The player clicked outside the inventory + if (event.getClickedInventory().getType() == InventoryType.PLAYER) + return; //The clicked inventory is a player inventory type + + QMenu qMenu = tracker.get(event.getWhoClicked().getUniqueId()); + qMenu.handleClick(event, this); + } + } + + /** + * Opens a quest listing menu for the player. + * + * @return 0 if success, 1 if no permission, 2 is only data loaded, 3 if player not found + */ + public int openQuestCategory(QPlayer qPlayer, Category category, CategoryQMenu superMenu, boolean backButton) { + Player player = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + if (player == null) { + return 3; + } + + if (category.isPermissionRequired() && !player.hasPermission("quests.category." + category.getId())) { + return 1; + } + + // Using `this` instead of searching again for this QPlayer + QuestQMenu questQMenu = new QuestQMenu(plugin, qPlayer, category.getId(), superMenu); + List quests = new ArrayList<>(); + for (String questid : category.getRegisteredQuestIds()) { + Quest quest = plugin.getQuestManager().getQuestById(questid); + if (quest != null) { + quests.add(quest); + } + } + questQMenu.populate(quests); + questQMenu.setBackButtonEnabled(backButton); + + openMenu(player, questQMenu, 1); + return 0; + } + + /** + * Opens a specific quest listing menu for the player. + * + * @return 0 if success, 1 if no permission, 2 is only data loaded, 3 if player not found + */ + public int openQuestCategory(QPlayer qPlayer, Category category, QuestQMenu questQMenu) { + Player player = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + if (player == null) { + return 3; + } + + if (category.isPermissionRequired() && !player.hasPermission("quests.category." + category.getId())) { + return 1; + } + + openMenu(player, questQMenu, 1); + return 0; + } + + /** + * Open the main menu for the player + * + * @param qPlayer player + */ + public void openMainMenu(QPlayer qPlayer) { + Player player = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + if (player == null) { + return; + } + + if (plugin.getQuestController().getName().equals("normal")) { + if (plugin.getQuestsConfig().getBoolean("options.categories-enabled")) { + CategoryQMenu categoryQMenu = new CategoryQMenu(plugin, qPlayer); + List questMenus = new ArrayList<>(); + for (Category category : plugin.getQuestManager().getCategories()) { + QuestQMenu questQMenu = new QuestQMenu(plugin, qPlayer, 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, qPlayer, "", null); + List quests = new ArrayList<>(); + for (Map.Entry entry : plugin.getQuestManager().getQuests().entrySet()) { + quests.add(entry.getValue()); + } + 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); +// } + } + + /** + * Open the started menu for the player + * + * @param qPlayer player + */ + public void openStartedQuests(QPlayer qPlayer) { + Player player = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + if (player == null) { + return; + } + + StartedQMenu startedQMenu = new StartedQMenu(plugin, qPlayer); + List quests = new ArrayList<>(); + for (Map.Entry entry : plugin.getQuestManager().getQuests().entrySet()) { + quests.add(new QuestSortWrapper(plugin, entry.getValue())); + } + startedQMenu.populate(quests); + + plugin.getMenuController().openMenu(player, startedQMenu, 1); + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/QMenu.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/QMenu.java new file mode 100644 index 00000000..0e3c9f78 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/QMenu.java @@ -0,0 +1,13 @@ +package com.leonardobishop.quests.bukkit.menu; + +import com.leonardobishop.quests.common.player.QPlayer; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; + +public interface QMenu { + + QPlayer getOwner(); + Inventory toInventory(int page); + void handleClick(InventoryClickEvent event, MenuController controller); + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/QuestQMenu.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/QuestQMenu.java new file mode 100644 index 00000000..be2125e8 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/QuestQMenu.java @@ -0,0 +1,288 @@ +package com.leonardobishop.quests.bukkit.menu; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.config.BukkitQuestsConfig; +import com.leonardobishop.quests.bukkit.menu.element.CustomMenuElement; +import com.leonardobishop.quests.bukkit.menu.element.MenuElement; +import com.leonardobishop.quests.bukkit.menu.element.QuestMenuElement; +import com.leonardobishop.quests.bukkit.menu.element.SpacerMenuElement; +import com.leonardobishop.quests.bukkit.util.Chat; +import com.leonardobishop.quests.bukkit.util.MenuUtils; +import com.leonardobishop.quests.common.enums.QuestStartResult; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.quest.Quest; +import org.apache.commons.lang.math.NumberUtils; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +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.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents a menu for a specified category (or all if they are disabled), + * which contains a listing of different quests. + */ +public class QuestQMenu implements QMenu { + + private final BukkitQuestsPlugin plugin; + private final BukkitQuestsConfig config; + private final HashMap menuElements = new HashMap<>(); + private final CategoryQMenu superMenu; + private final String categoryName; + private final int pageSize = 45; + private final QPlayer owner; + + private int maxElement = 0; + private int backButtonLocation = -1; + private int pagePrevLocation = -1; + private int pageNextLocation = -1; + private int currentPage = -1; + private boolean backButtonEnabled = true; + + public QuestQMenu(BukkitQuestsPlugin plugin, QPlayer owner, String categoryName, CategoryQMenu superMenu) { + this.plugin = plugin; + this.config = (BukkitQuestsConfig) plugin.getQuestsConfig(); + this.owner = owner; + this.categoryName = categoryName; + this.superMenu = superMenu; + } + + public void populate(List quests) { + String path; + if (config.getBoolean("options.categories-enabled")) { + path = "custom-elements.c:" + categoryName; + } else { + path = "custom-elements.quests"; + } + if (plugin.getConfig().isConfigurationSection(path)) { + for (String s : plugin.getConfig().getConfigurationSection(path).getKeys(false)) { + if (!NumberUtils.isNumber(s)) continue; + int slot = Integer.parseInt(s); + int repeat = plugin.getConfig().getInt(path + "." + s + ".repeat"); + MenuElement menuElement; + if (plugin.getConfig().contains(path + "." + s + ".display")) { + ItemStack is = plugin.getItemStack(path + "." + s + ".display", plugin.getConfig()); + menuElement = new CustomMenuElement(is); + } else if (plugin.getConfig().getBoolean(path + "." + s + ".spacer", false)) { + menuElement = new SpacerMenuElement(); + } else continue; // user = idiot + + for (int i = 0; i <= repeat; i++) { + menuElements.put(slot + i, menuElement); + } + } + } + + Collections.sort(quests); + int slot = 0; + for (Quest quest : quests) { + while (menuElements.containsKey(slot)) slot++; + if (config.getBoolean("options.gui-hide-locked")) { + QuestProgress questProgress = owner.getQuestProgressFile().getQuestProgress(quest); + long cooldown = owner.getQuestProgressFile().getCooldownFor(quest); + if (!owner.getQuestProgressFile().hasMetRequirements(quest) || (!quest.isRepeatable() && questProgress.isCompletedBefore()) || cooldown > 0) { + continue; + } + } + if (config.getBoolean("options.gui-hide-quests-nopermission") && quest.isPermissionRequired()) { + if (!Bukkit.getPlayer(owner.getPlayerUUID()).hasPermission("quests.quest." + quest.getId())) { + continue; + } + } + menuElements.put(slot, new QuestMenuElement(plugin, owner, quest.getId())); + slot++; + } + + for (Integer integer : menuElements.keySet()) { + if (integer + 1 > maxElement) maxElement = integer + 1; + } + } + + @Override + public QPlayer getOwner() { + return owner; + } + + public String getCategoryName() { + return categoryName; + } + + public int getPagePrevLocation() { + return pagePrevLocation; + } + + public int getPageNextLocation() { + return pageNextLocation; + } + + public int getCurrentPage() { + return currentPage; + } + + public int getPageSize() { + return pageSize; + } + + public Inventory toInventory(int page) { + currentPage = page; + int pageMin = pageSize * (page - 1); + int pageMax = pageSize * page; + String title = Chat.color(config.getString("options.guinames.quests-menu")); + + ItemStack pageIs; + ItemStack pagePrevIs; + ItemStack pageNextIs; + ItemStack back = config.getItem("gui.back-button"); + + Inventory inventory = Bukkit.createInventory(null, 54, title); + + int highestOnPage = 0; + for (int pointer = pageMin; pointer < pageMax; pointer++) { + if (menuElements.containsKey(pointer)) { + inventory.setItem(pointer - ((page - 1) * pageSize), menuElements.get(pointer).asItemStack()); + if (pointer + 1 > highestOnPage) highestOnPage = pointer + 1; + } + } + + pageNextLocation = -1; + pagePrevLocation = -1; + + Map pageplaceholders = new HashMap<>(); + pageplaceholders.put("{prevpage}", String.valueOf(page - 1)); + pageplaceholders.put("{nextpage}", String.valueOf(page + 1)); + pageplaceholders.put("{page}", String.valueOf(page)); + pageIs = replaceItemStack(config.getItem("gui.page-description"), pageplaceholders); + pageIs.setAmount(Math.min(page, 64)); + pagePrevIs = replaceItemStack(config.getItem("gui.page-prev"), pageplaceholders); + pageNextIs = replaceItemStack(config.getItem("gui.page-next"), pageplaceholders); + + if (config.getBoolean("options.categories-enabled") && backButtonEnabled) { + inventory.setItem(45, back); + backButtonLocation = 45; + } + if (maxElement > pageSize) { + inventory.setItem(49, pageIs); + if (page != 1) { + inventory.setItem(48, pagePrevIs); + pagePrevLocation = 48; + } + if (Math.ceil((double) maxElement / ((double) pageSize)) != page) { + inventory.setItem(50, pageNextIs); + pageNextLocation = 50; + } + } else if (config.getBoolean("options.trim-gui-size") && page == 1) { + int inventorySize = highestOnPage + (9 - highestOnPage % 9) * Math.min(1, highestOnPage % 9); + inventorySize = inventorySize <= 0 ? 9 : inventorySize; + if (inventorySize == 54) { + return inventory; + } else if (config.getBoolean("options.categories-enabled") && backButtonEnabled) { + inventorySize += 9; + } + + Inventory trimmedInventory = Bukkit.createInventory(null, inventorySize, title); + + for (int slot = 0; slot < trimmedInventory.getSize(); slot++) { + if (slot >= (trimmedInventory.getSize() - 9) && backButtonEnabled){ + if (config.getBoolean("options.categories-enabled")) { + trimmedInventory.setItem(slot, back); + backButtonLocation = slot; + } + break; + } + trimmedInventory.setItem(slot, inventory.getItem(slot)); + } + return trimmedInventory; + } + + return inventory; + } + + @Override + public void handleClick(InventoryClickEvent event, MenuController controller) { + //TODO maybe redo this maybe + if (pagePrevLocation == event.getSlot()) { + controller.openMenu(event.getWhoClicked(), this, currentPage - 1); + + } else if (pageNextLocation == event.getSlot()) { + controller.openMenu(event.getWhoClicked(), this, currentPage + 1); + + } else if (config.getBoolean("options.categories-enabled") && backButtonLocation == event.getSlot()) { + controller.openMenu(event.getWhoClicked(), superMenu, 1); + + } else if (event.getSlot() < pageSize && menuElements.containsKey(event.getSlot() + (((currentPage) - 1) * pageSize))) { + MenuElement menuElement = menuElements.get(event.getSlot() + ((currentPage - 1) * pageSize)); + if (menuElement instanceof QuestMenuElement) { + QuestMenuElement questMenuElement = (QuestMenuElement) menuElement; + Quest quest = plugin.getQuestManager().getQuestById(questMenuElement.getQuestId()); + if (event.getClick() == ClickType.LEFT) { + if (config.getBoolean("options.quest-autostart")) return; + if (owner.startQuest(quest) == QuestStartResult.QUEST_SUCCESS) { + event.getWhoClicked().closeInventory(); //TODO Option to keep the menu open + } + } else if (event.getClick() == ClickType.MIDDLE && config.getBoolean("options.quest-autostart")) { + MenuUtils.handleMiddleClick(plugin, this, quest, Bukkit.getPlayer(owner.getPlayerUUID()), controller); + } else if (event.getClick() == ClickType.RIGHT && config.getBoolean("options.allow-quest-cancel") + && owner.hasStartedQuest(quest)) { + MenuUtils.handleRightClick(plugin, this, quest, Bukkit.getPlayer(owner.getPlayerUUID()), controller); + } + } + } + } + + public boolean isBackButtonEnabled() { + return backButtonEnabled; + } + + public void setBackButtonEnabled(boolean backButtonEnabled) { + this.backButtonEnabled = backButtonEnabled; + } + + public int getBackButtonLocation() { + return backButtonLocation; + } + + public CategoryQMenu getSuperMenu() { + return superMenu; + } + + public ItemStack replaceItemStack(ItemStack is) { + return replaceItemStack(is, Collections.emptyMap()); + } + + public ItemStack replaceItemStack(ItemStack is, Map placeholders) { + ItemStack newItemStack = is.clone(); + List lore = newItemStack.getItemMeta().getLore(); + List newLore = new ArrayList<>(); + ItemMeta ism = newItemStack.getItemMeta(); + Player player = Bukkit.getPlayer(owner.getPlayerUUID()); + if (lore != null) { + for (String s : lore) { + for (Map.Entry entry : placeholders.entrySet()) { + s = s.replace(entry.getKey(), entry.getValue()); + if (plugin.getPlaceholderAPIHook() != null && plugin.getQuestsConfig().getBoolean("options.gui-use-placeholderapi")) { + s = plugin.getPlaceholderAPIHook().replacePlaceholders(player, s); + } + } + newLore.add(s); + } + } + for (Map.Entry entry : placeholders.entrySet()) { + ism.setDisplayName(ism.getDisplayName().replace(entry.getKey(), entry.getValue())); + if (plugin.getPlaceholderAPIHook() != null && plugin.getQuestsConfig().getBoolean("options.gui-use-placeholderapi")) { + ism.setDisplayName(plugin.getPlaceholderAPIHook().replacePlaceholders(player, ism.getDisplayName())); + } + } + ism.setLore(newLore); + newItemStack.setItemMeta(ism); + return newItemStack; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/QuestSortWrapper.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/QuestSortWrapper.java new file mode 100644 index 00000000..31d4f214 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/QuestSortWrapper.java @@ -0,0 +1,44 @@ +package com.leonardobishop.quests.bukkit.menu; + +import com.leonardobishop.quests.common.plugin.Quests; +import com.leonardobishop.quests.common.quest.Category; +import com.leonardobishop.quests.common.quest.Quest; + +public class QuestSortWrapper implements Comparable { + + private int weightedSortOrder; + private final Quest quest; + + public QuestSortWrapper(Quests plugin, Quest quest) { + this.quest = quest; + if (quest.getCategoryId() == null) { + weightedSortOrder = quest.getSortOrder(); + return; + } + Category c = plugin.getQuestManager().getCategoryById(quest.getCategoryId()); + if (c != null) { + int index = plugin.getQuestManager().getCategories().indexOf(c); + int amountBelow = 0; + //TODO precalculate + for (int i = index; i > 0; i--) { + Category below = plugin.getQuestManager().getCategories().get(i - 1); + amountBelow += below.getRegisteredQuestIds().size(); + } + weightedSortOrder = amountBelow + quest.getSortOrder(); + } + } + + public int getWeightedSortOrder() { + return weightedSortOrder; + } + + public Quest getQuest() { + return quest; + } + + @Override + public int compareTo(QuestSortWrapper quest) { + return (weightedSortOrder - quest.weightedSortOrder); + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/StartedQMenu.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/StartedQMenu.java new file mode 100644 index 00000000..01f99c79 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/StartedQMenu.java @@ -0,0 +1,175 @@ +package com.leonardobishop.quests.bukkit.menu; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.config.BukkitQuestsConfig; +import com.leonardobishop.quests.bukkit.util.Chat; +import com.leonardobishop.quests.bukkit.util.MenuUtils; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.quest.Quest; +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 java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents a menu listing quests the player has started. + */ +public class StartedQMenu implements QMenu { + + private final BukkitQuestsPlugin plugin; + private final BukkitQuestsConfig config; + private final HashMap slotsToQuestIds = new HashMap<>(); + private final int pageSize = 45; + private final QPlayer owner; + + private int pagePrevLocation = -1; + private int pageNextLocation = -1; + private int currentPage = -1; + + public StartedQMenu(BukkitQuestsPlugin plugin, QPlayer owner) { + this.plugin = plugin; + this.config = (BukkitQuestsConfig) plugin.getQuestsConfig(); + this.owner = owner; + } + + public void populate(List quests) { + Collections.sort(quests); + int slot = 0; + for (QuestSortWrapper quest : quests) { + if (owner.hasStartedQuest(quest.getQuest())) { + slotsToQuestIds.put(slot, quest.getQuest().getId()); + slot++; + } + } + } + + public HashMap getSlotsToMenu() { + return slotsToQuestIds; + } + + @Override + public QPlayer getOwner() { + return owner; + } + + public int getPagePrevLocation() { + return pagePrevLocation; + } + + public int getPageNextLocation() { + return pageNextLocation; + } + + public int getCurrentPage() { + return currentPage; + } + + public int getPageSize() { + return pageSize; + } + + public Inventory toInventory(int page) { + currentPage = page; + int pageMin = pageSize * (page - 1); + int pageMax = pageSize * page; + String title = Chat.color(config.getString("options.guinames.quests-started-menu")); + + ItemStack pageIs; + ItemStack pagePrevIs; + ItemStack pageNextIs; + ItemStack none = config.getItem("gui.no-started-quests"); + + Inventory inventory = Bukkit.createInventory(null, 54, title); + + int invSlot = 0; + if (!slotsToQuestIds.isEmpty()) { + for (int pointer = pageMin; pointer < pageMax; pointer++) { + if (slotsToQuestIds.containsKey(pointer)) { + Quest quest = plugin.getQuestManager().getQuestById(slotsToQuestIds.get(pointer)); + QuestProgress questProgress = owner.getQuestProgressFile().getQuestProgress(quest); + + inventory.setItem(invSlot, MenuUtils.applyPlaceholders(plugin, owner.getPlayerUUID(), + plugin.getQItemStackRegistry().getQuestItemStack(quest).toItemStack(quest, owner, questProgress))); + } + invSlot++; + } + } else { + inventory.setItem(4, none); + } + + pageNextLocation = -1; + pagePrevLocation = -1; + + Map pageplaceholders = new HashMap<>(); + pageplaceholders.put("{prevpage}", String.valueOf(page - 1)); + pageplaceholders.put("{nextpage}", String.valueOf(page + 1)); + pageplaceholders.put("{page}", String.valueOf(page)); + pageIs = MenuUtils.applyPlaceholders(plugin, owner.getPlayerUUID(), config.getItem("gui.page-description"), pageplaceholders); + pageIs.setAmount(Math.min(page, 64)); + pagePrevIs = MenuUtils.applyPlaceholders(plugin, owner.getPlayerUUID(), config.getItem("gui.page-prev"), pageplaceholders); + pageNextIs = MenuUtils.applyPlaceholders(plugin, owner.getPlayerUUID(), config.getItem("gui.page-next"), pageplaceholders); + + if (slotsToQuestIds.size() > pageSize) { + inventory.setItem(49, pageIs); + if (page != 1) { + inventory.setItem(48, pagePrevIs); + pagePrevLocation = 48; + } + if (Math.ceil((double) slotsToQuestIds.size() / ((double) 45)) != page) { + inventory.setItem(50, pageNextIs); + pageNextLocation = 50; + } + } else if (config.getBoolean("options.trim-gui-size") && page == 1) { + int slotsUsed = 0; + for (int pointer = 0; pointer < pageMax; pointer++) { + if (inventory.getItem(pointer) != null) { + slotsUsed++; + } + } + + int inventorySize = (slotsUsed >= 54) ? 54 : slotsUsed + (9 - slotsUsed % 9) * Math.min(1, slotsUsed % 9); + inventorySize = inventorySize <= 0 ? 9 : inventorySize; + if (inventorySize == 54) { + return inventory; + } + + Inventory trimmedInventory = Bukkit.createInventory(null, inventorySize, title); + + for (int slot = 0; slot < trimmedInventory.getSize(); slot++) { + trimmedInventory.setItem(slot, inventory.getItem(slot)); + } + return trimmedInventory; + } + + return inventory; + } + + @Override + public void handleClick(InventoryClickEvent event, MenuController controller) { + if (pagePrevLocation == event.getSlot()) { + controller.openMenu(event.getWhoClicked(), this, currentPage - 1); + + } else if (pageNextLocation == event.getSlot()) { + controller.openMenu(event.getWhoClicked(), this, currentPage + 1); + + } else if (event.getSlot() < pageSize && slotsToQuestIds.containsKey(event.getSlot() + ((currentPage) - 1) * pageSize)) { + + // repeat from above + String questid = slotsToQuestIds.get(event.getSlot() + (((currentPage) - 1) * pageSize)); + Quest quest = plugin.getQuestManager().getQuestById(questid); + if (event.getClick() == ClickType.MIDDLE && config.getBoolean("options.allow-quest-track")) { + MenuUtils.handleMiddleClick(plugin, this, quest, Bukkit.getPlayer(owner.getPlayerUUID()), controller); + } else if (event.getClick() == ClickType.RIGHT && config.getBoolean("options.allow-quest-cancel") + && owner.hasStartedQuest(quest)) { + MenuUtils.handleRightClick(plugin, this, quest, Bukkit.getPlayer(owner.getPlayerUUID()), controller); + } + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/CategoryMenuElement.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/CategoryMenuElement.java new file mode 100644 index 00000000..9aa2efb5 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/CategoryMenuElement.java @@ -0,0 +1,64 @@ +package com.leonardobishop.quests.bukkit.menu.element; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.menu.QuestQMenu; +import com.leonardobishop.quests.common.quest.Category; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class CategoryMenuElement extends MenuElement { + + private final BukkitQuestsPlugin plugin; + private final UUID owner; + private final QuestQMenu questMenu; + + public CategoryMenuElement(BukkitQuestsPlugin plugin, UUID owner, QuestQMenu questMenu) { + this.plugin = plugin; + this.owner = owner; + this.questMenu = questMenu; + } + + public UUID getOwner() { + return owner; + } + + public QuestQMenu getQuestMenu() { + return questMenu; + } + + @Override + public ItemStack asItemStack() { + Category category = plugin.getQuestManager().getCategoryById(questMenu.getCategoryName()); + if (category != null) { + return replaceItemStack(plugin.getQItemStackRegistry().getCategoryItemStack(category)); + } + return null; + } + + private ItemStack replaceItemStack(ItemStack is) { + if (plugin.getPlaceholderAPIHook() != null && plugin.getQuestsConfig().getBoolean("options.gui-use-placeholderapi")) { + ItemStack newItemStack = is.clone(); + List lore = newItemStack.getItemMeta().getLore(); + List newLore = new ArrayList<>(); + ItemMeta ism = newItemStack.getItemMeta(); + Player player = Bukkit.getPlayer(owner); + ism.setDisplayName(plugin.getPlaceholderAPIHook().replacePlaceholders(player, ism.getDisplayName())); + if (lore != null) { + for (String s : lore) { + s = plugin.getPlaceholderAPIHook().replacePlaceholders(player, s); + newLore.add(s); + } + } + ism.setLore(newLore); + newItemStack.setItemMeta(ism); + return newItemStack; + } + return is; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/CustomMenuElement.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/CustomMenuElement.java new file mode 100644 index 00000000..0eee9e92 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/CustomMenuElement.java @@ -0,0 +1,17 @@ +package com.leonardobishop.quests.bukkit.menu.element; + +import org.bukkit.inventory.ItemStack; + +public class CustomMenuElement extends MenuElement{ + + private ItemStack itemStack; + + public CustomMenuElement(ItemStack itemStack) { + this.itemStack = itemStack; + } + + @Override + public ItemStack asItemStack() { + return itemStack; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/MenuElement.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/MenuElement.java new file mode 100644 index 00000000..aa7ed46d --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/MenuElement.java @@ -0,0 +1,9 @@ +package com.leonardobishop.quests.bukkit.menu.element; + +import org.bukkit.inventory.ItemStack; + +public abstract class MenuElement { + + public abstract ItemStack asItemStack(); + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/QuestMenuElement.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/QuestMenuElement.java new file mode 100644 index 00000000..215a93a1 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/QuestMenuElement.java @@ -0,0 +1,120 @@ +package com.leonardobishop.quests.bukkit.menu.element; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.config.BukkitQuestsConfig; +import com.leonardobishop.quests.bukkit.menu.itemstack.QItemStack; +import com.leonardobishop.quests.bukkit.util.Chat; +import com.leonardobishop.quests.common.enums.QuestStartResult; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.util.Format; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class QuestMenuElement extends MenuElement { + + private final BukkitQuestsPlugin plugin; + private final BukkitQuestsConfig config; + private final QPlayer owner; + private final String questId; + + public QuestMenuElement(BukkitQuestsPlugin plugin, QPlayer owner, String questId) { + this.plugin = plugin; + this.config = (BukkitQuestsConfig) plugin.getQuestsConfig(); + this.owner = owner; + this.questId = questId; + } + + public QPlayer getOwner() { + return owner; + } + + public String getQuestId() { + return questId; + } + + @Override + 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); + QItemStack qItemStack = plugin.getQItemStackRegistry().getQuestItemStack(quest); + + if (status == QuestStartResult.QUEST_LOCKED) { + List quests = new ArrayList<>(); + for (String requirement : quest.getRequirements()) { + Quest requirementQuest = plugin.getQuestManager().getQuestById(requirement); + if (!owner.getQuestProgressFile().hasQuestProgress(requirementQuest) || + !owner.getQuestProgressFile().getQuestProgress(requirementQuest).isCompletedBefore()) { + quests.add(Chat.strip(plugin.getQItemStackRegistry().getQuestItemStack(requirementQuest).getName())); + } + } + Map placeholders = new HashMap<>(); + placeholders.put("{quest}", Chat.strip(qItemStack.getName())); + placeholders.put("{requirements}", String.join(", ", quests)); + ItemStack is = replaceItemStack(config.getItem("gui.quest-locked-display"), placeholders); + return is; + } else if (status == QuestStartResult.QUEST_ALREADY_COMPLETED) { + Map placeholders = new HashMap<>(); + placeholders.put("{quest}", Chat.strip(qItemStack.getName())); + ItemStack is = replaceItemStack(config.getItem("gui.quest-completed-display"), placeholders); + return is; + } else if (status == QuestStartResult.QUEST_NO_PERMISSION) { + Map placeholders = new HashMap<>(); + placeholders.put("{quest}", Chat.strip(qItemStack.getName())); + ItemStack is = replaceItemStack(config.getItem("gui.quest-permission-display"), placeholders); + return is; + } else if (cooldown > 0) { + Map placeholders = new HashMap<>(); + placeholders.put("{time}", Format.formatTime(TimeUnit.SECONDS.convert(cooldown, TimeUnit.MILLISECONDS))); + placeholders.put("{quest}", Chat.strip(qItemStack.getName())); + ItemStack is = replaceItemStack(config.getItem("gui.quest-cooldown-display"), placeholders); + return is; + } else { + return replaceItemStack(qItemStack.toItemStack(quest, owner, questProgress)); + } + } + + private ItemStack replaceItemStack(ItemStack is) { + return replaceItemStack(is, Collections.emptyMap()); + } + + private ItemStack replaceItemStack(ItemStack is, Map placeholders) { + ItemStack newItemStack = is.clone(); + List lore = newItemStack.getItemMeta().getLore(); + List newLore = new ArrayList<>(); + ItemMeta ism = newItemStack.getItemMeta(); + Player player = Bukkit.getPlayer(owner.getPlayerUUID()); + if (lore != null) { + for (String s : lore) { + for (Map.Entry entry : placeholders.entrySet()) { + s = s.replace(entry.getKey(), entry.getValue()); + if (plugin.getPlaceholderAPIHook() != null && plugin.getQuestsConfig().getBoolean("options.gui-use-placeholderapi")) { + s = plugin.getPlaceholderAPIHook().replacePlaceholders(player, s); + } + } + newLore.add(s); + } + } + for (Map.Entry entry : placeholders.entrySet()) { + ism.setDisplayName(ism.getDisplayName().replace(entry.getKey(), entry.getValue())); + if (plugin.getPlaceholderAPIHook() != null && plugin.getQuestsConfig().getBoolean("options.gui-use-placeholderapi")) { + ism.setDisplayName(plugin.getPlaceholderAPIHook().replacePlaceholders(player, ism.getDisplayName())); + } + } + ism.setLore(newLore); + newItemStack.setItemMeta(ism); + return newItemStack; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/SpacerMenuElement.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/SpacerMenuElement.java new file mode 100644 index 00000000..a4c5d69a --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/element/SpacerMenuElement.java @@ -0,0 +1,15 @@ +package com.leonardobishop.quests.bukkit.menu.element; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +/** + * literally has the sole purpose of returning Material.AIR + */ +public class SpacerMenuElement extends MenuElement { + + @Override + public ItemStack asItemStack() { + return new ItemStack(Material.AIR); + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/itemstack/QItemStack.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/itemstack/QItemStack.java new file mode 100644 index 00000000..52059b29 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/itemstack/QItemStack.java @@ -0,0 +1,149 @@ +package com.leonardobishop.quests.bukkit.menu.itemstack; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.util.Chat; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.quest.Quest; +import org.bukkit.Bukkit; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class QItemStack { + + private final BukkitQuestsPlugin plugin; + + private String name; + private List loreNormal; + private List loreStarted; + private final List globalLoreAppendNormal; + private final List globalLoreAppendNotStarted; + private final List globalLoreAppendStarted; + private final List globalLoreAppendTracked; + private ItemStack startingItemStack; + + public QItemStack(BukkitQuestsPlugin plugin, String name, List loreNormal, List loreStarted, ItemStack startingItemStack) { + this.plugin = plugin; + this.name = name; + this.loreNormal = loreNormal; + this.loreStarted = loreStarted; + this.startingItemStack = startingItemStack; + + this.globalLoreAppendNormal = Chat.color(plugin.getQuestsConfig().getStringList("global-quest-display.lore.append-normal")); + this.globalLoreAppendNotStarted = Chat.color(plugin.getQuestsConfig().getStringList("global-quest-display.lore.append-not-started")); + this.globalLoreAppendStarted = Chat.color(plugin.getQuestsConfig().getStringList("global-quest-display.lore.append-started")); + this.globalLoreAppendTracked = Chat.color(plugin.getQuestsConfig().getStringList("global-quest-display.lore.append-tracked")); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getLoreNormal() { + return loreNormal; + } + + public void setLoreNormal(List loreNormal) { + this.loreNormal = loreNormal; + } + + public List getLoreStarted() { + return loreStarted; + } + + public void setLoreStarted(List loreStarted) { + this.loreStarted = loreStarted; + } + + public ItemStack getStartingItemStack() { + return startingItemStack; + } + + public void setStartingItemStack(ItemStack startingItemStack) { + this.startingItemStack = startingItemStack; + } + + @SuppressWarnings("deprecation") + public ItemStack toItemStack(Quest quest, QPlayer qPlayer, QuestProgress questProgress) { + ItemStack is = new ItemStack(startingItemStack); + ItemMeta ism = is.getItemMeta(); + ism.setDisplayName(name); + List formattedLore = new ArrayList<>(); + List tempLore = new ArrayList<>(); + + if (!plugin.getQuestsConfig().getBoolean("options.global-task-configuration-override") || globalLoreAppendNormal.isEmpty()) { + tempLore.addAll(loreNormal); + } + tempLore.addAll(globalLoreAppendNormal); + + Player player = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + if (qPlayer.hasStartedQuest(quest)) { + boolean tracked = quest.getId().equals(qPlayer.getPlayerPreferences().getTrackedQuestId()); + if (!plugin.getQuestsConfig().getBoolean("options.global-task-configuration-override")|| globalLoreAppendStarted.isEmpty()) { + tempLore.addAll(loreStarted); + } + if (tracked) { + tempLore.addAll(globalLoreAppendTracked); + } else { + tempLore.addAll(globalLoreAppendStarted); + } + ism.addEnchant(Enchantment.ARROW_INFINITE, 1, true); + try { + ism.addItemFlags(ItemFlag.HIDE_ENCHANTS); + ism.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); + } catch (Exception ignored) { + + } + } else { + tempLore.addAll(globalLoreAppendNotStarted); + } + if (plugin.getPlaceholderAPIHook() != null && plugin.getQuestsConfig().getBoolean("options.gui-use-placeholderapi")) { + ism.setDisplayName(plugin.getPlaceholderAPIHook().replacePlaceholders(player, ism.getDisplayName())); + } + if (questProgress != null) { + for (String s : tempLore) { + s = processPlaceholders(s, questProgress); + if (plugin.getPlaceholderAPIHook() != null && plugin.getQuestsConfig().getBoolean("options.gui-use-placeholderapi")) { + s = plugin.getPlaceholderAPIHook().replacePlaceholders(player, s); + } + formattedLore.add(s); + } + } + ism.setLore(formattedLore); + is.setItemMeta(ism); + return is; + } + + public static String processPlaceholders(String s, QuestProgress questProgress) { + Matcher m = Pattern.compile("\\{([^}]+)}").matcher(s); + while (m.find()) { + String[] parts = m.group(1).split(":"); + if (parts.length > 1) { + if (questProgress.getTaskProgress(parts[0]) == null) { + continue; + } + if (parts[1].equals("progress")) { + String str = String.valueOf(questProgress.getTaskProgress(parts[0]).getProgress()); + s = s.replace("{" + m.group(1) + "}", (str.equals("null") ? String.valueOf(0) : str)); + } + if (parts[1].equals("complete")) { + String str = String.valueOf(questProgress.getTaskProgress(parts[0]).isCompleted()); + s = s.replace("{" + m.group(1) + "}", str); + } + } + } + return s; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/itemstack/QItemStackRegistry.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/itemstack/QItemStackRegistry.java new file mode 100644 index 00000000..703b8d21 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/itemstack/QItemStackRegistry.java @@ -0,0 +1,36 @@ +package com.leonardobishop.quests.bukkit.menu.itemstack; + +import com.leonardobishop.quests.common.quest.Category; +import com.leonardobishop.quests.common.quest.Quest; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.Map; + +public class QItemStackRegistry { + + private final Map questRegistry = new HashMap<>(); + private final Map categoryRegistry = new HashMap<>(); + + public QItemStack getQuestItemStack(Quest quest) { + return questRegistry.get(quest.getId()); + } + + public ItemStack getCategoryItemStack(Category category) { + return categoryRegistry.get(category.getId()); + } + + public void clearRegistry() { + questRegistry.clear(); + categoryRegistry.clear(); + } + + public void register(Quest quest, QItemStack qItemStack) { + questRegistry.put(quest.getId(), qItemStack); + } + + public void register(Category quest, ItemStack itemStack) { + categoryRegistry.put(quest.getId(), itemStack); + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcompleter/BukkitQuestCompleter.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcompleter/BukkitQuestCompleter.java new file mode 100644 index 00000000..32365a17 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcompleter/BukkitQuestCompleter.java @@ -0,0 +1,106 @@ +package com.leonardobishop.quests.bukkit.questcompleter; + + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.QuestCompleter; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.LinkedList; +import java.util.Queue; + +//TODO move complete effects here ? +public class BukkitQuestCompleter implements QuestCompleter, Runnable { + + private final Queue completionQueue = new LinkedList<>(); + private final Queue fullCheckQueue = new LinkedList<>(); + private final BukkitQuestsPlugin plugin; + + public BukkitQuestCompleter(BukkitQuestsPlugin 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; + + plugin.getQuestsLogger().debug("Processing player (singular: " + questProgress.getQuestId() + ") " + qPlayer.getPlayerUUID()); + 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; + plugin.getQuestsLogger().debug("Processing player (full check) " + qPlayer.getPlayerUUID()); + 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; + } + + @Override + public void queueSingular(QuestProgress questProgress) { + completionQueue.add(questProgress); + } + + @Override + public void queueFullCheck(QuestProgressFile questProgressFile) { + fullCheckQueue.add(questProgressFile); + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/DailyQuestController.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/DailyQuestController.java new file mode 100644 index 00000000..c6e103bc --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/DailyQuestController.java @@ -0,0 +1,184 @@ +//package com.leonardobishop.quests.bukkit.questcontroller; +// +//import com.leonardobishop.quests.common.enums.QuestStartResult; +//import com.leonardobishop.quests.common.player.QPlayer; +//import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +//import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +//import com.leonardobishop.quests.common.plugin.Quests; +//import com.leonardobishop.quests.common.quest.Quest; +//import com.leonardobishop.quests.common.questcontroller.QuestController; +//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/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java new file mode 100644 index 00000000..e385ba9f --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java @@ -0,0 +1,285 @@ +package com.leonardobishop.quests.bukkit.questcontroller; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.api.event.PlayerCancelQuestEvent; +import com.leonardobishop.quests.bukkit.api.event.PlayerFinishQuestEvent; +import com.leonardobishop.quests.bukkit.api.event.PlayerStartQuestEvent; +import com.leonardobishop.quests.bukkit.api.event.PlayerStartTrackQuestEvent; +import com.leonardobishop.quests.bukkit.api.event.PlayerStopTrackQuestEvent; +import com.leonardobishop.quests.bukkit.api.event.PreStartQuestEvent; +import com.leonardobishop.quests.bukkit.config.BukkitQuestsConfig; +import com.leonardobishop.quests.bukkit.menu.itemstack.QItemStack; +import com.leonardobishop.quests.bukkit.util.Chat; +import com.leonardobishop.quests.bukkit.util.Messages; +import com.leonardobishop.quests.common.enums.QuestStartResult; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import com.leonardobishop.quests.common.questcontroller.QuestController; +import com.leonardobishop.quests.common.util.Format; +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 BukkitQuestsPlugin plugin; + private final BukkitQuestsConfig config; + + public NormalQuestController(BukkitQuestsPlugin plugin) { + this.plugin = plugin; + this.config = (BukkitQuestsConfig) plugin.getQuestsConfig(); + } + + @Override + public String getName() { + return "normal"; + } + + @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(config.getInt("options.quest-started-limit"))); + 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}", Format.formatTime(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 (config.getBoolean("options.allow-quest-track") + && config.getBoolean("options.quest-autotrack")) { + qPlayer.trackQuest(quest); + } + questProgress.setCompleted(false); + if (player != null) { + QItemStack qItemStack = plugin.getQItemStackRegistry().getQuestItemStack(quest); + String displayName = Chat.strip(qItemStack.getName()); + String questStartMessage = Messages.QUEST_START.getMessage().replace("{quest}", displayName); + // 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 (config.getBoolean("options.titles-enabled")) { + plugin.getTitleHandle().sendTitle(player, Messages.TITLE_QUEST_START_TITLE.getMessage().replace("{quest}", displayName), + Messages.TITLE_QUEST_START_SUBTITLE.getMessage().replace("{quest}", displayName)); + } + 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() >= config.getInt("options.quest-started-limit") && !config.getBoolean("options.quest-autostart")) { + 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 (config.getBoolean("options.allow-quest-track") && config.getBoolean("options.quest-autotrack") + && !(quest.isRepeatable() && !quest.isCooldownEnabled())) { + qPlayer.trackQuest(null); + } + Player player = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + if (player != null) { + QItemStack qItemStack = plugin.getQItemStackRegistry().getQuestItemStack(quest); + String displayName = Chat.strip(qItemStack.getName()); + String questFinishMessage = Messages.QUEST_COMPLETE.getMessage().replace("{quest}", displayName); + // 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 (config.getBoolean("options.titles-enabled")) { + plugin.getTitleHandle().sendTitle(player, Messages.TITLE_QUEST_COMPLETE_TITLE.getMessage().replace("{quest}", displayName), + Messages.TITLE_QUEST_COMPLETE_SUBTITLE.getMessage().replace("{quest}", displayName)); + } + for (String s : quest.getRewardString()) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', s)); + } + } + if ((config.getBoolean("options.allow-quest-track") && config.getBoolean("options.quest-autotrack") && !(quest.isRepeatable() && !quest.isCooldownEnabled())) + || (!config.getBoolean("options.allow-quest-track") && config.getBoolean("options.quest-autotrack"))) { + 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 (config.getBoolean("options.quest-autostart")) { + 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) { + QItemStack qItemStack = plugin.getQItemStackRegistry().getQuestItemStack(quest); + String displayName = Chat.strip(qItemStack.getName()); + String questCancelMessage = Messages.QUEST_CANCEL.getMessage().replace("{quest}", displayName); + // 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; + } + + @Override + public void trackQuestForPlayer(QPlayer qPlayer, Quest quest) { + Player player = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + + if (quest == null) { + String currentTrackedQuestId = qPlayer.getPlayerPreferences().getTrackedQuestId(); + qPlayer.getPlayerPreferences().setTrackedQuestId(null); + if (player != null) { + Bukkit.getPluginManager().callEvent(new PlayerStopTrackQuestEvent(player, qPlayer)); + Quest currentTrackedQuest; + if (currentTrackedQuestId != null && (currentTrackedQuest = plugin.getQuestManager().getQuestById(currentTrackedQuestId)) != null) { + QItemStack qItemStack = plugin.getQItemStackRegistry().getQuestItemStack(currentTrackedQuest); + String displayName = Chat.strip(qItemStack.getName()); + player.sendMessage(Messages.QUEST_TRACK_STOP.getMessage().replace("{quest}", displayName)); + } + } + } else if (qPlayer.hasStartedQuest(quest)) { + QItemStack qItemStack = plugin.getQItemStackRegistry().getQuestItemStack(quest); + String displayName = Chat.strip(qItemStack.getName()); + qPlayer.getPlayerPreferences().setTrackedQuestId(quest.getId()); + if (player != null) { + Bukkit.getPluginManager().callEvent(new PlayerStartTrackQuestEvent(player, qPlayer)); + player.sendMessage(Messages.QUEST_TRACK.getMessage().replace("{quest}", displayName)); + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/runnable/QuestsAutoSaveRunnable.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/runnable/QuestsAutoSaveRunnable.java new file mode 100644 index 00000000..34c1a5f6 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/runnable/QuestsAutoSaveRunnable.java @@ -0,0 +1,42 @@ +package com.leonardobishop.quests.bukkit.runnable; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +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 BukkitQuestsPlugin plugin; + + public QuestsAutoSaveRunnable(BukkitQuestsPlugin 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/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/MySqlStorageProvider.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/MySqlStorageProvider.java new file mode 100644 index 00000000..fd473af6 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/MySqlStorageProvider.java @@ -0,0 +1,276 @@ +package com.leonardobishop.quests.bukkit.storage; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.storage.StorageProvider; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Function; + +public class MySqlStorageProvider implements StorageProvider { + + private static final String CREATE_TABLE_QUEST_PROGRESS = + "CREATE TABLE IF NOT EXISTS `{prefix}quest_progress` (" + + " `uuid` VARCHAR(36) NOT NULL," + + " `quest_id` VARCHAR(50) NOT NULL," + + " `started` BOOL NOT NULL," + + " `completed` BOOL NOT NULL," + + " `completed_before` BOOL NOT NULL," + + " `completion_date` BIGINT NOT NULL," + + " PRIMARY KEY (`uuid`, `quest_id`));"; + private static final String CREATE_TABLE_TASK_PROGRESS = + "CREATE TABLE IF NOT EXISTS `{prefix}task_progress` (" + + " `uuid` VARCHAR(36) NOT NULL," + + " `quest_id` VARCHAR(50) NOT NULL," + + " `task_id` VARCHAR(50) NOT NULL," + + " `completed` BOOL NOT NULL," + + " `progress` VARCHAR(64) NULL," + + " `data_type` VARCHAR(10) NULL," + + " PRIMARY KEY (`uuid`, `quest_id`, `task_id`));"; + private static final String SELECT_PLAYER_QUEST_PROGRESS = + "SELECT quest_id, started, completed, completed_before, completion_date FROM `{prefix}quest_progress` WHERE uuid=?;"; + private static final String SELECT_PLAYER_TASK_PROGRESS = + "SELECT quest_id, task_id, completed, progress, data_type FROM `{prefix}task_progress` WHERE uuid=?;"; + private static final String SELECT_KNOWN_PLAYER_QUEST_PROGRESS = + "SELECT quest_id FROM `{prefix}quest_progress` WHERE uuid=?;"; + private static final String SELECT_KNOWN_PLAYER_TASK_PROGRESS = + "SELECT quest_id, task_id FROM `{prefix}task_progress` WHERE uuid=?;"; + private static final String WRITE_PLAYER_QUEST_PROGRESS = + "INSERT INTO `{prefix}quest_progress` (uuid, quest_id, started, completed, completed_before, completion_date) VALUES (?,?,?,?,?,?) ON DUPLICATE KEY UPDATE started=?, completed=?, completed_before=?, completion_date=?"; + private static final String WRITE_PLAYER_TASK_PROGRESS = + "INSERT INTO `{prefix}task_progress` (uuid, quest_id, task_id, completed, progress, data_type) VALUES (?,?,?,?,?,?) ON DUPLICATE KEY UPDATE completed=?, progress=?, data_type=?"; + + private final ConfigurationSection configuration; + private final BukkitQuestsPlugin plugin; + private HikariDataSource hikari; + private String prefix; + private Function statementProcessor; + private boolean fault; + + public MySqlStorageProvider(BukkitQuestsPlugin plugin, ConfigurationSection configuration) { + this.plugin = plugin; + if (configuration == null) { + configuration = new YamlConfiguration(); + } + this.configuration = configuration; + } + + @Override + public void init() { + String address = configuration.getString("network.address", "localhost:3306"); + String database = configuration.getString("network.database", "minecraft"); + String url = "jdbc:mysql://" + address + "/" + database; + + HikariConfig config = new HikariConfig(); + config.setPoolName("quests-hikari"); + + config.setUsername(configuration.getString("network.username", "root")); + config.setPassword(configuration.getString("network.password", "")); + config.setJdbcUrl(url); + config.setMaximumPoolSize(configuration.getInt("connection-pool-settings.maximum-pool-size", 8)); + config.setMinimumIdle(configuration.getInt("connection-pool-settings.minimum-idle", 8)); + config.setMaxLifetime(configuration.getInt("connection-pool-settings.maximum-lifetime", 1800000)); + config.setConnectionTimeout(configuration.getInt("connection-pool-settings.connection-timeout", 5000)); + + config.addDataSourceProperty("cachePrepStmts", true); + config.addDataSourceProperty("prepStmtCacheSize", 250); + config.addDataSourceProperty("prepStmtCacheSqlLimit", 2048); + config.addDataSourceProperty("useServerPrepStmts", true); + config.addDataSourceProperty("useLocalSessionState", true); + config.addDataSourceProperty("rewriteBatchedStatements", true); + config.addDataSourceProperty("cacheResultSetMetadata", true); + config.addDataSourceProperty("cacheServerConfiguration", true); + config.addDataSourceProperty("elideSetAutoCommits", true); + config.addDataSourceProperty("maintainTimeStats", false); + + try { + this.hikari = new HikariDataSource(config); + } catch (Exception e) { + e.printStackTrace(); + fault = true; + } + this.prefix = configuration.getString("database-settings.table-prefix", "quests_"); + this.statementProcessor = s -> s.replace("{prefix}", prefix); + try (Connection connection = hikari.getConnection()) { + try (Statement s = connection.createStatement()) { + plugin.getQuestsLogger().debug("Creating default tables"); + s.addBatch(this.statementProcessor.apply(CREATE_TABLE_QUEST_PROGRESS)); + s.addBatch(this.statementProcessor.apply(CREATE_TABLE_TASK_PROGRESS)); + + s.executeBatch(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public void shutdown() { + if (hikari != null) hikari.close(); + } + + @Override + public QuestProgressFile loadProgressFile(UUID uuid) { + if (fault) return null; + QuestProgressFile questProgressFile = new QuestProgressFile(uuid, plugin); + try (Connection connection = hikari.getConnection()) { + plugin.getQuestsLogger().debug("Querying player " + uuid); + Map questProgressMap = new HashMap<>(); + try (PreparedStatement ps = connection.prepareStatement(this.statementProcessor.apply(SELECT_PLAYER_QUEST_PROGRESS))) { + ps.setString(1, uuid.toString()); + + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + String questId = rs.getString(1); + boolean started = rs.getBoolean(2); + boolean completed = rs.getBoolean(3); + boolean completedBefore = rs.getBoolean(4); + long completionDate = rs.getLong(5); + + QuestProgress questProgress = new QuestProgress(plugin, questId, completed, completedBefore, completionDate, uuid, started); + questProgressMap.put(questId, questProgress); + } + } + } + try (PreparedStatement ps = connection.prepareStatement(this.statementProcessor.apply(SELECT_PLAYER_TASK_PROGRESS))) { + ps.setString(1, uuid.toString()); + + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + String questId = rs.getString(1); + String taskId = rs.getString(2); + boolean completed = rs.getBoolean(3); + String encodedProgress = rs.getString(4); + String type = rs.getString(5); + Object progress; + try { + if (type == null) { + progress = null; + } else if (type.equals("double")) { + progress = Double.valueOf(encodedProgress); + } else if (type.equals("float")) { + progress = Float.valueOf(encodedProgress); + } else if (type.equals("int")) { + progress = Integer.valueOf(encodedProgress); + } else { + throw new RuntimeException("unknown data type '" + type + "'"); + } + } catch (NumberFormatException ex) { + plugin.getQuestsLogger().warning("Cannot retrieve progress for task '" + + taskId + "' in quest '" + questId + "' for player " + uuid + + " since data is malformed!"); + continue; + } catch (RuntimeException ex) { + if (ex.getMessage().startsWith("unknown data type ")) { + plugin.getQuestsLogger().warning("Cannot retrieve progress for task '" + + taskId + "' in quest '" + questId + "' for player " + uuid + + ": " + ex.getMessage()); + continue; + } else { + throw ex; + } + } + + QuestProgress linkedQuestProgress = questProgressMap.get(questId); + if (linkedQuestProgress == null) continue; // lost quest progress ? + TaskProgress questProgress = new TaskProgress(linkedQuestProgress, taskId, progress, uuid, completed); + linkedQuestProgress.addTaskProgress(questProgress); + } + } + } + for (QuestProgress questProgress : questProgressMap.values()) { + questProgressFile.addQuestProgress(questProgress); + } + } catch (SQLException e) { + plugin.getQuestsLogger().severe("Failed to load player: " + uuid + "!"); + e.printStackTrace(); + return null; + } + return questProgressFile; + } + + @Override + public void saveProgressFile(UUID uuid, QuestProgressFile questProgressFile) { + if (fault) return; + try (Connection connection = hikari.getConnection()) { + try (PreparedStatement writeQuestProgress = connection.prepareStatement(this.statementProcessor.apply(WRITE_PLAYER_QUEST_PROGRESS)); + PreparedStatement writeTaskProgress = connection.prepareStatement(this.statementProcessor.apply(WRITE_PLAYER_TASK_PROGRESS))) { + + List questProgressValues = new ArrayList<>(questProgressFile.getAllQuestProgress()); + for (QuestProgress questProgress : questProgressValues) { + if (!questProgress.isModified()) continue; + + String questId = questProgress.getQuestId(); + writeQuestProgress.setString(1, uuid.toString()); + writeQuestProgress.setString(2, questProgress.getQuestId()); + writeQuestProgress.setBoolean(3, questProgress.isStarted()); + writeQuestProgress.setBoolean(4, questProgress.isCompleted()); + writeQuestProgress.setBoolean(5, questProgress.isCompletedBefore()); + writeQuestProgress.setLong(6, questProgress.getCompletionDate()); + writeQuestProgress.setBoolean(7, questProgress.isStarted()); + writeQuestProgress.setBoolean(8, questProgress.isCompleted()); + writeQuestProgress.setBoolean(9, questProgress.isCompletedBefore()); + writeQuestProgress.setLong(10, questProgress.getCompletionDate()); + writeQuestProgress.addBatch(); + + for (TaskProgress taskProgress : questProgress.getTaskProgress()) { + String taskId = taskProgress.getTaskId(); + + String encodedProgress; + Object progress = taskProgress.getProgress(); + String type; + if (progress == null) { + type = null; + encodedProgress = null; + } else if (progress instanceof Double) { + type = "double"; + encodedProgress = String.valueOf(progress); + } else if (progress instanceof Integer) { + type = "int"; + encodedProgress = String.valueOf(progress); + } else if (progress instanceof Float) { + type = "float"; + encodedProgress = String.valueOf(progress); + } else { + plugin.getQuestsLogger().warning("Cannot store progress for task '" + + taskId + "' in quest '" + questId + "' for player " + uuid + + " since type " + progress.getClass().getName() + " cannot be encoded!"); + continue; + } + writeTaskProgress.setString(1, uuid.toString()); + writeTaskProgress.setString(2, questId); + writeTaskProgress.setString(3, taskProgress.getTaskId()); + writeTaskProgress.setBoolean(4, taskProgress.isCompleted()); + writeTaskProgress.setString(5, encodedProgress); + writeTaskProgress.setString(6, type); + writeTaskProgress.setBoolean(7, taskProgress.isCompleted()); + writeTaskProgress.setString(8, encodedProgress); + writeTaskProgress.setString(9, type); + writeTaskProgress.addBatch(); + } + } + + writeQuestProgress.executeBatch(); + writeTaskProgress.executeBatch(); + } + } catch (SQLException e) { + plugin.getQuestsLogger().severe("Failed to save player: " + uuid + "!"); + e.printStackTrace(); + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/YamlStorageProvider.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/YamlStorageProvider.java new file mode 100644 index 00000000..75e271f9 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/YamlStorageProvider.java @@ -0,0 +1,138 @@ +package com.leonardobishop.quests.bukkit.storage; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.storage.StorageProvider; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + +public class YamlStorageProvider implements StorageProvider { + + private final Map locks = new ConcurrentHashMap<>(); + private BukkitQuestsPlugin plugin; + + public YamlStorageProvider(BukkitQuestsPlugin plugin) { + this.plugin = plugin; + } + + private ReentrantLock lock(UUID uuid) { + locks.putIfAbsent(uuid, new ReentrantLock()); + ReentrantLock lock = locks.get(uuid); + lock.lock(); + return lock; + } + + @Override + public void init() { + File directory = new File(plugin.getDataFolder() + File.separator + "playerdata"); + directory.mkdirs(); + } + + @Override + public void shutdown() { + // no impl + } + + public QuestProgressFile loadProgressFile(UUID uuid) { + ReentrantLock lock = lock(uuid); + QuestProgressFile questProgressFile = new QuestProgressFile(uuid, plugin); + try { + File directory = new File(plugin.getDataFolder() + File.separator + "playerdata"); + if (directory.exists() && directory.isDirectory()) { + File file = new File(plugin.getDataFolder() + File.separator + "playerdata" + File.separator + uuid.toString() + ".yml"); + if (file.exists()) { + YamlConfiguration data = YamlConfiguration.loadConfiguration(file); + plugin.getQuestsLogger().debug("Player " + uuid + " has a valid quest progress file."); + if (data.isConfigurationSection("quest-progress")) { //Same job as "isSet" + it checks if is CfgSection + for (String id : data.getConfigurationSection("quest-progress").getKeys(false)) { + boolean started = data.getBoolean("quest-progress." + id + ".started"); + boolean completed = data.getBoolean("quest-progress." + id + ".completed"); + boolean completedBefore = data.getBoolean("quest-progress." + id + ".completed-before"); + long completionDate = data.getLong("quest-progress." + id + ".completion-date"); + + QuestProgress questProgress = new QuestProgress(plugin, id, completed, completedBefore, completionDate, uuid, started, true); + + if (data.isConfigurationSection("quest-progress." + id + ".task-progress")) { + for (String taskid : data.getConfigurationSection("quest-progress." + id + ".task-progress").getKeys(false)) { + boolean taskCompleted = data.getBoolean("quest-progress." + id + ".task-progress." + taskid + ".completed"); + Object taskProgression = data.get("quest-progress." + id + ".task-progress." + taskid + ".progress"); + + TaskProgress taskProgress = new TaskProgress(questProgress, taskid, taskProgression, uuid, taskCompleted, false); + questProgress.addTaskProgress(taskProgress); + } + } + + questProgressFile.addQuestProgress(questProgress); + } + } + } else { + plugin.getQuestsLogger().debug("Player " + uuid + " does not have a quest progress file."); + } + } + } catch (Exception ex) { + plugin.getQuestsLogger().severe("Failed to load player: " + uuid + "! This WILL cause errors."); + ex.printStackTrace(); + // fuck + } finally { + lock.unlock(); + } + + return questProgressFile; + } + + public void saveProgressFile(UUID uuid, QuestProgressFile questProgressFile) { + ReentrantLock lock = lock(uuid); + try { + List questProgressValues = new ArrayList<>(questProgressFile.getAllQuestProgress()); + File directory = new File(plugin.getDataFolder() + File.separator + "playerdata"); + if (!directory.exists() && !directory.isDirectory()) { + directory.mkdirs(); + } + + File file = new File(plugin.getDataFolder() + File.separator + "playerdata" + File.separator + uuid.toString() + ".yml"); + if (!file.exists()) { + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + YamlConfiguration data = YamlConfiguration.loadConfiguration(file); + for (QuestProgress questProgress : questProgressValues) { + if (!questProgress.isModified()) continue; + data.set("quest-progress." + questProgress.getQuestId() + ".started", questProgress.isStarted()); + data.set("quest-progress." + questProgress.getQuestId() + ".completed", questProgress.isCompleted()); + data.set("quest-progress." + questProgress.getQuestId() + ".completed-before", questProgress.isCompletedBefore()); + data.set("quest-progress." + questProgress.getQuestId() + ".completion-date", questProgress.getCompletionDate()); + for (TaskProgress taskProgress : questProgress.getTaskProgress()) { + data.set("quest-progress." + questProgress.getQuestId() + ".task-progress." + taskProgress.getTaskId() + ".completed", taskProgress + .isCompleted()); + data.set("quest-progress." + questProgress.getQuestId() + ".task-progress." + taskProgress.getTaskId() + ".progress", taskProgress + .getProgress()); + } + } + + plugin.getQuestsLogger().debug("Writing player " + uuid + " to disk."); + try { + data.save(file); + plugin.getQuestsLogger().debug("Write of player " + uuid + " to disk complete."); + } catch (IOException e) { + plugin.getQuestsLogger().debug("Failed to write player: " + uuid + "!."); + e.printStackTrace(); + } + } finally { + lock.unlock(); + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/BukkitTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/BukkitTaskType.java new file mode 100644 index 00000000..81f312c7 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/BukkitTaskType.java @@ -0,0 +1,16 @@ +package com.leonardobishop.quests.bukkit.tasktype; + +import com.leonardobishop.quests.common.tasktype.TaskType; +import org.bukkit.event.Listener; + +public abstract class BukkitTaskType extends TaskType implements Listener { + + public BukkitTaskType(String type, String author, String description) { + super(type, author, description); + } + + public BukkitTaskType(String type) { + super(type); + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/BukkitTaskTypeManager.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/BukkitTaskTypeManager.java new file mode 100644 index 00000000..67c9ab7d --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/BukkitTaskTypeManager.java @@ -0,0 +1,25 @@ +package com.leonardobishop.quests.bukkit.tasktype; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.common.tasktype.TaskType; +import com.leonardobishop.quests.common.tasktype.TaskTypeManager; + +public class BukkitTaskTypeManager extends TaskTypeManager { + + private final BukkitQuestsPlugin plugin; + + public BukkitTaskTypeManager(BukkitQuestsPlugin plugin) { + super(plugin); + this.plugin = plugin; + } + + @Override + public void registerTaskType(TaskType taskType) { + if (!(taskType instanceof BukkitTaskType)) throw new RuntimeException("task type must be instance of BukkitTaskType!"); + + BukkitTaskType bukkitTaskType = (BukkitTaskType) taskType; + super.registerTaskType(taskType); + plugin.getServer().getPluginManager().registerEvents(bukkitTaskType, plugin); + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BreedingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BreedingTaskType.java new file mode 100644 index 00000000..c4d05eed --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BreedingTaskType.java @@ -0,0 +1,94 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class BreedingTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public BreedingTaskType(BukkitQuestsPlugin plugin) { + super("breeding", TaskUtils.TASK_ATTRIBUTION_STRING, "Breed a set amount of animals."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBreed(CreatureSpawnEvent e) { + if (!e.getSpawnReason().equals(SpawnReason.BREEDING)) { + return; + } + + Entity ent = e.getEntity(); + List entList = ent.getNearbyEntities(10, 10, 10); + + if (entList.isEmpty()) { + return; + } + // Check if there is a player in the list, otherwise: return. + for (Entity current : entList) { + if (current instanceof Player && !current.hasMetadata("NPC")) { + Player player = (Player) current; + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + continue; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int breedingNeeded = (int) task.getConfigValue("amount"); + int breedingProgress; + + if (taskProgress.getProgress() == null) { + breedingProgress = 0; + } else { + breedingProgress = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(breedingProgress + 1); + + if (((int) taskProgress.getProgress()) >= breedingNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BrewingCertainTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BrewingCertainTaskType.java new file mode 100644 index 00000000..aeda362c --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BrewingCertainTaskType.java @@ -0,0 +1,114 @@ +package com.leonardobishop.quests.bukkit.tasktype.type;// TODO: fix +// +//package me.fatpigsarefat.quests.quests.tasktypes.types; +// +//import Quests; +//import QPlayer; +//import QuestProgress; +//import QuestProgressFile; +//import TaskProgress; +//import Quest; +//import Task; +//import ConfigValue; +//import TaskType; +//import org.bukkit.Bukkit; +//import org.bukkit.Location; +//import org.bukkit.Material; +//import org.bukkit.entity.Player; +//import org.bukkit.event.EventHandler; +//import org.bukkit.event.EventPriority; +//import org.bukkit.event.block.Action; +//import org.bukkit.event.inventory.BrewEvent; +//import org.bukkit.event.player.PlayerInteractEvent; +//import org.bukkit.inventory.ItemStack; +// +//import java.util.ArrayList; +//import java.util.HashMap; +//import java.util.List; +//import java.util.UUID; +// +//public final class BrewingCertainTaskType extends TaskType { +// +// private List creatorConfigValues = new ArrayList<>(); +// private HashMap brewingStands = new HashMap<>(); +// +// public BrewingCertainTaskType() { +// super("brewingcertain", "fatpigsarefat", "Brew a certain type of potion."); +// this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of potions to be brewed.")); +// this.creatorConfigValues.add(new ConfigValue("potion", true, "ID of potion to be brewed.")); +// } +// +// @Override +// public List getCreatorConfigValues() { +// return creatorConfigValues; +// } +// +// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) +// public void onBlockPlace(PlayerInteractEvent event) { +// if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { +// if (event.getClickedBlock().getType() == Material.BREWING_STAND) { +// brewingStands.put(event.getClickedBlock().getLocation(), event.getPlayer().getUniqueId()); +// } +// } +// } +// +// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) +// public void onBlockPlace(BrewEvent event) { +// UUID uuid; +// if ((uuid = brewingStands.get(event.getBlock().getLocation())) != null) { +// Player player = Bukkit.getPlayer(uuid); +// +// if (player == null) { +// return; +// } +// +// QPlayer qPlayer = Quests.getPlayerManager().getPlayer(player.getUniqueId()); +// QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); +// +// for (Quest quest : super.getRegisteredQuests()) { +// if (questProgressFile.hasStartedQuest(quest)) { +// QuestProgress questProgress = questProgressFile.getQuestProgress(quest); +// +// for (Task task : quest.getTasksOfType(super.getType())) { +// TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); +// +// if (taskProgress.isCompleted()) { +// continue; +// } +// +// int potionsNeeded = (int) task.getConfigValue("amount"); +// +// int progress; +// if (taskProgress.getProgress() == null) { +// progress = 0; +// } else { +// progress = (int) taskProgress.getProgress(); +// } +// +// int potionType = (int) task.getConfigValue("potion"); +// +// ItemStack potion1 = event.getContents().getItem(0); +// if (potion1.getDurability() != potionType) { +// potion1 = null; +// } +// ItemStack potion2 = event.getContents().getItem(1); +// if (potion2.getDurability() != potionType) { +// potion2 = null; +// } +// ItemStack potion3 = event.getContents().getItem(2); +// if (potion3.getDurability() != potionType) { +// potion3 = null; +// } +// +// taskProgress.setProgress(progress + (potion1 == null ? 0 : 1) + (potion2 == null ? 0 : 1) + (potion3 == null ? 0 : 1)); +// +// if (((int) taskProgress.getProgress()) >= potionsNeeded) { +// taskProgress.setCompleted(true); +// } +// } +// } +// } +// } +// } +// +//} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BrewingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BrewingTaskType.java new file mode 100644 index 00000000..d6ede688 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BrewingTaskType.java @@ -0,0 +1,107 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.inventory.BrewEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +public final class BrewingTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + private final HashMap brewingStands = new HashMap<>(); + + public BrewingTaskType(BukkitQuestsPlugin plugin) { + super("brewing", TaskUtils.TASK_ATTRIBUTION_STRING, "Brew a potion."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(PlayerInteractEvent event) { + if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { + if (event.getClickedBlock().getType() == Material.BREWING_STAND) { + brewingStands.put(event.getClickedBlock().getLocation(), event.getPlayer().getUniqueId()); + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BrewEvent event) { + UUID uuid; + if ((uuid = brewingStands.get(event.getBlock().getLocation())) != null) { + Player player = Bukkit.getPlayer(uuid); + + if (player == null || player.hasMetadata("NPC")) { + return; + } + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int potionsNeeded = (int) task.getConfigValue("amount"); + + int progress; + if (taskProgress.getProgress() == null) { + progress = 0; + } else { + progress = (int) taskProgress.getProgress(); + } + + ItemStack potion1 = event.getContents().getItem(0); + ItemStack potion2 = event.getContents().getItem(1); + ItemStack potion3 = event.getContents().getItem(2); + + taskProgress.setProgress(progress + (potion1 == null ? 0 : 1) + (potion2 == null ? 0 : 1) + (potion3 == null ? 0 : 1)); + + if (((int) taskProgress.getProgress()) >= potionsNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BuildingCertainTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BuildingCertainTaskType.java new file mode 100644 index 00000000..550e6435 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BuildingCertainTaskType.java @@ -0,0 +1,187 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.config.ConfigProblemDescriptions; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class BuildingCertainTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public BuildingCertainTaskType(BukkitQuestsPlugin plugin) { + super("blockplacecertain", TaskUtils.TASK_ATTRIBUTION_STRING, "Place a set amount of a specific block."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + if (config.get("block") == null && config.get("blocks") == null) { + TaskUtils.configValidateExists(root + ".block", config.get("block"), problems, "block", super.getType()); + } else { + Object configBlock; + String source; + if (config.containsKey("block")) { + source = "block"; + } else { + source = "blocks"; + } + configBlock = config.get(source); + List checkBlocks = new ArrayList<>(); + if (configBlock instanceof List) { + checkBlocks.addAll((List) configBlock); + } else { + checkBlocks.add(String.valueOf(configBlock)); + } + + for (String materialName : checkBlocks) { + String[] split = materialName.split(":"); + if (Material.getMaterial(String.valueOf(split[0])) == null) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, + ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(materialName), root + "." + source)); + } + } + } + TaskUtils.configValidateBoolean(root + ".reverse-if-broken", config.get("reverse-if-broken"), problems, true,"reverse-if-broken"); + TaskUtils.configValidateBoolean(root + ".use-similar-blocks", config.get("use-similar-blocks"), problems, true,"use-similar-blocks"); + TaskUtils.configValidateInt(root + ".data", config.get("data"), problems, true,true, "data"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) { + if (event.getPlayer().hasMetadata("NPC")) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(event.getPlayer(), task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + if (matchBlock(task, event.getBlock())) { + increment(task, taskProgress, 1); + } + } + } + } + } + + // subtract if enabled + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockBreak(BlockBreakEvent event) { + if (event.getPlayer().hasMetadata("NPC")) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + if (task.getConfigValue("reverse-if-placed") != null && ((boolean) task.getConfigValue("reverse-if-placed"))) { + if (matchBlock(task, event.getBlock())) { + increment(task, taskProgress, -1); + } + } + } + } + } + } + + @SuppressWarnings("deprecation") + private boolean matchBlock(Task task, Block block) { + Material material; + + Object configBlock = task.getConfigValues().containsKey("block") ? task.getConfigValue("block") : task.getConfigValue("blocks"); + Object configData = task.getConfigValue("data"); + Object configSimilarBlocks = task.getConfigValue("use-similar-blocks"); + + List checkBlocks = new ArrayList<>(); + if (configBlock instanceof List) { + checkBlocks.addAll((List) configBlock); + } else { + checkBlocks.add(String.valueOf(configBlock)); + } + + for (String materialName : checkBlocks) { + // LOG:1 LOG:2 LOG should all be supported with this + String[] split = materialName.split(":"); + int comparableData = 0; + if (configData != null) { + comparableData = (int) configData; + } + if (split.length > 1) { + comparableData = Integer.parseInt(split[1]); + } + + material = Material.getMaterial(String.valueOf(split[0])); + Material blockType = block.getType(); + + short blockData = block.getData(); + + if (blockType == material) { + if (((split.length == 1 && configData == null) || ((int) blockData) == comparableData)) + return true; + } + } + return false; + } + + private void increment(Task task, TaskProgress taskProgress, int amount) { + int brokenBlocksNeeded = (int) task.getConfigValue("amount"); + + int progressBlocksBroken; + if (taskProgress.getProgress() == null) { + progressBlocksBroken = 0; + } else { + progressBlocksBroken = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressBlocksBroken + amount); + + if (((int) taskProgress.getProgress()) >= brokenBlocksNeeded) { + taskProgress.setCompleted(true); + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BuildingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BuildingTaskType.java new file mode 100644 index 00000000..fe0e3ee7 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BuildingTaskType.java @@ -0,0 +1,78 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockPlaceEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class BuildingTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public BuildingTaskType(BukkitQuestsPlugin plugin) { + super("blockplace", TaskUtils.TASK_ATTRIBUTION_STRING, "Place a set amount of blocks."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) { + if (event.getPlayer().hasMetadata("NPC")) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(event.getPlayer(), task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int brokenBlocksNeeded = (int) task.getConfigValue("amount"); + + int progressBlocksBroken; + if (taskProgress.getProgress() == null) { + progressBlocksBroken = 0; + } else { + progressBlocksBroken = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressBlocksBroken + 1); + + if (((int) taskProgress.getProgress()) >= brokenBlocksNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/CommandTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/CommandTaskType.java new file mode 100644 index 00000000..db44f8d6 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/CommandTaskType.java @@ -0,0 +1,91 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class CommandTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public CommandTaskType(BukkitQuestsPlugin plugin) { + super("command", TaskUtils.TASK_ATTRIBUTION_STRING, "Execute a certain command."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".command", config.get("command"), problems, "command", super.getType()); + TaskUtils.configValidateBoolean(root + ".ignore-case", config.get("ignore-case"), problems, true, "ignore-case", super.getType()); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onCommand(PlayerCommandPreprocessEvent e) { + if (e.getPlayer().hasMetadata("NPC")) return; + + Player player = e.getPlayer(); + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + Object configCommand = task.getConfigValue("command"); + Object configIgnoreCase = task.getConfigValue("ignore-case"); + + List commands = new ArrayList<>(); + if (configCommand instanceof List) { + commands.addAll((List) configCommand); + } else { + commands.add(String.valueOf(configCommand)); + } + + boolean ignoreCasing = false; + if (configIgnoreCase != null) { + ignoreCasing = (boolean) task.getConfigValue("ignore-case"); + } + String message = e.getMessage(); + if (message.length() >= 1) { + message = message.substring(1); + } + + for (String command : commands) { + if (ignoreCasing && command.equalsIgnoreCase(message)) { + taskProgress.setCompleted(true); + } else if (!ignoreCasing && command.equals(message)) { + taskProgress.setCompleted(true); + } + } + } + } + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DealDamageTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DealDamageTaskType.java new file mode 100644 index 00000000..950a50ad --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DealDamageTaskType.java @@ -0,0 +1,86 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageByEntityEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class DealDamageTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public DealDamageTaskType(BukkitQuestsPlugin plugin) { + super("dealdamage", TaskUtils.TASK_ATTRIBUTION_STRING, "Deal a certain amount of damage."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onDamage(EntityDamageByEntityEvent e) { + if (!(e.getDamager() instanceof Player)) { + return; + } + + Player player = (Player) e.getDamager(); + double damage = e.getDamage(); + + if (player.hasMetadata("NPC")) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + double progressDamage; + int damageNeeded = (int) task.getConfigValue("amount"); + + if (taskProgress.getProgress() == null) { + progressDamage = 0.0; + } else { + progressDamage = (double) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressDamage + damage); + + if (((double) taskProgress.getProgress()) >= (double) damageNeeded) { + taskProgress.setProgress(damageNeeded); + taskProgress.setCompleted(true); + } + } + } + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DistancefromTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DistancefromTaskType.java new file mode 100644 index 00000000..b0b4b9e9 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DistancefromTaskType.java @@ -0,0 +1,108 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerMoveEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class DistancefromTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public DistancefromTaskType(BukkitQuestsPlugin plugin) { + super("distancefrom", TaskUtils.TASK_ATTRIBUTION_STRING, "Distance yourself from a set of co-ordinates."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".x", config.get("x"), problems, "x", super.getType())) + TaskUtils.configValidateInt(root + ".x", config.get("x"), problems, false, false, "x"); + if (TaskUtils.configValidateExists(root + ".y", config.get("y"), problems, "y", super.getType())) + TaskUtils.configValidateInt(root + ".y", config.get("y"), problems, false, false, "y"); + if (TaskUtils.configValidateExists(root + ".z", config.get("z"), problems, "z", super.getType())) + TaskUtils.configValidateInt(root + ".z", config.get("z"), problems, false, false, "z"); + if (TaskUtils.configValidateExists(root + ".distance", config.get("distance"), problems, "distance", super.getType())) + TaskUtils.configValidateInt(root + ".distance", config.get("distance"), problems, false, true, "distance"); + return problems; + } + +// private HashMap> distanceSquaredCache = new HashMap<>(); +// +// @Override +// public void onReady() { +// distanceSquaredCache.clear(); +// for (Quest quest : super.getRegisteredQuests()) { +// HashMap squaredDistances = new HashMap<>(); +// for (Task task : quest.getTasksOfType(super.getType())) { +// int distance = (int) task.getConfigValue("distance"); +// squaredDistances.put(task.getId(), distance); +// } +// distanceSquaredCache.put(quest.getId(), squaredDistances); +// } +// } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMove(PlayerMoveEvent event) { + if (event.getFrom().getBlockX() == event.getTo().getBlockX() && event.getFrom().getBlockZ() == event.getTo().getBlockZ()) { + return; + } + + if (event.getPlayer().hasMetadata("NPC")) return; + Player player = event.getPlayer(); + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int x = (int) task.getConfigValue("x"); + int y = (int) task.getConfigValue("y"); + int z = (int) task.getConfigValue("z"); + String worldString = (String) task.getConfigValue("world"); + int distance = (int) task.getConfigValue("distance"); + int distanceSquared = distance * distance; + + World world = Bukkit.getWorld(worldString); + if (world == null) { + continue; + } + + Location location = new Location(world, x, y, z); + if (player.getWorld().equals(world) && player.getLocation().distanceSquared(location) > distanceSquared) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/EnchantingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/EnchantingTaskType.java new file mode 100644 index 00000000..5293960f --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/EnchantingTaskType.java @@ -0,0 +1,80 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.enchantment.EnchantItemEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class EnchantingTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public EnchantingTaskType(BukkitQuestsPlugin plugin) { + super("enchanting", TaskUtils.TASK_ATTRIBUTION_STRING, "Enchant a certain amount of items."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onEnchant(EnchantItemEvent e) { + if (e.getEnchanter().hasMetadata("NPC")) return; + + Player player = e.getEnchanter(); + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int enchantsNeeded = (int) task.getConfigValue("amount"); + + int progressEnchant; + if (taskProgress.getProgress() == null) { + progressEnchant = 0; + } else { + progressEnchant = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressEnchant + 1); + + if (((int) taskProgress.getProgress()) >= enchantsNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/ExpEarnTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/ExpEarnTaskType.java new file mode 100644 index 00000000..81653d86 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/ExpEarnTaskType.java @@ -0,0 +1,78 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerExpChangeEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class ExpEarnTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public ExpEarnTaskType(BukkitQuestsPlugin plugin) { + super("expearn", TaskUtils.TASK_ATTRIBUTION_STRING, "Earn a set amount of exp."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onExpEarn(PlayerExpChangeEvent e) { + if (e.getPlayer().hasMetadata("NPC")) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(e.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(e.getPlayer(), task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + int amount = e.getAmount(); + int expNeeded = (int) task.getConfigValue("amount"); + + int progressExp; + if (taskProgress.getProgress() == null) { + progressExp = 0; + } else { + progressExp = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressExp + amount); + + if (((int) taskProgress.getProgress()) >= expNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/FarmingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/FarmingTaskType.java new file mode 100644 index 00000000..cdc92930 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/FarmingTaskType.java @@ -0,0 +1,85 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.material.Crops; + +public final class FarmingTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public FarmingTaskType(BukkitQuestsPlugin plugin) { + super("farming", TaskUtils.TASK_ATTRIBUTION_STRING, "Break a set amount of a crop."); + this.plugin = plugin; + } + + @SuppressWarnings("deprecation") + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockBreak(BlockBreakEvent event) { + //TODO: finish this + if (!(event.getBlock().getState() instanceof Crops)) { + return; + } + Crops crop = (Crops) event.getBlock().getState(); + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(event.getPlayer(), task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + Material material; + Object configBlock = task.getConfigValue("block"); + Object configData = task.getConfigValue("data"); + + material = Material.matchMaterial(String.valueOf(configBlock)); + + + if (material != null && event.getBlock().getType().equals(material)) { + + if (configData != null && (((int) event.getBlock().getData()) != ((int) configData))) { + continue; + } + int brokenBlocksNeeded = (int) task.getConfigValue("amount"); + + int progressBlocksBroken; + if (taskProgress.getProgress() == null) { + progressBlocksBroken = 0; + } else { + progressBlocksBroken = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressBlocksBroken + 1); + + if (((int) taskProgress.getProgress()) >= brokenBlocksNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/FishingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/FishingTaskType.java new file mode 100644 index 00000000..bbaa59c7 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/FishingTaskType.java @@ -0,0 +1,90 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerFishEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class FishingTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public FishingTaskType(BukkitQuestsPlugin plugin) { + super("fishing", TaskUtils.TASK_ATTRIBUTION_STRING, "Catch a set amount of items from the sea."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onFishCaught(PlayerFishEvent event) { + if (event.getPlayer().hasMetadata("NPC")) return; + + if (event.getState() != PlayerFishEvent.State.CAUGHT_FISH) { + return; + } + +// Location hookLocation = event.getHook().getLocation().add(0, -1, 0); +// if (!(hookLocation.getBlock().getType() == Material.WATER)) { +// return; +// } + + Player player = event.getPlayer(); + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int catchesNeeded = (int) task.getConfigValue("amount"); + + int progressCatches; + if (taskProgress.getProgress() == null) { + progressCatches = 0; + } else { + progressCatches = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressCatches + 1); + + if (((int) taskProgress.getProgress()) >= catchesNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/InventoryTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/InventoryTaskType.java new file mode 100644 index 00000000..55df10de --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/InventoryTaskType.java @@ -0,0 +1,168 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.config.ConfigProblemDescriptions; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class InventoryTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public InventoryTaskType(BukkitQuestsPlugin plugin) { + super("inventory", TaskUtils.TASK_ATTRIBUTION_STRING, "Obtain a set of items."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".item", config.get("item"), problems, "item", super.getType())) { + Object configBlock = config.get("item"); + if (configBlock instanceof ConfigurationSection) { + ConfigurationSection section = (ConfigurationSection) configBlock; + String itemloc = "item"; + if (!section.contains("item")) { + itemloc = "type"; + } + if (!section.contains(itemloc)) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, + ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(""), root + ".item.type")); + } else { + String type = String.valueOf(section.get(itemloc)); + if (!plugin.getItemGetter().isValidMaterial(type)) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, + ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(type), root + ".item." + itemloc)); + } + } + } else { + if (Material.getMaterial(String.valueOf(configBlock)) == null) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, + ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(String.valueOf(configBlock)), root + ".item.item")); + } + } + } + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + TaskUtils.configValidateInt(root + ".data", config.get("data"), problems, true, false, "data"); + TaskUtils.configValidateBoolean(root + ".remove-items-when-complete", config.get("remove-items-when-complete"), problems, true, "remove-items-when-complete", super.getType()); + TaskUtils.configValidateBoolean(root + ".update-progress", config.get("update-progress"), problems, true, "update-progress", super.getType()); + return problems; + } + + @SuppressWarnings("deprecation") + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onItemPickup(PlayerPickupItemEvent event) { + if (event.getPlayer().hasMetadata("NPC")) return; + + Bukkit.getScheduler().runTaskLater(plugin, () -> this.checkInventory(event.getPlayer()), 1L); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onInventoryClick(InventoryCloseEvent event) { + Bukkit.getScheduler().runTaskLater(plugin, () -> checkInventory((Player) event.getPlayer()), 1L); //Still some work to do as it doesn't really work + } + + @SuppressWarnings("deprecation") + private void checkInventory(Player player) { + if (player == null || !player.isOnline()) { + return; + } + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + Material material; + int amount = (int) task.getConfigValue("amount"); + Object configBlock = task.getConfigValue("item"); + Object configData = task.getConfigValue("data"); + Object remove = task.getConfigValue("remove-items-when-complete"); + + ItemStack is; + if (configBlock instanceof ConfigurationSection) { + is = plugin.getItemStack("", (ConfigurationSection) configBlock); + } else { + material = Material.getMaterial(String.valueOf(configBlock)); + + if (material == null) { + continue; + } + if (configData != null) { + is = new ItemStack(material, 1, ((Integer) configData).shortValue()); + } else { + is = new ItemStack(material, 1); + } + } + + if (task.getConfigValue("update-progress") != null + && (Boolean) task.getConfigValue("update-progress")) { + int inInv = getAmount(player, is, amount); + if (taskProgress.getProgress() != null && (int) taskProgress.getProgress() != inInv) { + taskProgress.setProgress(inInv); + } else if (taskProgress.getProgress() == null) { + taskProgress.setProgress(inInv); + } + } + + if (player.getInventory().containsAtLeast(is, amount)) { + is.setAmount(amount); + taskProgress.setCompleted(true); + + if (remove != null && ((Boolean) remove)) { + player.getInventory().removeItem(is); + } + } + } + } + } + } + + private int getAmount(Player player, ItemStack is, int max) { + if (is == null) { + return 0; + } + int amount = 0; + for (int i = 0; i < 36; i++) { + ItemStack slot = player.getInventory().getItem(i); + if (slot == null || !slot.isSimilar(is)) + continue; + amount += slot.getAmount(); + } + return Math.min(amount, max); + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MilkingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MilkingTaskType.java new file mode 100644 index 00000000..79dc975b --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MilkingTaskType.java @@ -0,0 +1,91 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.Material; +import org.bukkit.entity.Cow; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerInteractEntityEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class MilkingTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public MilkingTaskType(BukkitQuestsPlugin plugin) { + super("milking", TaskUtils.TASK_ATTRIBUTION_STRING, "Milk a set amount of cows."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @SuppressWarnings("deprecation") + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMilk(PlayerInteractEntityEvent event) { + if (!(event.getRightClicked() instanceof Cow) || (event.getPlayer().getItemInHand().getType() != Material.BUCKET)) { + return; + } + + if (event.getPlayer().hasMetadata("NPC")) return; + + Player player = event.getPlayer(); + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int cowsNeeded = (int) task.getConfigValue("amount"); + + int progressMilked; + if (taskProgress.getProgress() == null) { + progressMilked = 0; + } else { + progressMilked = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressMilked + 1); + + if (((int) taskProgress.getProgress()) >= cowsNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MiningCertainTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MiningCertainTaskType.java new file mode 100644 index 00000000..9c881f01 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MiningCertainTaskType.java @@ -0,0 +1,195 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.config.ConfigProblemDescriptions; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class MiningCertainTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public MiningCertainTaskType(BukkitQuestsPlugin plugin) { + super("blockbreakcertain", TaskUtils.TASK_ATTRIBUTION_STRING, "Break a set amount of a specific block."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + if (config.get("block") == null && config.get("blocks") == null) { + TaskUtils.configValidateExists(root + ".block", config.get("block"), problems, "block", super.getType()); + } else { + Object configBlock; + String source; + if (config.containsKey("block")) { + source = "block"; + } else { + source = "blocks"; + } + configBlock = config.get(source); + List checkBlocks = new ArrayList<>(); + if (configBlock instanceof List) { + checkBlocks.addAll((List) configBlock); + } else { + checkBlocks.add(String.valueOf(configBlock)); + } + + for (String materialName : checkBlocks) { + String[] split = materialName.split(":"); + if (Material.getMaterial(String.valueOf(split[0])) == null) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, + ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(materialName), root + "." + source)); + } + } + } + TaskUtils.configValidateBoolean(root + ".reverse-if-broken", config.get("reverse-if-broken"), problems, true,"reverse-if-broken"); + TaskUtils.configValidateBoolean(root + ".check-coreprotect", config.get("check-coreprotect"), problems, true,"check-coreprotect"); + TaskUtils.configValidateInt(root + ".check-coreprotect-time", config.get("check-coreprotect-time"), problems, true,true, "check-coreprotect-time"); + TaskUtils.configValidateBoolean(root + ".use-similar-blocks", config.get("use-similar-blocks"), problems, true,"use-similar-blocks"); + TaskUtils.configValidateInt(root + ".data", config.get("data"), problems, true,true, "data"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockBreak(BlockBreakEvent event) { + if (event.getPlayer().hasMetadata("NPC")) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(event.getPlayer(), task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + if (matchBlock(task, event.getBlock())) { + boolean coreProtectEnabled = (boolean) task.getConfigValue("check-coreprotect", false); + int coreProtectTime = (int) task.getConfigValue("check-coreprotect-time", 3600); + + if (coreProtectEnabled && plugin.getCoreProtectHook().checkBlock(event.getBlock(), coreProtectTime)) { + continue; + } + increment(task, taskProgress, 1); + } + } + } + } + } + + // subtract if enabled + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) { + if (event.getPlayer().hasMetadata("NPC")) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + if (task.getConfigValue("reverse-if-placed") != null && ((boolean) task.getConfigValue("reverse-if-placed"))) { + if (matchBlock(task, event.getBlock())) { + increment(task, taskProgress, -1); + } + } + } + } + } + } + + @SuppressWarnings("deprecation") + private boolean matchBlock(Task task, Block block) { + Material material; + + Object configBlock = task.getConfigValues().containsKey("block") ? task.getConfigValue("block") : task.getConfigValue("blocks"); + Object configData = task.getConfigValue("data"); + Object configSimilarBlocks = task.getConfigValue("use-similar-blocks"); + + List checkBlocks = new ArrayList<>(); + if (configBlock instanceof List) { + checkBlocks.addAll((List) configBlock); + } else { + checkBlocks.add(String.valueOf(configBlock)); + } + + for (String materialName : checkBlocks) { + // LOG:1 LOG:2 LOG should all be supported with this + String[] split = materialName.split(":"); + int comparableData = 0; + if (configData != null) { + comparableData = (int) configData; + } + if (split.length > 1) { + comparableData = Integer.parseInt(split[1]); + } + + material = Material.getMaterial(String.valueOf(split[0])); + Material blockType = block.getType(); + + short blockData = block.getData(); + + if (blockType == material) { + if (((split.length == 1 && configData == null) || ((int) blockData) == comparableData)) + return true; + } + } + return false; + } + + private void increment(Task task, TaskProgress taskProgress, int amount) { + int brokenBlocksNeeded = (int) task.getConfigValue("amount"); + + int progressBlocksBroken; + if (taskProgress.getProgress() == null) { + progressBlocksBroken = 0; + } else { + progressBlocksBroken = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressBlocksBroken + amount); + + if (((int) taskProgress.getProgress()) >= brokenBlocksNeeded) { + taskProgress.setCompleted(true); + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MiningTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MiningTaskType.java new file mode 100644 index 00000000..519cf87a --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MiningTaskType.java @@ -0,0 +1,79 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockBreakEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class MiningTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public MiningTaskType(BukkitQuestsPlugin plugin) { + // type, author, description + super("blockbreak", TaskUtils.TASK_ATTRIBUTION_STRING, "Break a set amount of blocks."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockBreak(BlockBreakEvent event) { + if (event.getPlayer().hasMetadata("NPC")) return; // citizens also causes these events to fire + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); // get the qplayer so you can get their progress + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { // iterate through all quests which are registered to use this task type + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { // get all tasks of this type + if (!TaskUtils.validateWorld(event.getPlayer(), task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); // get the task progress and increment progress by 1 + + if (taskProgress.isCompleted()) { // dont need to increment a completed task + continue; + } + + int brokenBlocksNeeded = (int) task.getConfigValue("amount"); // this will retrieve a value from the config under the key "value" + + int progressBlocksBroken; + if (taskProgress.getProgress() == null) { // note: if the player has never progressed before, getProgress() will return null + progressBlocksBroken = 0; + } else { + progressBlocksBroken = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressBlocksBroken + 1); // the progress does not have to be an int, although must be serializable by the yaml provider + + if (((int) taskProgress.getProgress()) >= brokenBlocksNeeded) { // completion statement, if true the task is complete + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingCertainTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingCertainTaskType.java new file mode 100644 index 00000000..1dca3e8b --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingCertainTaskType.java @@ -0,0 +1,137 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.config.ConfigProblemDescriptions; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.ChatColor; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDeathEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class MobkillingCertainTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public MobkillingCertainTaskType(BukkitQuestsPlugin plugin) { + super("mobkillingcertain", TaskUtils.TASK_ATTRIBUTION_STRING, "Kill a set amount of a specific entity type."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".mob", config.get("mob"), problems, "mob", super.getType())) { + try { + EntityType.valueOf(String.valueOf(config.get("mob"))); + } catch (IllegalArgumentException ex) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, + ConfigProblemDescriptions.UNKNOWN_ENTITY_TYPE.getDescription(String.valueOf(config.get("mob"))), root + ".mob")); + } + } + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMobKill(EntityDeathEvent event) { + Player killer = event.getEntity().getKiller(); + Entity mob = event.getEntity(); + + if (mob == null || mob instanceof Player) { + return; + } + + if (killer == null) { + return; + } + + if (killer.hasMetadata("NPC")) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(killer.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(killer, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + String configEntity = (String) task.getConfigValue("mob"); + + EntityType entity; + try { + entity = EntityType.valueOf(configEntity); + } catch (IllegalArgumentException ex) { + continue; + } + + Object configName = task.getConfigValues().containsKey("name") ? task.getConfigValue("name") : task.getConfigValue("names"); + + if (configName != null) { + List configNames = new ArrayList<>(); + if (configName instanceof List) { + configNames.addAll((List) configName); + } else { + configNames.add(String.valueOf(configName)); + } + + boolean validName = false; + for (String name : configNames) { + name = ChatColor.translateAlternateColorCodes('&', name); + if (mob.getCustomName() == null || !mob.getCustomName().equals(name)) { + validName = true; + break; + } + } + + if (!validName) continue; + } + + if (mob.getType() != entity) { + continue; + } + + int mobKillsNeeded = (int) task.getConfigValue("amount"); + + int progressKills; + if (taskProgress.getProgress() == null) { + progressKills = 0; + } else { + progressKills = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressKills + 1); + + if (((int) taskProgress.getProgress()) >= mobKillsNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingTaskType.java new file mode 100644 index 00000000..c1dfbe2a --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingTaskType.java @@ -0,0 +1,109 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.entity.Animals; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDeathEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class MobkillingTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public MobkillingTaskType(BukkitQuestsPlugin plugin) { + super("mobkilling", TaskUtils.TASK_ATTRIBUTION_STRING, "Kill a set amount of entities."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + TaskUtils.configValidateBoolean(root + ".hostile", config.get("hostile"), problems, true, "hostile"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMobKill(EntityDeathEvent event) { + Player killer = event.getEntity().getKiller(); //The killer is a player + Entity mob = event.getEntity(); + + if (mob == null || mob instanceof Player) { + return; + } + + if (killer == null) { + return; + } + + if (killer.hasMetadata("NPC")) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(killer.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(killer, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + boolean hostilitySpecified = false; + boolean hostile = false; + if (task.getConfigValue("hostile") != null) { + hostilitySpecified = true; + hostile = (boolean) task.getConfigValue("hostile"); + } + + if (hostilitySpecified) { + if (!hostile && !(mob instanceof Animals)) { + continue; + } else if (hostile && !(mob instanceof Monster)) { + continue; + } + } + + int mobKillsNeeded = (int) task.getConfigValue("amount"); + + int progressKills; + if (taskProgress.getProgress() == null) { + progressKills = 0; + } else { + progressKills = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressKills + 1); + + if (((int) taskProgress.getProgress()) >= mobKillsNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PermissionTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PermissionTaskType.java new file mode 100644 index 00000000..33dc0db9 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PermissionTaskType.java @@ -0,0 +1,65 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; + +public final class PermissionTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + private BukkitTask poll; + + public PermissionTaskType(BukkitQuestsPlugin plugin) { + super("permission", TaskUtils.TASK_ATTRIBUTION_STRING, "Test if a player has a permission"); + this.plugin = plugin; + } + + @Override + public void onReady() { + this.poll = new BukkitRunnable() { + @Override + public void run() { + for (Player player : Bukkit.getOnlinePlayers()) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + continue; + } + for (Quest quest : PermissionTaskType.super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + for (Task task : quest.getTasksOfType(PermissionTaskType.super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + if (taskProgress.isCompleted()) { + continue; + } + String permission = (String) task.getConfigValue("permission"); + if (permission != null) { + if (player.hasPermission(permission)) { + taskProgress.setCompleted(true); + } + } + } + } + } + } + } + }.runTaskTimer(plugin, 30L, 30L); + } + + @Override + public void onDisable() { + if (this.poll != null) { + this.poll.cancel(); + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PlayerkillingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PlayerkillingTaskType.java new file mode 100644 index 00000000..db9fda8b --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PlayerkillingTaskType.java @@ -0,0 +1,91 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDeathEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class PlayerkillingTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public PlayerkillingTaskType(BukkitQuestsPlugin plugin) { + super("playerkilling", TaskUtils.TASK_ATTRIBUTION_STRING, "Kill a set amount of players."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMobKill(EntityDeathEvent event) { + Player killer = event.getEntity().getKiller(); + Entity mob = event.getEntity(); + + if (!(mob instanceof Player)) { + return; + } + + if (killer == null) { + return; + } + + if (killer.hasMetadata("NPC")) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(killer.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(killer, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int playerKillsNeeded = (int) task.getConfigValue("amount"); + + int progressKills; + if (taskProgress.getProgress() == null) { + progressKills = 0; + } else { + progressKills = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressKills + 1); + + if (((int) taskProgress.getProgress()) >= playerKillsNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PlaytimeTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PlaytimeTaskType.java new file mode 100644 index 00000000..28ecced4 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PlaytimeTaskType.java @@ -0,0 +1,87 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class PlaytimeTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + private BukkitTask poll; + + public PlaytimeTaskType(BukkitQuestsPlugin plugin) { + super("playtime", TaskUtils.TASK_ATTRIBUTION_STRING, "Track the amount of playing time a user has been on"); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".minutes", config.get("minutes"), problems, "minutes", super.getType())) + TaskUtils.configValidateInt(root + ".minutes", config.get("minutes"), problems, false, true, "minutes"); + return problems; + } + + + @Override + public void onReady() { + if (this.poll == null) { + this.poll = new BukkitRunnable() { + @Override + public void run() { + for (Player player : Bukkit.getOnlinePlayers()) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + continue; + } + + for (Quest quest : PlaytimeTaskType.super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + for (Task task : quest.getTasksOfType(PlaytimeTaskType.super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + if (taskProgress.isCompleted()) { + continue; + } + int minutes = (int) task.getConfigValue("minutes"); + if (taskProgress.getProgress() == null) { + taskProgress.setProgress(1); + } else { + taskProgress.setProgress((int) taskProgress.getProgress() + 1); + } + if (((int) taskProgress.getProgress()) >= minutes) { + taskProgress.setCompleted(true); + } + } + } + } + } + } + }.runTaskTimer(plugin, 1200L, 1200L); + } + } + + @Override + public void onDisable() { +// if (this.poll != null) { +// this.poll.cancel(); +// } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PositionTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PositionTaskType.java new file mode 100644 index 00000000..876081ae --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/PositionTaskType.java @@ -0,0 +1,98 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerMoveEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class PositionTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public PositionTaskType(BukkitQuestsPlugin plugin) { + super("position", TaskUtils.TASK_ATTRIBUTION_STRING, "Reach a set of co-ordinates."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".world", config.get("world"), problems, "world", super.getType()); + if (TaskUtils.configValidateExists(root + ".x", config.get("x"), problems, "x", super.getType())) + TaskUtils.configValidateInt(root + ".x", config.get("x"), problems, false, false, "x"); + if (TaskUtils.configValidateExists(root + ".y", config.get("y"), problems, "y", super.getType())) + TaskUtils.configValidateInt(root + ".y", config.get("y"), problems, false, false, "y"); + if (TaskUtils.configValidateExists(root + ".z", config.get("z"), problems, "z", super.getType())) + TaskUtils.configValidateInt(root + ".z", config.get("z"), problems, false, false, "z"); + TaskUtils.configValidateInt(root + ".distance-padding", config.get("distance-padding"), problems, true, true, "distance-padding"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMove(PlayerMoveEvent event) { + if (event.getFrom().getBlockX() == event.getTo().getBlockX() && event.getFrom().getBlockZ() == event.getTo().getBlockZ()) { + return; + } + + if (event.getPlayer().hasMetadata("NPC")) return; + + Player player = event.getPlayer(); + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int x = (int) task.getConfigValue("x"); + int y = (int) task.getConfigValue("y"); + int z = (int) task.getConfigValue("z"); + String worldString = (String) task.getConfigValue("world"); + int padding = 0; + if (task.getConfigValue("distance-padding") != null) { + padding = (int) task.getConfigValue("distance-padding"); + } + int paddingSquared = padding * padding; + World world = Bukkit.getWorld(worldString); + if (world == null) { + continue; + } + + Location location = new Location(world, x, y, z); + if (player.getWorld().equals(world) && player.getLocation().getBlockX() == location.getBlockX() && player.getLocation().getBlockY() == location.getBlockY() && player.getLocation().getBlockZ() == location.getBlockZ()) { + taskProgress.setCompleted(true); + } else if (padding != 0 && player.getWorld().equals(world) && player.getLocation().distanceSquared(location) < paddingSquared) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/ShearingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/ShearingTaskType.java new file mode 100644 index 00000000..6778ae69 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/ShearingTaskType.java @@ -0,0 +1,86 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.entity.Player; +import org.bukkit.entity.Sheep; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerShearEntityEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class ShearingTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public ShearingTaskType(BukkitQuestsPlugin plugin) { + super("shearing", TaskUtils.TASK_ATTRIBUTION_STRING, "Shear a set amount of sheep."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onShear(PlayerShearEntityEvent event) { + if (!(event.getEntity() instanceof Sheep)) { + return; + } + + if (event.getPlayer().hasMetadata("NPC")) return; + + Player player = event.getPlayer(); + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int sheepNeeded = (int) task.getConfigValue("amount"); + + int progressSheared; + if (taskProgress.getProgress() == null) { + progressSheared = 0; + } else { + progressSheared = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressSheared + 1); + + if (((int) taskProgress.getProgress()) >= sheepNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/TamingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/TamingTaskType.java new file mode 100644 index 00000000..7555e60c --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/TamingTaskType.java @@ -0,0 +1,85 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityTameEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class TamingTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public TamingTaskType(BukkitQuestsPlugin plugin) { + super("taming", TaskUtils.TASK_ATTRIBUTION_STRING, "Tame a set amount of animals."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onTame(EntityTameEvent event) { + if (!(event.getOwner() instanceof Player)) { + return; + } + + Player player = (Player) event.getOwner(); + + if (player.hasMetadata("NPC")) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int tamesNeeded = (int) task.getConfigValue("amount"); + + int progressTamed; + if (taskProgress.getProgress() == null) { + progressTamed = 0; + } else { + progressTamed = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressTamed + 1); + + if (((int) taskProgress.getProgress()) >= tamesNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/WalkingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/WalkingTaskType.java new file mode 100644 index 00000000..cc0db63d --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/WalkingTaskType.java @@ -0,0 +1,85 @@ +package com.leonardobishop.quests.bukkit.tasktype.type; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerMoveEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class WalkingTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public WalkingTaskType(BukkitQuestsPlugin plugin) { + super("walking", TaskUtils.TASK_ATTRIBUTION_STRING, "Walk a set distance."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".distance", config.get("distance"), problems, "distance", super.getType())) + TaskUtils.configValidateInt(root + ".distance", config.get("distance"), problems, false, true, "distance"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMove(PlayerMoveEvent event) { + if (event.getFrom().getBlockX() == event.getTo().getBlockX() && event.getFrom().getBlockZ() == event.getTo().getBlockZ()) { + return; + } + + Player player = event.getPlayer(); + + if (player.hasMetadata("NPC")) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int distanceNeeded = (int) task.getConfigValue("distance"); + + int progressDistance; + if (taskProgress.getProgress() == null) { + progressDistance = 0; + } else { + progressDistance = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressDistance + 1); + + if (((int) taskProgress.getProgress()) >= distanceNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/ASkyBlockLevelTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/ASkyBlockLevelTaskType.java new file mode 100644 index 00000000..3953a95f --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/ASkyBlockLevelTaskType.java @@ -0,0 +1,66 @@ +package com.leonardobishop.quests.bukkit.tasktype.type.dependent; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import com.wasteofplastic.askyblock.events.IslandPostLevelEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class ASkyBlockLevelTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public ASkyBlockLevelTaskType(BukkitQuestsPlugin plugin) { + super("askyblock_level", TaskUtils.TASK_ATTRIBUTION_STRING, "Reach a certain island level for ASkyBlock."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".level", config.get("level"), problems, "level", super.getType())) + TaskUtils.configValidateInt(root + ".level", config.get("level"), problems, false, false, "level"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onIslandLevel(IslandPostLevelEvent event) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + long islandLevelNeeded = (long) (int) task.getConfigValue("level"); + + taskProgress.setProgress(event.getLongLevel()); + + if (((long) taskProgress.getProgress()) >= islandLevelNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/BentoBoxLevelTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/BentoBoxLevelTaskType.java new file mode 100644 index 00000000..ba662166 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/BentoBoxLevelTaskType.java @@ -0,0 +1,100 @@ +package com.leonardobishop.quests.bukkit.tasktype.type.dependent; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import com.leonardobishop.quests.common.tasktype.TaskTypeManager; +import org.bukkit.event.EventHandler; +import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.api.events.BentoBoxEvent; +import world.bentobox.bentobox.database.objects.Island; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; + +public final class BentoBoxLevelTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + private Field levelField = null; + + public BentoBoxLevelTaskType(BukkitQuestsPlugin plugin) { + super("bentobox_level", TaskUtils.TASK_ATTRIBUTION_STRING, "Reach a certain island level in the level addon for BentoBox."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".level", config.get("level"), problems, "level", super.getType())) + TaskUtils.configValidateInt(root + ".level", config.get("level"), problems, false, false, "level"); + return problems; + } + + + public static void register(BukkitQuestsPlugin plugin, TaskTypeManager manager) { + if (BentoBox.getInstance().getAddonsManager().getAddonByName("Level").isPresent()) { + manager.registerTaskType(new BentoBoxLevelTaskType(plugin)); + } + } + + @EventHandler + public void onBentoBoxIslandLevelCalculated(BentoBoxEvent event) { + Map keyValues = event.getKeyValues(); + + if ("IslandLevelCalculatedEvent".equalsIgnoreCase(event.getEventName())) { + Island island = (Island) keyValues.get("island"); + + for (UUID member : island.getMemberSet()) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(member); + if (qPlayer == null) { + continue; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + long islandLevelNeeded = (long) (int) task.getConfigValue("level"); + + Object results = keyValues.get("results"); + + try { + if (levelField == null) { + levelField = results.getClass().getDeclaredField("level"); + levelField.setAccessible(true); + } + + AtomicLong level = (AtomicLong) levelField.get(results); + taskProgress.setProgress(level.get()); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + + if (((long) taskProgress.getProgress()) >= islandLevelNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/CitizensDeliverTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/CitizensDeliverTaskType.java new file mode 100644 index 00000000..cc4aafa4 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/CitizensDeliverTaskType.java @@ -0,0 +1,138 @@ +package com.leonardobishop.quests.bukkit.tasktype.type.dependent; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.config.ConfigProblemDescriptions; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import net.citizensnpcs.api.event.NPCRightClickEvent; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class CitizensDeliverTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public CitizensDeliverTaskType(BukkitQuestsPlugin plugin) { + super("citizens_deliver", TaskUtils.TASK_ATTRIBUTION_STRING, "Deliver a set of items to a NPC."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".item", config.get("item"), problems, "item", super.getType())) { + Object configBlock = config.get("item"); + if (configBlock instanceof ConfigurationSection) { + ConfigurationSection section = (ConfigurationSection) configBlock; + String itemloc = "item"; + if (!section.contains("item")) { + itemloc = "type"; + } + if (!section.contains(itemloc)) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, + ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(""), root + ".item.type")); + } else { + String type = String.valueOf(section.get(itemloc)); + if (!plugin.getItemGetter().isValidMaterial(type)) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, + ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(type), root + ".item." + itemloc)); + } + } + } else { + if (Material.getMaterial(String.valueOf(configBlock)) == null) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, + ConfigProblemDescriptions.UNKNOWN_MATERIAL.getDescription(String.valueOf(configBlock)), root + ".item.item")); + } + } + } + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + TaskUtils.configValidateExists(root + ".npc-name", config.get("npc-name"), problems, "npc-name", super.getType()); + TaskUtils.configValidateBoolean(root + ".remove-items-when-complete", config.get("remove-items-when-complete"), problems, true, "remove-items-when-complete", super.getType()); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onNPCClick(NPCRightClickEvent event) { + Bukkit.getScheduler().runTaskLater(plugin, () -> checkInventory(event.getClicker(), event.getNPC().getName()), 1L); + } + + @SuppressWarnings("deprecation") + private void checkInventory(Player player, String citizenName) { + if (player == null || !player.isOnline()) { + return; + } + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', String.valueOf(task.getConfigValue("npc-name")))).equals(ChatColor + .stripColor(ChatColor.translateAlternateColorCodes('&', citizenName)))) { + return; + } + if (!TaskUtils.validateWorld(player, task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + Material material; + int amount = (int) task.getConfigValue("amount"); + Object configBlock = task.getConfigValue("item"); + Object configData = task.getConfigValue("data"); + Object remove = task.getConfigValue("remove-items-when-complete"); + + ItemStack is; + if (configBlock instanceof ConfigurationSection) { + is = plugin.getItemStack("", (ConfigurationSection) configBlock); + } else { + material = Material.getMaterial(String.valueOf(configBlock)); + + if (material == null) { + continue; + } + if (configData != null) { + is = new ItemStack(material, 1, ((Integer) configData).shortValue()); + } else { + is = new ItemStack(material, 1); + } + } + + if (player.getInventory().containsAtLeast(is, amount)) { + is.setAmount(amount); + taskProgress.setCompleted(true); + + if (remove != null && ((Boolean) remove)) { + player.getInventory().removeItem(is); + } + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/CitizensInteractTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/CitizensInteractTaskType.java new file mode 100644 index 00000000..5c6e6be2 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/CitizensInteractTaskType.java @@ -0,0 +1,68 @@ +package com.leonardobishop.quests.bukkit.tasktype.type.dependent; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import net.citizensnpcs.api.event.NPCRightClickEvent; +import org.bukkit.ChatColor; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class CitizensInteractTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public CitizensInteractTaskType(BukkitQuestsPlugin plugin) { + super("citizens_interact", TaskUtils.TASK_ATTRIBUTION_STRING, "Interact with an NPC to complete the quest."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".npc-name", config.get("npc-name"), problems, "npc-name", super.getType()); + TaskUtils.configValidateBoolean(root + ".remove-items-when-complete", config.get("remove-items-when-complete"), problems, true, "remove-items-when-complete", super.getType()); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onNPCClick(NPCRightClickEvent event) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getClicker().getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(event.getClicker(), task)) continue; + + if (!ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', String.valueOf(task.getConfigValue("npc-name")))).equals(ChatColor + .stripColor(ChatColor.translateAlternateColorCodes('&', event.getNPC().getName())))) { + return; + } + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + taskProgress.setCompleted(true); + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/EssentialsBalanceTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/EssentialsBalanceTaskType.java new file mode 100644 index 00000000..f207a499 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/EssentialsBalanceTaskType.java @@ -0,0 +1,95 @@ +package com.leonardobishop.quests.bukkit.tasktype.type.dependent; + +import com.earth2me.essentials.Essentials; +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import net.ess3.api.events.UserBalanceUpdateEvent; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +public class EssentialsBalanceTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public EssentialsBalanceTaskType(BukkitQuestsPlugin plugin) { + super("essentials_balance", TaskUtils.TASK_ATTRIBUTION_STRING, "Reach a set amount of money."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, false, "amount"); + return problems; + } + + @Override + public void onStart(Quest quest, Task task, UUID playerUUID) { + Player player = Bukkit.getPlayer(playerUUID); + Essentials ess = (Essentials) Bukkit.getPluginManager().getPlugin("Essentials"); + if (player != null && player.isOnline() && ess != null) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(playerUUID); + if (qPlayer == null) { + return; + } + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + QuestProgress questProgress = questProgressFile.getQuestProgress(quest); + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + int earningsNeeded = (int) task.getConfigValue("amount"); + BigDecimal money = ess.getUser(player).getMoney(); + taskProgress.setProgress(money); + if (money.compareTo(BigDecimal.valueOf(earningsNeeded)) > 0) { + taskProgress.setCompleted(true); + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMoneyEarn(UserBalanceUpdateEvent event) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int earningsNeeded = (int) task.getConfigValue("amount"); + + taskProgress.setProgress(event.getNewBalance()); + + if (event.getNewBalance().compareTo(BigDecimal.valueOf(earningsNeeded)) > 0) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/EssentialsMoneyEarnTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/EssentialsMoneyEarnTaskType.java new file mode 100644 index 00000000..5f4c2a0e --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/EssentialsMoneyEarnTaskType.java @@ -0,0 +1,73 @@ +package com.leonardobishop.quests.bukkit.tasktype.type.dependent; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import net.ess3.api.events.UserBalanceUpdateEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class EssentialsMoneyEarnTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public EssentialsMoneyEarnTaskType(BukkitQuestsPlugin plugin) { + super("essentials_moneyearn", TaskUtils.TASK_ATTRIBUTION_STRING, "Earn a set amount of money."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, false, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMoneyEarn(UserBalanceUpdateEvent event) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + int earningsNeeded = (int) task.getConfigValue("amount"); + + BigDecimal current = (BigDecimal) taskProgress.getProgress(); + if (current == null) { + current = new BigDecimal(0); + } + BigDecimal newProgress = current.add(event.getNewBalance().subtract(event.getOldBalance())); + taskProgress.setProgress(newProgress); + + if (newProgress.compareTo(BigDecimal.valueOf(earningsNeeded)) > 0) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/IridiumSkyblockValueType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/IridiumSkyblockValueType.java new file mode 100644 index 00000000..35934250 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/IridiumSkyblockValueType.java @@ -0,0 +1,87 @@ +//package com.leonardobishop.quests.bukkit.tasktype.type.dependent; +// +//import com.iridium.iridiumskyblock.Island; +//import com.iridium.iridiumskyblock.api.IslandWorthCalculatedEvent; +//import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +//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; +//import com.leonardobishop.quests.player.questprogressfile.TaskProgress; +//import com.leonardobishop.quests.quest.Quest; +//import com.leonardobishop.quests.quest.Task; +//import com.leonardobishop.quests.tasktype.ConfigValue; +//import com.leonardobishop.quests.tasktype.TaskType; +//import com.leonardobishop.quests.tasktype.TaskUtils; +//import org.bukkit.event.EventHandler; +//import org.bukkit.event.EventPriority; +// +//import java.util.ArrayList; +//import java.util.HashMap; +//import java.util.List; +//import java.util.UUID; +// +//TODO update to latest ver +//public final class IridiumSkyblockValueType extends BukkitTaskType { +// +// private List creatorConfigValues = new ArrayList<>(); +// +// public IridiumSkyblockValueType() { +// super("iridiumskyblock_value", TaskUtils.TASK_ATTRIBUTION_STRING, "Reach a certain island value for Iridium Skyblock."); +// this.creatorConfigValues.add(new ConfigValue("value", true, "Minimum island value needed.")); +// } +// +// @Override +// public List detectProblemsInConfig(String root, HashMap config) { +// ArrayList problems = new ArrayList<>(); +// if (TaskUtils.configValidateExists(root + ".value", config.get("value"), problems, "value", super.getType())) +// TaskUtils.configValidateInt(root + ".value", config.get("value"), problems, false, false, "value"); +// return problems; +// } +// +// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) +// public void onIslandLevel(IslandWorthCalculatedEvent event) { +// Island island = event.getIsland(); +// for (String player : island.members) { +// UUID uuid; +// try { +// uuid = UUID.fromString(player); +// } catch (Exception e) { +// continue; +// } +// QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(uuid); +// if (qPlayer == null) { +// continue; +// } +// +// for (Quest quest : IridiumSkyblockValueType.super.getRegisteredQuests()) { +// if (qPlayer.hasStartedQuest(quest)) { +// QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); +// +// for (Task task : quest.getTasksOfType(IridiumSkyblockValueType.super.getType())) { +// TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); +// +// if (taskProgress.isCompleted()) { +// continue; +// } +// +// int islandValueNeeded = (int) task.getConfigValue("value"); +// +// taskProgress.setProgress(event.getIslandWorth()); +// +// if (((double) taskProgress.getProgress()) >= islandValueNeeded) { +// taskProgress.setCompleted(true); +// } +// } +// } +// } +// } +// +// } +// +// @Override +// public List getCreatorConfigValues() { +// return creatorConfigValues; +// } +// +//} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/MythicMobsKillingType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/MythicMobsKillingType.java new file mode 100644 index 00000000..1e4ede3e --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/MythicMobsKillingType.java @@ -0,0 +1,107 @@ +package com.leonardobishop.quests.bukkit.tasktype.type.dependent; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import io.lumine.xikage.mythicmobs.api.bukkit.events.MythicMobDeathEvent; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class MythicMobsKillingType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public MythicMobsKillingType(BukkitQuestsPlugin plugin) { + super("mythicmobs_killing", TaskUtils.TASK_ATTRIBUTION_STRING, "Kill a set amount of a MythicMobs entity."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".name", config.get("name"), problems, "name", super.getType()); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + TaskUtils.configValidateInt(root + ".level", config.get("level"), problems, true, true, "level"); + TaskUtils.configValidateInt(root + ".min-level", config.get("min-level"), problems, true, true, "min-level"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMobKill(MythicMobDeathEvent event) { + Entity killer = event.getKiller(); + Entity mob = event.getEntity(); + + if (mob == null || mob instanceof Player) { + return; + } + + if (killer == null) { + return; + } + + String mobName = event.getMobType().getInternalName(); + double level = event.getMobLevel(); + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(killer.getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(killer.getWorld().getName(), task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + String configName = (String) task.getConfigValue("name"); + int minMobLevel = (int) task.getConfigValue("min-level", -1); + int requiredLevel = (int) task.getConfigValue("level", -1); + + if (!mobName.equals(configName) || level < minMobLevel) { + return; + } + + if (requiredLevel != -1 && level != requiredLevel) { + return; + } + + int mobKillsNeeded = (int) task.getConfigValue("amount"); + + int progressKills; + if (taskProgress.getProgress() == null) { + progressKills = 0; + } else { + progressKills = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressKills + 1); + + if (((int) taskProgress.getProgress()) >= mobKillsNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/PlaceholderAPIEvaluateTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/PlaceholderAPIEvaluateTaskType.java new file mode 100644 index 00000000..fed42bf4 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/PlaceholderAPIEvaluateTaskType.java @@ -0,0 +1,151 @@ +package com.leonardobishop.quests.bukkit.tasktype.type.dependent; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import me.clip.placeholderapi.PlaceholderAPI; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class PlaceholderAPIEvaluateTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + private BukkitTask poll; + + public PlaceholderAPIEvaluateTaskType(BukkitQuestsPlugin plugin) { + super("placeholderapi_evaluate", TaskUtils.TASK_ATTRIBUTION_STRING, "Evaluate the result of a placeholder"); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".placeholder", config.get("placeholder"), problems, "placeholder", super.getType()); + boolean evalExists = TaskUtils.configValidateExists(root + ".evaluates", config.get("evaluates"), problems, "evaluates", super.getType()); + + if (config.containsKey("operator")) { + String operatorStr = (String) config.get("operator"); + Operator operator = null; + try { + operator = Operator.valueOf(operatorStr); + } catch (IllegalArgumentException ex) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, + "Operator '" + operatorStr + "' does not exist.", root + ".operator")); + } + if (operator != null && evalExists) { + String evalStr = String.valueOf(config.get("evaluates")); + try { + Double.parseDouble(evalStr); + } catch (IllegalArgumentException ex) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.WARNING, + "Numeric operator specified, but placeholder evaluation '" + evalStr + "' is not numeric.", root + ".evaluates")); + } + } + } + return problems; + } + + @Override + public void onReady() { + this.poll = new BukkitRunnable() { + @Override + public void run() { + for (Player player : Bukkit.getOnlinePlayers()) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + continue; + } + + for (Quest quest : PlaceholderAPIEvaluateTaskType.super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + for (Task task : quest.getTasksOfType(PlaceholderAPIEvaluateTaskType.super.getType())) { + if (!TaskUtils.validateWorld(player, task)) continue; + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + if (taskProgress.isCompleted()) { + continue; + } + String placeholder = (String) task.getConfigValue("placeholder"); + String evaluates = String.valueOf(task.getConfigValue("evaluates")); + String configOperator = (String) task.getConfigValue("operator"); + Operator operator = null; + if (configOperator != null) { + try { + operator = Operator.valueOf(configOperator); + } catch (IllegalArgumentException ignored) { } + } + if (placeholder != null && evaluates != null) { + double numericEvaluates = 0; + if (operator != null) { + try { + numericEvaluates = Double.parseDouble(evaluates); + } catch (NumberFormatException ex) { + continue; + } + } + + String evaluated = PlaceholderAPI.setPlaceholders(player, placeholder); + if (operator == null && evaluated.equals(evaluates)) { + taskProgress.setCompleted(true); + } else if (operator != null) { + double numericEvaluated; + try { + numericEvaluated = Double.parseDouble(evaluated); + } catch (NumberFormatException ex) { + continue; + } + switch (operator) { + case GREATER_THAN: + if (numericEvaluated > numericEvaluates) + taskProgress.setCompleted(true); + continue; + case LESS_THAN: + if (numericEvaluated < numericEvaluates) + taskProgress.setCompleted(true); + continue; + case GREATER_THAN_OR_EQUAL_TO: + if (numericEvaluated >= numericEvaluates) + taskProgress.setCompleted(true); + continue; + case LESS_THAN_OR_EQUAL_TO: + if (numericEvaluated <= numericEvaluates) + taskProgress.setCompleted(true); + continue; + } + } + } + + } + } + } + } + } + }.runTaskTimer(plugin, 30L, 30L); + } + + @Override + public void onDisable() { + if (this.poll != null) { + this.poll.cancel(); + } + } + + enum Operator { + GREATER_THAN, + LESS_THAN, + GREATER_THAN_OR_EQUAL_TO, + LESS_THAN_OR_EQUAL_TO; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/ShopGUIPlusBuyCertainTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/ShopGUIPlusBuyCertainTaskType.java new file mode 100644 index 00000000..c7944232 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/ShopGUIPlusBuyCertainTaskType.java @@ -0,0 +1,85 @@ +package com.leonardobishop.quests.bukkit.tasktype.type.dependent; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import net.brcdev.shopgui.event.ShopPreTransactionEvent; +import net.brcdev.shopgui.shop.ShopManager; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class ShopGUIPlusBuyCertainTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public ShopGUIPlusBuyCertainTaskType(BukkitQuestsPlugin plugin) { + super("shopguiplus_buycertain", TaskUtils.TASK_ATTRIBUTION_STRING, "Purchase a given item from a ShopGUI+ shop"); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, false, "amount"); + TaskUtils.configValidateExists(root + ".id", config.get("id"), problems, "id", super.getType()); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMobKill(ShopPreTransactionEvent event) { + if (event.getShopAction() != ShopManager.ShopAction.BUY) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(event.getPlayer().getWorld().getName(), task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + String configName = (String) task.getConfigValue("id"); + + if (!event.getShopItem().getId().equals(configName)) { + return; + } + + int amountNeeded = (int) task.getConfigValue("amount"); + + int progressAmount; + if (taskProgress.getProgress() == null) { + progressAmount = 0; + } else { + progressAmount = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressAmount + event.getAmount()); + + if (((int) taskProgress.getProgress()) >= amountNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/ShopGUIPlusSellCertainTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/ShopGUIPlusSellCertainTaskType.java new file mode 100644 index 00000000..9b2ba441 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/ShopGUIPlusSellCertainTaskType.java @@ -0,0 +1,85 @@ +package com.leonardobishop.quests.bukkit.tasktype.type.dependent; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import net.brcdev.shopgui.event.ShopPreTransactionEvent; +import net.brcdev.shopgui.shop.ShopManager; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class ShopGUIPlusSellCertainTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public ShopGUIPlusSellCertainTaskType(BukkitQuestsPlugin plugin) { + super("shopguiplus_sellcertain", TaskUtils.TASK_ATTRIBUTION_STRING, "Sell a given item from to a ShopGUI+ shop"); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, false, "amount"); + TaskUtils.configValidateExists(root + ".id", config.get("id"), problems, "id", super.getType()); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMobKill(ShopPreTransactionEvent event) { + if (event.getShopAction() != ShopManager.ShopAction.SELL || event.getShopAction() != ShopManager.ShopAction.SELL_ALL) return; + + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + if (!TaskUtils.validateWorld(event.getPlayer().getWorld().getName(), task)) continue; + + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + String configName = (String) task.getConfigValue("id"); + + if (!event.getShopItem().getId().equals(configName)) { + return; + } + + int amountNeeded = (int) task.getConfigValue("amount"); + + int progressAmount; + if (taskProgress.getProgress() == null) { + progressAmount = 0; + } else { + progressAmount = (int) taskProgress.getProgress(); + } + + taskProgress.setProgress(progressAmount + event.getAmount()); + + if (((int) taskProgress.getProgress()) >= amountNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/uSkyBlockLevelTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/uSkyBlockLevelTaskType.java new file mode 100644 index 00000000..ac093522 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/uSkyBlockLevelTaskType.java @@ -0,0 +1,67 @@ +package com.leonardobishop.quests.bukkit.tasktype.type.dependent; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType; +import com.leonardobishop.quests.bukkit.util.TaskUtils; +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import us.talabrek.ultimateskyblock.api.event.uSkyBlockScoreChangedEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class uSkyBlockLevelTaskType extends BukkitTaskType { + + private final BukkitQuestsPlugin plugin; + + public uSkyBlockLevelTaskType(BukkitQuestsPlugin plugin) { + super("uskyblock_level", TaskUtils.TASK_ATTRIBUTION_STRING, "Reach a certain island level for uSkyBlock."); + this.plugin = plugin; + } + + @Override + public List validateConfig(String root, HashMap config) { + ArrayList problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".level", config.get("level"), problems, "level", super.getType())) + TaskUtils.configValidateInt(root + ".level", config.get("level"), problems, false, false, "level"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onIslandLevel(uSkyBlockScoreChangedEvent event) { + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + for (Quest quest : super.getRegisteredQuests()) { + if (qPlayer.hasStartedQuest(quest)) { + QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + double islandLevelNeeded = (double) (int) task.getConfigValue("level"); + + taskProgress.setProgress(event.getScore().getScore()); + + if (((double) taskProgress.getProgress()) >= islandLevelNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/Chat.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/Chat.java new file mode 100644 index 00000000..36fe0d2d --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/Chat.java @@ -0,0 +1,40 @@ +package com.leonardobishop.quests.bukkit.util; + +import com.leonardobishop.quests.common.config.ConfigProblem; +import org.bukkit.ChatColor; + +import java.util.ArrayList; +import java.util.List; + +public class Chat { + + public static String color(String s) { + return ChatColor.translateAlternateColorCodes('&', s); + } + + public static List color(List s) { + if (s == null || s.size() == 0) return s; + + List colored = new ArrayList<>(); + for (String line : s) { + colored.add(ChatColor.translateAlternateColorCodes('&', line)); + } + return colored; + } + + public static String strip(String s) { + return ChatColor.stripColor(s); + } + + public static ChatColor matchConfigProblemToColor(ConfigProblem.ConfigProblemType configProblem) { + switch (configProblem) { + case ERROR: + return ChatColor.RED; + case WARNING: + return ChatColor.YELLOW; + default: + return ChatColor.WHITE; + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/MenuUtils.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/MenuUtils.java new file mode 100644 index 00000000..2cce530f --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/MenuUtils.java @@ -0,0 +1,74 @@ +package com.leonardobishop.quests.bukkit.util; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import com.leonardobishop.quests.bukkit.menu.CancelQMenu; +import com.leonardobishop.quests.bukkit.menu.MenuController; +import com.leonardobishop.quests.bukkit.menu.QMenu; +import com.leonardobishop.quests.common.quest.Quest; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class MenuUtils { + + public static ItemStack applyPlaceholders(BukkitQuestsPlugin plugin, UUID owner, ItemStack is) { + return applyPlaceholders(plugin, owner, is, Collections.emptyMap()); + } + + public static ItemStack applyPlaceholders(BukkitQuestsPlugin plugin, UUID owner, ItemStack is, Map placeholders) { + ItemStack newItemStack = is.clone(); + List lore = newItemStack.getItemMeta().getLore(); + List newLore = new ArrayList<>(); + ItemMeta ism = newItemStack.getItemMeta(); + Player player = Bukkit.getPlayer(owner); + if (lore != null) { + for (String s : lore) { + for (Map.Entry entry : placeholders.entrySet()) { + s = s.replace(entry.getKey(), entry.getValue()); + if (plugin.getPlaceholderAPIHook() != null && plugin.getQuestsConfig().getBoolean("options.gui-use-placeholderapi")) { + s = plugin.getPlaceholderAPIHook().replacePlaceholders(player, s); + } + } + newLore.add(s); + } + } + for (Map.Entry entry : placeholders.entrySet()) { + ism.setDisplayName(ism.getDisplayName().replace(entry.getKey(), entry.getValue())); + if (plugin.getPlaceholderAPIHook() != null && plugin.getQuestsConfig().getBoolean("options.gui-use-placeholderapi")) { + ism.setDisplayName(plugin.getPlaceholderAPIHook().replacePlaceholders(player, ism.getDisplayName())); + } + } + ism.setLore(newLore); + newItemStack.setItemMeta(ism); + return newItemStack; + } + + public static void handleMiddleClick(BukkitQuestsPlugin plugin, QMenu menu, Quest quest, Player player, MenuController controller) { + if (menu.getOwner().hasStartedQuest(quest)) { + String tracked = menu.getOwner().getPlayerPreferences().getTrackedQuestId(); + + if (quest.getId().equals(tracked)) { + menu.getOwner().trackQuest(null); + } else { + menu.getOwner().trackQuest(quest); + } + player.closeInventory(); + } + } + + public static void handleRightClick(BukkitQuestsPlugin plugin, QMenu menu, Quest quest, Player player, MenuController controller) { + if (menu.getOwner().hasStartedQuest(quest)) { + if (plugin.getQuestsConfig().getBoolean("options.allow-quest-cancel")) return; + CancelQMenu cancelQMenu = new CancelQMenu(plugin, menu, menu.getOwner(), quest); + controller.openMenu(player, cancelQMenu, 1); + } + } + +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/Messages.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/Messages.java new file mode 100644 index 00000000..be99920e --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/Messages.java @@ -0,0 +1,83 @@ +package com.leonardobishop.quests.bukkit.util; + +import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; +import org.bukkit.ChatColor; + +//TODO refactor this +public enum Messages { + + TIME_FORMAT("messages.time-format"), + QUEST_START("messages.quest-start"), + QUEST_COMPLETE("messages.quest-complete"), + QUEST_CANCEL("messages.quest-cancel"), + QUEST_TRACK("messages.quest-track"), + QUEST_TRACK_STOP("messages.quest-track-stop"), + QUEST_RANDOM_NONE("messages.quest-random-none"), + QUEST_START_LIMIT("messages.quest-start-limit"), + QUEST_START_DISABLED("messages.quest-start-disabled"), + QUEST_START_LOCKED("messages.quest-start-locked"), + QUEST_START_COOLDOWN("messages.quest-start-cooldown"), + QUEST_START_STARTED("messages.quest-start-started"), + QUEST_START_PERMISSION("messages.quest-start-permission"), + QUEST_CATEGORY_QUEST_PERMISSION("messages.quest-category-quest-permission"), + QUEST_CATEGORY_PERMISSION("messages.quest-category-permission"), + QUEST_CANCEL_NOTSTARTED("messages.quest-cancel-notstarted"), + QUEST_UPDATER("messages.quest-updater"), + COMMAND_DATA_NOT_LOADED("messages.command-data-not-loaded"), + COMMAND_SUB_DOESNTEXIST("messages.command-sub-doesntexist"), + COMMAND_QUEST_START_DOESNTEXIST("messages.command-quest-start-doesntexist"), + COMMAND_QUEST_GENERAL_DOESNTEXIST("messages.command-quest-general-doesntexist"), + COMMAND_QUEST_OPENCATEGORY_ADMIN_SUCCESS("messages.command-quest-opencategory-admin-success"), + COMMAND_QUEST_OPENQUESTS_ADMIN_SUCCESS("messages.command-quest-openquests-admin-success"), + COMMAND_QUEST_ADMIN_PLAYERNOTFOUND("messages.command-quest-admin-playernotfound"), + COMMAND_CATEGORY_OPEN_DOESNTEXIST("messages.command-category-open-doesntexist"), + COMMAND_CATEGORY_OPEN_DISABLED("messages.command-category-open-disabled"), + COMMAND_QUEST_START_ADMIN_SUCCESS("messages.command-quest-start-admin-success"), + COMMAND_TASKVIEW_ADMIN_FAIL("messages.command-taskview-admin-fail"), + COMMAND_QUEST_START_ADMIN_FAIL("messages.command-quest-start-admin-fail"), + TITLE_QUEST_START_TITLE("titles.quest-start.title"), + TITLE_QUEST_START_SUBTITLE("titles.quest-start.subtitle"), + TITLE_QUEST_COMPLETE_TITLE("titles.quest-complete.title"), + TITLE_QUEST_COMPLETE_SUBTITLE("titles.quest-complete.subtitle"), + BETA_REMINDER("messages.beta-reminder"), + COMMAND_QUEST_ADMIN_LOADDATA("messages.command-quest-admin-loaddata"), + COMMAND_QUEST_ADMIN_NODATA("messages.command-quest-admin-nodata"), + COMMAND_QUEST_ADMIN_CLEAN_SUCCESS("messages.command-quest-admin-clean-success"), + COMMAND_QUEST_ADMIN_CLEAN_FAIL("messages.command-quest-admin-clean-fail"), + COMMAND_QUEST_ADMIN_FULLRESET("messages.command-quest-admin-fullreset"), + COMMAND_QUEST_ADMIN_START_FAILLOCKED("messages.command-quest-admin-start-faillocked"), + COMMAND_QUEST_ADMIN_START_FAILCOOLDOWN("messages.command-quest-admin-start-failcooldown"), + COMMAND_QUEST_ADMIN_START_FAILCOMPLETE("messages.command-quest-admin-start-failcomplete"), + COMMAND_QUEST_ADMIN_START_FAILLIMIT("messages.command-quest-admin-start-faillimit"), + COMMAND_QUEST_ADMIN_START_FAILSTARTED("messages.command-quest-admin-start-failstarted"), + COMMAND_QUEST_ADMIN_START_FAILPERMISSION("messages.command-quest-admin-start-failpermission"), + COMMAND_QUEST_ADMIN_START_FAILCATEGORY("messages.command-quest-admin-start-failpermission"), + COMMAND_QUEST_ADMIN_START_FAILCATEGORYPERMISSION("messages.command-quest-admin-start-failcategorypermission"), + COMMAND_QUEST_ADMIN_START_FAILOTHER("messages.command-quest-admin-start-failother"), + COMMAND_QUEST_ADMIN_START_SUCCESS("messages.command-quest-admin-start-success"), + COMMAND_QUEST_ADMIN_CATEGORY_PERMISSION("messages.command-quest-admin-category-permission"), + COMMAND_QUEST_ADMIN_COMPLETE_SUCCESS("messages.command-quest-admin-complete-success"), + COMMAND_QUEST_ADMIN_RESET_SUCCESS("messages.command-quest-admin-reset-success"); + + private static BukkitQuestsPlugin plugin; + + private final String path; + + Messages(String path) { + this.path = path; + } + + public static void setPlugin(BukkitQuestsPlugin plugin) { + Messages.plugin = plugin; + } + + public String getMessage() { + if (plugin.getConfig().contains(path)) { + String message = plugin.getQuestsConfig().getString(path); + if (message != null) { + return ChatColor.translateAlternateColorCodes('&', message); + } + } + return path; + } +} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/TaskUtils.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/TaskUtils.java new file mode 100644 index 00000000..ce930639 --- /dev/null +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/TaskUtils.java @@ -0,0 +1,90 @@ +package com.leonardobishop.quests.bukkit.util; + +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.config.ConfigProblemDescriptions; +import com.leonardobishop.quests.common.quest.Task; +import org.bukkit.entity.Player; + +import java.util.List; + +public class TaskUtils { + + public static String TASK_ATTRIBUTION_STRING = ""; + + public static boolean validateWorld(Player player, Task task) { + return validateWorld(player.getLocation().getWorld().getName(), task.getConfigValue("worlds")); + } + + public static boolean validateWorld(String worldName, Task task) { + return validateWorld(worldName, task.getConfigValue("worlds")); + } + + public static boolean validateWorld(String worldName, Object configurationData) { + if (configurationData == null) { + return true; + } + + if (configurationData instanceof List) { + List allowedWorlds = (List) configurationData; + if (!allowedWorlds.isEmpty() && allowedWorlds.get(0) instanceof String) { + List allowedWorldNames = (List) allowedWorlds; + return allowedWorldNames.contains(worldName); + } + return true; + } + + if (configurationData instanceof String) { + String allowedWorld = (String) configurationData; + return worldName.equals(allowedWorld); + } + + return true; + } + + public static void configValidateInt(String path, Object object, List problems, boolean allowNull, boolean greaterThanZero, String... args) { + if (object == null) { + if (!allowNull) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.ERROR, + String.format("Expected an integer for '%s', but got null instead", (Object[]) args), path)); + } + return; + } + + try { + Integer i = (Integer) object; + if (greaterThanZero && i <= 0) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.ERROR, + String.format("Value for field '%s' must be greater than 0", (Object[]) args), path)); + } + } catch (ClassCastException ex) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.ERROR, + String.format("Expected an integer for '%s', but got '" + object + "' instead", (Object[]) args), path)); + } + } + + public static void configValidateBoolean(String path, Object object, List problems, boolean allowNull, String... args) { + if (object == null) { + if (!allowNull) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.ERROR, + String.format("Expected a boolean for '%s', but got null instead", (Object[]) args), path)); + } + return; + } + + try { + Boolean b = (Boolean) object; + } catch (ClassCastException ex) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.ERROR, + String.format("Expected a boolean for '%s', but got '" + object + "' instead", (Object[]) args), path)); + } + } + + public static boolean configValidateExists(String path, Object object, List problems, String... args) { + if (object == null) { + problems.add(new ConfigProblem(ConfigProblem.ConfigProblemType.ERROR, + String.format(ConfigProblemDescriptions.TASK_MISSING_FIELD.getDescription(args), (Object[]) args), path)); + return false; + } + return true; + } +} diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml new file mode 100644 index 00000000..5cb81473 --- /dev/null +++ b/bukkit/src/main/resources/plugin.yml @@ -0,0 +1,30 @@ +name: Quests + +# This will be replaced with the property "version" in build.gradle +version: ${version} + +main: com.leonardobishop.quests.bukkit.BukkitQuestsPlugin +website: https://github.com/LMBishop/Quests +author: "LMBishop & contributors" +softdepend: [ASkyBlock, BentoBox, IridiumSkyblock, uSkyBlock, Citizens, MythicMobs, PlaceholderAPI, Essentials, ShopGUIPlus, CoreProtect] +prefix: Quests +api-version: "1.13" # allows new API features but Quests will still work pre-1.13 + +commands: + quests: + description: Interact with your quests + usage: /quests + permission: quests.command + aliases: [q, quest] + +#todo redo perms +permissions: + quests.command: + description: Permission for main command + default: true + quests.command.random: + description: Permission to execute /q random + default: true + quests.admin: + description: Permission for the admin commands + default: op \ No newline at end of file diff --git a/bukkit/src/main/resources/resources/bukkit/config.yml b/bukkit/src/main/resources/resources/bukkit/config.yml new file mode 100644 index 00000000..f7084505 --- /dev/null +++ b/bukkit/src/main/resources/resources/bukkit/config.yml @@ -0,0 +1,355 @@ +# | =================================================== | +# | Thank you for downloading and trying out | +# | Quests | +# | https://www.spigotmc.org/resources/23696/ | +# | https://github.com/LMBishop/Quests/ | +# | | +# | =x= | +# | | +# | Trying to add new quests? | +# | | +# | Go to the 'quests' | +# | subdirectory to edit the | +# | quests | +# | | +# | The example quests | +# | are commented to help you | +# | learn how to use the plugin | +# | | +# | =x= | +# | | +# | Have Discord & need help? | +# | Head to the GitHub page and click on the | +# | Discord link, or create an issue | +# | =================================================== | + + +# Categories are a way of grouping up quests. +# When a player uses /quests, a menu of categories will be presented to them. +# When a player clicks ona category, a list of quests under that category will show. +# If categories are disabled, all quests will be shown under one big GUI. +# Players can access specific categories by command using /quests c [category]. +# If a quest does not have a category, it will not be shown. +categories: + examples: + display: + name: "&cExample Quests" + lore: + - "&7This category contains example quests" + - "&7which are commented in the config." + - "&7The comments should guide you with" + - "&7how the config works." + - "" + - "&cIt is highly recommended you read this" + - "&csection and all the comments so you can" + - "&cmake the most of this plugin." + type: "WATER_BUCKET" + permissionexample: + display: + name: "&cPermission Example" + lore: + - "&7This category is an example of one which" + - "&7requires a permission to open." + - "" + - "&cIt is highly recommended you read this" + - "&csection and all the comments so you can" + - "&cmake the most of this plugin." + type: "WATER_BUCKET" + # This category needs the permission "quests.category.permissionexample", because the category ID is 'permissionexample'. + # The permission for other categories is: "quests.category.". + permission-required: true + +# The items listed below are placeholder items for quests which the player cannot start. +# You should change these for 1.8 +gui: + back-button: + name: "&cReturn" + lore: + - "&7Return to the categories menu." + type: "ARROW" + page-prev: + name: "&7Previous Page" + lore: + - "&7Switch the page to page &c{prevpage}." + type: "FEATHER" + page-next: + name: "&7Next Page" + lore: + - "&7Switch the page to page &c{nextpage}." + type: "FEATHER" + page-desc: + name: "&7Page &c{page}" + lore: + - "&7You are currently viewing page &c{page}." + type: "PAPER" + quest-locked-display: + name: "&c&lQuest Locked" + lore: + - "&7You have not completed the requirements" + - "&7for this quest (&c{quest}&7)." + - "" + - "&7Requires: &c{requirements}" + - "&7to be completed to unlock." + type: "RED_STAINED_GLASS_PANE" + quest-permission-display: + name: "&6&lNo Permission" + lore: + - "&7You do not have permission for this" + - "&7quest (&6{quest}&7)." + type: "BROWN_STAINED_GLASS_PANE" + quest-cooldown-display: + name: "&e&lQuest On Cooldown" + lore: + - "&7You have recently completed this quest" + - "&7(&e{quest}&7) and you must" + - "&7wait another &e{time} &7to unlock again." + type: "ORANGE_STAINED_GLASS_PANE" + quest-completed-display: + name: "&a&lQuest Complete" + lore: + - "&7You have completed this quest" + - "&7(&a{quest}&7) and cannot." + - "&7repeat it." + type: "GREEN_STAINED_GLASS_PANE" + no-started-quests: + name: "&c&lNo Started Quests" + lore: + - "&7Go start some!" + type: "FEATHER" + quest-cancel-yes: + name: "&a&lConfirm Cancel" + lore: + - "&7Confirm you wish to cancel" + - "&7this quest and lose all" + - "&7progress." + type: "GREEN_STAINED_GLASS_PANE" + quest-cancel-no: + name: "&c&lAbort Cancel" + lore: + - "&7Return to the quest menu." + type: "RED_STAINED_GLASS_PANE" + quest-cancel-background: + type: "GRAY_STAINED_GLASS_PANE" + +# Here you can add custom items to the quest menu +# Categories & quests will fill empty slots +#custom-elements: +# "categories": # apply to the categories menu (the main menu by default) +# 0: # <--- slot 1, note the slots start from 0! so 0 = slot 1 in this case +# display: +# name: "&cExample Custom Item (slot 1)" +# lore: +# - "&7This is a custom item which can be added" +# - "&7to your menus. This is purely cosmetic." +# - "" +# - "&7Two empty slots should follow." +# type: "DIAMOND_BLOCK" +# 1: # <--- start from slot 2 +# spacer: true # empty slot in GUI +# repeat: 2 # repeats for 2 slots +# 3: # <--- start from slot 4 +# display: +# name: "&cExample Custom Item (slots 4 - 7)" +# lore: +# - "&7This is a custom item which can be added" +# - "&7to your menus, but in slot 4 and repeated" +# - "&73 times." +# - "&7" +# - "&7This will come after 2 empty slots." +# - "&7" +# - "&7This is purely cosmetic." +# type: "NETHERRACK" +# repeat: 3 # repeats for 3 more slots +# "c:examples": # apply to the category "examples" +# 0: +# display: +# name: "&cExample Custom Item (slot 1)" +# lore: +# - "&7This is a custom item which can be added" +# - "&7to your menus. This is purely cosmetic." +# type: "EMERALD_BLOCK" +# "quests": # apply to the general quests menu IF categories are disabled +# 0: +# display: +# name: "&cExample Custom Item (slot 1)" +# lore: +# - "&7This is a custom item which can be added" +# - "&7to your menus. This is purely cosmetic." +# type: "EMERALD_BLOCK" + +options: + # If categories are disabled, quests will be put into one big gui. + categories-enabled: true + # If true, the gui size will automatically change based on the amount of quests inside it. + trim-gui-size: true + # Enable/disable titles + titles-enabled: true + # Players cannot start any more quests than this at a single time + quest-started-limit: 2 + # Hide locked quests, quests on cooldown and completed (but not repeatable) quests + gui-hide-locked: false + # Allow players to cancel a quest (you may want to remove the cancel instructions in the global item lore) + allow-quest-cancel: true + # Allow players to track a quest (you may want to remove the tracking instructions in the global item lore) + allow-quest-track: true + # Titles for the GUIs + guinames: + quests-category: "Quests Categories" + quests-menu: "Quests" + quests-started-menu: "Started Quests" + daily-quests: "Daily Quests" + quest-cancel: "Cancel Quest" + # Show when quests register in console - will only show if verbose-logging-level=2. Disable if you want less console spam at startup. + show-quest-registrations: true + # Hide quests which a player cannot start due to permissions. + gui-hide-quests-nopermission: false + # Hide categories which a player cannot open due to permissions. + gui-hide-categories-nopermission: false + # Replace placeholders from PlaceholderAPI in Quests GUI items + gui-use-placeholderapi: false + # Make it so players do not have to start quest themselves + quest-autostart: false + # Automatically track quests on start, and stop tracking on completion + quest-autotrack: true + # How much quests should log, 0 = errors only, 1 = warnings, 2 = info, 3 = debug + verbose-logging-level: 2 + # Verify quests exist when a player's data is loaded - inconsistencies may arise when + # players progress on specific quests and those quests are later removed. The problem is that their progress + # is still kept in the quest progress file, which may lead to issues such as players reaching a quest started + # limit when the quests they had active no longer exist - having this option enabled prevents + # non-existent quests from being loaded + verify-quest-exists-on-load: true + performance-tweaking: # The following are measured in server ticks, multiply SECONDS by 20 to get the number of ticks. + quest-queue-executor-interval: 1 # how frequently Quests should execute the next check in the completion queue (def=1 - 0.05s) - increase this value if you are struggling with performance + quest-autosave-interval: 12000 # how frequently online players data will be autosaved (def=12000 - 10 minutes) + tab-completion: + enabled: true + error-checking: + # Allow quests to be loaded if they contain errors + # This may lead to errors in the console! + override-errors: false + # How much time (in seconds) that plugin will cache placeholders + placeholder-cache-time: 10 + # Whether or not the global task configuration will override per-task configuration settings + global-task-configuration-override: false + # Whether or not the global display configuration will override per-quest display settins + global-quest-display-configuration-override: false + # Storage options - please see the following: https://github.com/LMBishop/Quests/wiki/Storage-Providers + storage: + # Either 'yaml' (flatfile) or 'mysql' (network) + # Please read the following before using MySQL https://github.com/LMBishop/Quests/wiki/Storage-Providers#network + provider: "yaml" + # The following is only applicable for database storage providers (e.g. mysql) + database-settings: + network: + # The name of the database. This database should already exist! + database: "minecraft" + username: "root" + password: "" + # Address should be in the format ip:port (just like the game itself) + address: "localhost:3306" + # This plugin uses 'HikariCP' for connection management, the pooling configuration can be changed here + connection-pool-settings: + # The maximum number of connections to keep open with the database (def=8) + maximum-pool-size: 8 + # The minimum number of connections to keep open with the database (def=8) + minimum-idle: 8 + # The maximum time (in milliseconds) to keep a single connection open (def=1800000 - 30 min) + maximum-lifetime: 1800000 + # The time (in milliseconds) the plugin will wait for a response by the database (def=500) + connection-timeout: 5000 + # The prefix each table will use + table-prefix: "quests_" + + +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" +# set to true. This is useful if you do not want to go through each quest if you want to update the configuration +# for every task of a specific type. +# +# You must uncomment all below lines for the example to have any effect +# vvvvvvvvvvvvvvvvvvvvvvvvv +#global-task-configuration: +# types: +# inventory: +# update-progress: true + +global-quest-display: + lore: +# append-normal: +# - "..." + append-not-started: + - "" + - "&eLeft Click &7to start this quest." + append-started: + - "" + - "&aYou have started this quest." + - "&eMiddle Click &7to track this quest." + - "&eRight Click &7to cancel this quest." + append-tracked: + - "" + - "&aYou are &etracking &athis quest." + - "&eMiddle Click &7to stop tracking this quest." + - "&eRight Click &7to cancel this quest." + + +# Configure titles +titles: + quest-start: + title: "&cQuest Started" + subtitle: "&7{quest}" + quest-complete: + title: "&cQuest Complete" + subtitle: "&7{quest}" + +# Configure messages +messages: + time-format: "{hours}h {minutes}m" + quest-start: "&7Quest &c{quest} &7started!" + quest-complete: "&7Quest &c{quest} &7completed!" + quest-cancel: "&7Quest &c{quest} &7cancelled!" + quest-track: "&7Tracking quest &c{quest}&7." + quest-track-stop: "&7No longer tracking quest &c{quest}&7." + quest-random-none: "&cYou have no quests which you can start." + quest-start-limit: "&7Players are limited to &c{limit} &7started quests at a time." + quest-start-disabled: "&7You cannot repeat this quest." + quest-start-locked: "&7You have not unlocked this quest yet." + quest-start-cooldown: "&7You have recently completed this quest. You have to wait &c{time} &7until you are able to restart it." + quest-start-started: "&7You have already started this quest." + quest-start-permission: "&7You do not have permission to start this quest." + quest-category-permission: "&7You do not have permission to view this category." + quest-category-quest-permission: "&7You do not have permission to start this quest since it is in a category you do not have permission to view." + quest-cancel-notstarted: "&7You have not started this quest." + quest-updater: "&cQuests > &7A new version &c{newver} &7was found on Spigot (your version: &c{oldver}&7). Please update me! <3 - Link: {link}" + command-data-not-loaded: "&4Your quests progress file has not been loaded; you cannot use quests. If this issue persists, contact an admin." + command-sub-doesntexist: "&7The specified subcommand '&c{sub}' &7does not exist." + command-quest-start-doesntexist: "&7The specified quest '&c{quest}&7' does not exist." + command-quest-general-doesntexist: "&7The specified quest '&c{quest}&7' does not exist." + command-category-open-disabled: "&7Categories are disabled." + command-category-open-doesntexist: "&7The specified category '&c{category}&7' does not exist." + command-quest-admin-playernotfound: "&7Player '&c{player}&7' could not be found." + command-quest-openquests-admin-success: "&7Opened Quest GUI for player &c{player}&7." + command-quest-opencategory-admin-success: "&7Opened category &c{category} &7for player &c{player}&7." + command-taskview-admin-fail: "&7Task type '&c{task}&7' does not exist." + beta-reminder: "&cQuests > &7Reminder: you are currently using a &cbeta &7version of Quests. Please send bug reports to https://github.com/fatpigsarefat/Quests/issues and check for updates regularly using &c/quests admin update&7!" + command-quest-admin-loaddata: "&7Quest data for '&c{player}&7' is being loaded." + command-quest-admin-nodata: "&7No data could be found for player &c{player}&7." + command-quest-admin-fullreset: "&7Data for player &c{player}&7 has been fully reset." + command-quest-admin-clean-success: "&7All quest progress files have been cleaned." + command-quest-admin-clean-fail: "&cFailed to clean quest progress files. Please report the error in the console." + command-quest-admin-start-faillocked: "&7Quest '&c{quest}&7' could not be started for player &c{player}&7. They have not yet unlocked it." + command-quest-admin-start-failcooldown: "&7Quest '&c{quest}&7' could not be started for player &c{player}&7. It is still on cooldown for them." + command-quest-admin-start-failcomplete: "&7Quest '&c{quest}&7' could not be started for player &c{player}&7. They have already completed it." + command-quest-admin-start-faillimit: "&7Quest '&c{quest}&7' could not be started for player &c{player}&7. They have reached their quest start limit." + command-quest-admin-start-failstarted: "&7Quest '&c{quest}&7' could not be started for player &c{player}&7. It is already started." + command-quest-admin-start-failpermission: "&7Quest '&c{quest}&7' could not be started for player &c{player}&7. They do not have permission." + command-quest-admin-start-failcategorypermission: "&7Quest '&c{quest}&7' could not be started for player &c{player}&7. They do not have permission for the category which the quest is in." + command-quest-admin-start-failother: "&7Quest '&c{quest}&7' could not be started for player &c{player}&7." + command-quest-admin-start-success: "&7Quest &c{quest} &7started for player &c{player}&7." + command-quest-admin-category-permission: "&7Category &c{category} &7 could not be opened for player &c{player}&7. They do not have permission to view it." + command-quest-admin-complete-success: "&7Quest &c{quest} &7completed for player &c{player}&7." + command-quest-admin-reset-success: "&7Successfully reset quest '&c{quest}&7' for player &c{player}&7." + diff --git a/bukkit/src/main/resources/resources/bukkit/quests/README.txt b/bukkit/src/main/resources/resources/bukkit/quests/README.txt new file mode 100644 index 00000000..779dd6bb --- /dev/null +++ b/bukkit/src/main/resources/resources/bukkit/quests/README.txt @@ -0,0 +1,40 @@ +# !! READ ME - IT WILL NOT TAKE LONG !! +# +# Each file ín the 'quests' folder defines a single quest. +# The name of the file is the quest ID. These must be alphanumeric and unique. +# Quest files must be in the .yml format. +# +# A quest is a series of tasks which players must complete for a reward and may require a previous quest to start. +# A task is an objective such as breaking blocks or obtaining items. +# A reward is a command executed by the SERVER. Use {player} to get the players name. +# +# Most task types will allow you to restrict them to a certain world. Check out the wiki for which ones. +# +# A quest can have a 'startstring' (this is optional). They will be sent to the player when they start the quest. +# A quest can have a 'rewardstring' (this is optional). They will be sent to the player when they complete the quest. +# An example of the startstring/rewardstring in use can be seen in the quest example4. +# +# Each quest will have ONE "display" item, this is the item shown to the player in the GUI. +# The display item will have a "name", a "type" and TWO lores. +# The name is the name of the item, the type is the material and the lore is the text underneath the item (when mouse-over-ing). +# The first lore you must give is called 'lore-normal'. This is the lore seen if the player has not started the quest. +# The second lore you must give is 'lore-started'. This will be APPENDED to the first lore IF the player has started the quest - useful for putting progression. +# Within the lores you can get the players progress for each task. Use {TASKID:progress} (replace TASKID with the ID of the task). +# You can also get if a task is complete. Use {TASKID:complete} (replace TASKID with the ID of the task). +# +# Quests can be put inside a category. When a player runs /quests they will first see a menu of categories. +# They can click one and another menu of quests under that category will show up. +# +# =============================================================== +# +# You can see other task types here: +# https://github.com/LMBishop/Quests/wiki/Task-Types +# +# =============================================================== +# +# Need help? +# Find the Discord link in the README.md, or open an issue on GitHub +# https://github.com/LMBishop/Quests/issues +# https://github.com/LMBishop/Quests/blob/master/README.md +# +# =============================================================== diff --git a/bukkit/src/main/resources/resources/bukkit/quests/example1.yml b/bukkit/src/main/resources/resources/bukkit/quests/example1.yml new file mode 100644 index 00000000..ca57f714 --- /dev/null +++ b/bukkit/src/main/resources/resources/bukkit/quests/example1.yml @@ -0,0 +1,61 @@ +# The name of this file is the quest ID. It must be alphanumeric and unique. + +# Everything inside of this section defines tasks the player must complete to progress. +tasks: + # This is the task ID ("mining"). This can share the same name as the quest ID but MUST be unique with all other task IDs in the same quest. + mining: + # This defines what type of task this is. In this instance, it is "blockbreak" (breaking blocks) + # NOTE: guides to set up each type of task is on the wiki (see README)! + type: "blockbreak" + # This defines the amount of blocks which need to be broken + amount: 30 + # You can have multiple tasks for each quest (example further down). + +# Everything inside of this section defines the display item. +display: + # This is the name of the item. This allows color codes. + name: "&cExample I (Single Task)" + # This is the lore of the item if the player has not started the quest. This allows color codes and task/player placeholders. + lore-normal: + - "&cThis category is designed to show you the different" + - "&cattributes a quest can have." + - "" + - "&7This quest requires you to:" + - "&7 - Break &f30 blocks&7." + - "" + - "&7Rewards:" + - "&7 - &f10 &7diamonds." + # This lore will be appended to the bottom of the above lore when the player starts their quest. + # To get the players progress through a task, use {TASKID:progress} and replace TASKID with the ID of the task. + lore-started: + - "" + - "&7Your current progression:" + - "&7 - &f{mining:progress}&7/30 blocks broken." + # This is the material of the item. It is recommended to stick to bukkit names. + type: "WOODEN_PICKAXE" + +# List all commands to be executed by the server when the player completes the quest. Use {player} to get the players name. +rewards: + - "give {player} diamond 10" + +# These placeholders are accessible using PlaceholderAPI, for example %quests_tracked_p:description% +# They are useful for putting information about the players tracked quest on a scoreboard +# You may want to keep the names of them the same for ALL quests for this use-case +placeholders: + description: "&7Break &f30 blocks &7of any type." + progress: " &8- &f{mining:progress}&7/30 broken" + +# Everything inside this section define quest-specific options +options: + # This is the category for the quest, it will appear under the "examples" category. Categories can be disabled. + category: "examples" + # Set if the quest can be repeated after being completed for the first time. + repeatable: false + # Define the cooldown on quests. The above (repeatable) must be true for this to take effect. + cooldown: + # If true, players will have to wait between repeating quests. + enabled: true + # Time (in minutes) + time: 1440 + # This is the relative position in the GUI + sort-order: 1 \ No newline at end of file diff --git a/bukkit/src/main/resources/resources/bukkit/quests/example2.yml b/bukkit/src/main/resources/resources/bukkit/quests/example2.yml new file mode 100644 index 00000000..7ad82bea --- /dev/null +++ b/bukkit/src/main/resources/resources/bukkit/quests/example2.yml @@ -0,0 +1,47 @@ +# This is a quest which requires the previous quest to be complete to start. + +tasks: + # Unlike the previous quest, this quest has multiple tasks. + mining: + type: "blockbreak" + amount: 100 + building: + type: "blockplace" + amount: 100 +display: + name: "&cExample II (Multiple Tasks)" + lore-normal: + - "&cThis category is designed to show you the different" + - "&cattributes a quest can have. This quest requires" + - "&cmultiple things to be done, unlike the previous one." + - "" + - "&7This quest requires you to:" + - "&7 - Break &f100 &7blocks." + - "&7 - Place &f100 &7blocks." + - "" + - "&7Rewards:" + - "&7 - &f15 diamonds&7." + - "&7 - &f$50&7 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - &f{mining:progress}&7/100 blocks broken." + - "&7 - &f{building:progress}&7/100 blocks placed." + type: "GRASS_BLOCK" +rewards: + - "give {player} diamond 15" + - "eco give {player} 50" +placeholders: + description: "&7Break and place &f100 blocks &7of any type." + progress: " &8- &f{mining:progress}&7/100 broken, &f{building:progress}&7/100 placed" +options: + category: "examples" + # Unlike the previous quest, this quest has "example1" as a required quest. You cannot start this quest without "example1" quest complete. + requires: + - "example1" + repeatable: false + cooldown: + enabled: true + time: 1440 + # The sort order has been changed so this quest will appear after in the GUI + sort-order: 2 \ No newline at end of file diff --git a/bukkit/src/main/resources/resources/bukkit/quests/example3.yml b/bukkit/src/main/resources/resources/bukkit/quests/example3.yml new file mode 100644 index 00000000..dbd893e4 --- /dev/null +++ b/bukkit/src/main/resources/resources/bukkit/quests/example3.yml @@ -0,0 +1,49 @@ +# This is a quest which requires the previous quest to be complete to start. +# Unlike the previous quest, this one can be re-done but it has a 10 minute cooldown. + +tasks: + # Unlike the previous two quests, this quest specifies a specific block to be broken. + mining: + type: "blockbreakcertain" + amount: 81 + block: GOLD_ORE + building: + type: "blockplacecertain" + amount: 9 + block: GOLD_BLOCK +display: + name: "&cExample III (Repeatable, 10 minute cooldown)" + lore-normal: + - "&cThis category is designed to show you the different" + - "&cattributes a quest can have. This quest can be replayed" + - "&cafter a cooldown, unlike the previous one." + - "" + - "&7This quest requires you to:" + - "&7 - Break &f81 gold ore&7." + - "&7 - Place &f9 gold blocks&7." + - "" + - "&7Rewards:" + - "&7 - &f30 diamonds&7." + - "&7 - &f$10&7 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - &f{mining:progress}&7/81 gold ore broken." + - "&7 - &f{building:progress}&7/9 gold blocks placed." + type: "GOLD_ORE" +rewards: + - "give {player} diamond 30" + - "eco give {player} 10" +placeholders: + description: "&7Break &f81 gold ore &7and place &f9 gold blocks." + progress: " &8- &f{mining:progress}&7/81 gold ore, &f{building:progress}&7/9 gold blocks" +options: + category: "examples" + requires: + - "example2" + # This quest is repeatable, it has cooldowns enabled (meaning the player must wait before repeating it) and the time set to 10 (minutes). + repeatable: true + cooldown: + enabled: true + time: 10 + sort-order: 3 \ No newline at end of file diff --git a/bukkit/src/main/resources/resources/bukkit/quests/example4.yml b/bukkit/src/main/resources/resources/bukkit/quests/example4.yml new file mode 100644 index 00000000..4e9c27a8 --- /dev/null +++ b/bukkit/src/main/resources/resources/bukkit/quests/example4.yml @@ -0,0 +1,50 @@ +# This is a quest which requires the previous quest to be complete to start. +# Unlike the previous quests, this quest has a reward string and a start string. + +tasks: + mobkilling: + type: "mobkilling" + amount: 3 +display: + name: "&cExample IV (Reward String)" + lore-normal: + - "&cThis category is designed to show you the different" + - "&cattributes a quest can have. This quest has a 'reward string'" + - "&c(a series of messages sent when a quest is complete)," + - "&cunlike the previous one." + - "" + - "&7This quest requires you to:" + - "&7 - Kill &f3 &7mobs." + - "" + - "&7Rewards:" + - "&7 - &f$50 &7added to your in-game balance." + - "&7 - &f1 diamond&7." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - &f{mobkilling:progress}&7/3 mobs killed." + type: "STRING" +# Here you can list messages which will be sent to the player (if they are online) upon the quest starting. +startstring: + - "&7Upon completion of this quest, you will be rewarded with" + - " &8* &c$50" + - " &8* &c1 diamonds" +rewards: + - "eco give {player} 50" + - "give {player} diamond 1" +placeholders: + description: "&7Kill &f3 &7mobs." + progress: " &8- &f{mobkilling:progress}&7/3 mobs" +# Here you can list messages which will be sent to the player (if they are online) upon completion. +rewardstring: + - " &8* &c$1000 &7was added to your in-game balance." + - " &8* &c1 diamond &7was added to your inventory." +options: + category: "examples" + requires: + - "example3" + repeatable: true + cooldown: + enabled: true + time: 10 + sort-order: 4 \ No newline at end of file diff --git a/bukkit/src/main/resources/resources/bukkit/quests/example5.yml b/bukkit/src/main/resources/resources/bukkit/quests/example5.yml new file mode 100644 index 00000000..cb92f0f1 --- /dev/null +++ b/bukkit/src/main/resources/resources/bukkit/quests/example5.yml @@ -0,0 +1,38 @@ +tasks: + building: + type: "blockplace" + amount: 10 +display: + name: "&cExample V (Permission)" + lore-normal: + - "&cThis category is designed to show you the different" + - "&cattributes a quest can have. This quest requires" + - "&ccertain permissions." + - "" + - "&7This quest requires you to:" + - "&7 - Place &f10 &7blocks." + - "" + - "&7Rewards:" + - "&7 - &f$10 &7added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - &f{building:progress}&7/10 blocks placed." + type: "GRASS_BLOCK" +rewards: + - "eco give {player} 10" +placeholders: + description: "&7Place &f10 &7blocks of any type." + progress: " &8- &f{building:progress}&7/10 blocks" +options: + category: "examples" + requires: + - "example4" + # Unlike the previous quests, this one requires you to have the permission "quests.quest.example5" to start. + # The permission for other quests is: "quests.quest.". + permission-required: true + repeatable: false + cooldown: + enabled: true + time: 1440 + sort-order: 5 \ No newline at end of file diff --git a/bukkit/src/main/resources/resources/bukkit/quests/example6.yml b/bukkit/src/main/resources/resources/bukkit/quests/example6.yml new file mode 100644 index 00000000..0913a7cb --- /dev/null +++ b/bukkit/src/main/resources/resources/bukkit/quests/example6.yml @@ -0,0 +1,35 @@ +tasks: + building: + type: "blockplace" + amount: 10 +display: + name: "&cExample VI (Different category, permissions)" + lore-normal: + - "&cThis category is designed to show you the different" + - "&cattributes a quest can have. This quest requires" + - "&ccertain permissions." + - "" + - "&7This quest requires you to:" + - "&7 - Place &f10 &7blocks." + - "" + - "&7Rewards:" + - "&7 - &f$10 &7added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - &f{building:progress}&7/10 blocks placed." + type: "GRASS_BLOCK" +rewards: + - "eco give {player} 10" +placeholders: + description: "&7Place &f10 &7blocks of any type." + progress: " &8- &f{building:progress}&7/10 blocks" +options: + category: "permissionexample" + # This quest has no specific permission, however its category does. The permission for the category is "quests.category.permissionexample" + repeatable: false + cooldown: + enabled: true + time: 1440 + # The quest is in a different category so the sort order is 1. + sort-order: 1 \ No newline at end of file diff --git a/bukkit/src/main/resources/resources/bukkit/quests/example7.yml b/bukkit/src/main/resources/resources/bukkit/quests/example7.yml new file mode 100644 index 00000000..32bb7e04 --- /dev/null +++ b/bukkit/src/main/resources/resources/bukkit/quests/example7.yml @@ -0,0 +1,37 @@ +tasks: + building: + type: "blockplace" + amount: 10 + worlds: + - "world" +display: + name: "&cExample VII (Different category, world restricted)" + lore-normal: + - "&cThis category is designed to show you the different" + - "&cattributes a quest can have. This quest requires" + - "&chas a task which requires you to be in a world called 'world'." + - "" + - "&7This quest requires you to:" + - "&7 - Place &f10 &7blocks." + - "" + - "&7Rewards:" + - "&7 - &f$10 &7added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - &f{building:progress}&7/10 blocks placed." + type: "GRASS_BLOCK" +rewards: + - "eco give {player} 10" +placeholders: + description: "&7Place &f10 &7blocks of any type in world &fworld." + progress: " &8- &f{building:progress}&7/10 blocks" +options: + category: "permissionexample" + # This quest has no specific permission, however its category does. The permission for the category is "quests.category.permissionexample" + repeatable: false + cooldown: + enabled: true + time: 1440 + # The quest is in a different category so the sort order is 1. + sort-order: 1 \ No newline at end of file -- cgit v1.2.3-70-g09d2