diff options
Diffstat (limited to 'bukkit/src/main/java')
93 files changed, 9706 insertions, 0 deletions
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<String, List<ConfigProblem>> 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("<MAIN CONFIG> 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<String> 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<String, List<ConfigProblem>> 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 + * <p> + * 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 + * <p> + * 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<String, Object> 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<Quest> 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<ConfigProblem.ConfigProblemType> problemTypes = new HashSet<>(); + int count = 0; + for (Map.Entry<String, List<ConfigProblem>> entry : plugin.getConfigProblems().entrySet()) { + HashMap<ConfigProblem.ConfigProblemType, List<ConfigProblem>> sortedProblems = new HashMap<>(); + for (ConfigProblem problem : entry.getValue()) { + if (sortedProblems.containsKey(problem.getType())) { + sortedProblems.get(problem.getType()).add(problem); + } else { + List<ConfigProblem> 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<String> 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 <categoryid> " + ChatColor.DARK_GRAY + ": open category by ID"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests q/quest <questid> <start|cancel|track>" + 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 <player> " + ChatColor.DARK_GRAY + ": forcefully show" + + " quests for player"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a opengui c/category <player> <category> " + ChatColor.DARK_GRAY + ": " + + "forcefully " + + "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 <player> " + ChatColor.DARK_GRAY + ": clear a " + + "players quest data file"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata reset <player> <questid> " + ChatColor.DARK_GRAY + ": clear a " + + "players data for specifc quest"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata start <player> <questid> " + ChatColor.DARK_GRAY + ": start a " + + "quest for a player"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata complete <player> <questid> " + ChatColor.DARK_GRAY + ": " + + "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<String> matchTabComplete(String arg, List<String> options) { + List<String> completions = new ArrayList<>(); + StringUtil.copyPartialMatches(arg, options, completions); + Collections.sort(completions); + return completions; + } + + private List<String> tabCompleteCategory(String arg) { + List<String> options = new ArrayList<>(); + for (Category c : plugin.getQuestManager().getCategories()) { + options.add(c.getId()); + } + return matchTabComplete(arg, options); + } + + private List<String> tabCompleteQuests(String arg) { + List<String> options = new ArrayList<>(plugin.getQuestManager().getQuests().keySet()); + return matchTabComplete(arg, options); + } + + @Nullable + @Override + public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { + if (!plugin.getQuestsConfig().getBoolean("options.tab-completion.enabled")) { + return null; + } + if (sender instanceof Player) { + if (args.length == 1) { + List<String> 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<String> 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<String> 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<String> options = new ArrayList<>(); + for (TaskType taskType : plugin.getTaskTypeManager().getTaskTypes()) { + options.add(taskType.getType()); + } + return matchTabComplete(args[2], options); + } else if (args[1].equalsIgnoreCase("opengui")) { + List<String> options = Arrays.asList("resources/bukkit/quests", "category"); + return matchTabComplete(args[2], options); + } else if (args[1].equalsIgnoreCase("moddata")) { + List<String> 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<String, ItemStack> cachedItemStacks = new HashMap<>(); + // this is faster than just relying on the YamlConfiguration to cache it for some reason + private final Map<String, Boolean> 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<String> getStringList(String path) { + return config.getStringList(path); + } + + @Override + public List<String> getStringList(String path, List<String> def) { + List<String> 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<String, List<ConfigProblem>> loadQuests(File root) { + qItemStackRegistry.clearRegistry(); + questManager.getQuests().clear(); + questManager.getCategories().clear(); + taskTypeManager.resetTaskTypes(); + + Map<String, List<ConfigProblem>> configProblems = new HashMap<>(); + HashMap<String, Quest> pathToQuest = new HashMap<>(); + HashMap<String, Map<String, Object>> globalTaskConfig = new HashMap<>(); + + if (questsConfig.getConfig().isConfigurationSection("global-task-configuration.types")) { + for (String type : questsConfig.getConfig().getConfigurationSection("global-task-configuration.types").getKeys(false)) { + HashMap<String, Object> 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<Path> fileVisitor = new SimpleFileVisitor<Path>() { + @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<ConfigProblem> 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<String, Object> 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<String> rewards = config.getStringList("rewards"); + List<String> requirements = config.getStringList("options.requires"); + List<String> rewardString = config.getStringList("rewardstring"); + List<String> startString = config.getStringList("startstring"); + boolean repeatable = config.getBoolean("options.repeatable", false); + boolean cooldown = config.getBoolean("options.cooldown.enabled", false); + boolean permissionRequired = config.getBoolean("options.permission-required", false); + int cooldownTime = config.getInt("options.cooldown.time", 10); + int sortOrder = config.getInt("options.sort-order", 1); + String category = config.getString("options.category"); + Map<String, String> 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<String, Object> 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<String, Quest> loadedQuest : pathToQuest.entrySet()) { + List<ConfigProblem> 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<ConfigProblem> 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<String> cLoreNormal = config.getStringList(path + ".lore-normal"); + List<String> cLoreStarted = config.getStringList(path + ".lore-started"); + + List<String> loreNormal = translateColoursInList(cLoreNormal); + List<String> 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<String> translateColoursInList(List<String> list) { + List<String> 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<String[]> 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<Filter> 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<String> cLore = config.getStringList(path + "lore"); + List<String> cItemFlags = config.getStringList(path + "itemflags"); + boolean hasAttributeModifiers = config.contains(path + "attributemodifiers"); + List<Map<?, ?>> 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<String> 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<Filter> 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<String> cLore = config.getStringList(path + "lore"); + List<String> cItemFlags = config.getStringList(path + "itemflags"); + boolean hasAttributeModifiers = config.contains(path + "attributemodifiers"); + List<Map<?, ?>> 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<String> 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<Filter> 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<String> cLore = config.getStringList(path + "lore"); + List<String> 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<String> 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<String, Map<String, String>> cache = new HashMap<>(); + private final Map<String, SimpleDateFormat> 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<Quest> listAll = new ArrayList<>(plugin.getQuestManager().getQuests().values()); + result = (args.length == 1 ? String.valueOf(listAll.size()) : parseList((List<Quest>) listAll, args[1], split)); + break; + case "completed": + case "c": + final List<Quest> listCompleted = qPlayer.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.COMPLETED); + result = (args.length == 1 ? String.valueOf(listCompleted.size()) : parseList(listCompleted, args[1], split)); + break; + case "completedbefore": + case "cb": + final List<Quest> listCompletedB = qPlayer.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.COMPLETED_BEFORE); + result = (args.length == 1 ? String.valueOf(listCompletedB.size()) : parseList(listCompletedB, args[1], split)); + break; + case "started": + case "s": + final List<Quest> listStarted = qPlayer.getQuestProgressFile().getAllQuestsFromProgress(QuestProgressFile.QuestsProgressFilter.STARTED); + result = (args.length == 1 ? String.valueOf(listStarted.size()) : parseList(listStarted, args[1], split)); + break; + case "categories": + if (args.length == 1) { + result = String.valueOf(plugin.getQuestManager().getCategories().size()); + } else { + final List<String> listCategories = new ArrayList<>(); + switch (args[1].toLowerCase()) { + case "list": + case "l": + plugin.getQuestManager().getCategories().forEach(c -> { + 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<Quest> listAll = getCategoryQuests(qPlayer, category, QuestProgressFile.QuestsProgressFilter.ALL); + result = (args.length == 2 ? String.valueOf(listAll.size()) : parseList(listAll, args[2], split)); + break; + case "completed": + case "c": + final List<Quest> listCompleted = getCategoryQuests(qPlayer, category, QuestProgressFile.QuestsProgressFilter.COMPLETED); + result = (args.length == 2 ? String.valueOf(listCompleted.size()) : parseList(listCompleted, args[2], split)); + break; + case "completedbefore": + case "cb": + final List<Quest> listCompletedB = getCategoryQuests(qPlayer, category, QuestProgressFile.QuestsProgressFilter.COMPLETED_BEFORE); + result = (args.length == 2 ? String.valueOf(listCompletedB.size()) : parseList(listCompletedB, args[2], split)); + break; + case "started": + case "s": + final List<Quest> listStarted = getCategoryQuests(qPlayer, category, QuestProgressFile.QuestsProgressFilter.STARTED); + result = (args.length == 2 ? String.valueOf(listStarted.size()) : parseList(listStarted, args[2], split)); + break; + default: + return args[0] + "_" + args[1] + " is not a valid placeholder"; + } + } + 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<String, String> map = new HashMap<>(); + map.put(params, result); + cache.put(player, map); + Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> cache.get(player).remove(params), plugin.getConfig().getInt("options.placeholder-cache-time", 10) * 20); + } + return result; + } + + 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<Quest> list, String type, String separator) { + final List<String> 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<Quest> getCategoryQuests(QPlayer questP, Category category, QuestProgressFile.QuestsProgressFilter filter) { + final List<Quest> categoryQuests = new ArrayList<>(); + category.getRegisteredQuestIds().forEach(q -> { + Quest quest = plugin.getQuestManager().getQuestById(q); + if (quest != null) { + switch (filter) { + case STARTED: + if (questP.getQuestProgressFile().getQuestProgress(quest).isStarted()) + categoryQuests.add(quest); + break; + case COMPLETED: + if (questP.getQuestProgressFile().getQuestProgress(quest).isCompleted()) + categoryQuests.add(quest); + break; + case COMPLETED_BEFORE: + if (questP.getQuestProgressFile().getQuestProgress(quest).isCompletedBefore()) + categoryQuests.add(quest); + break; + default: + categoryQuests.add(quest); + } + } + }); + return categoryQuests; + } +} diff --git a/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<Integer, MenuElement> 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<QuestQMenu> 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<String, String> 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<Integer, MenuElement> 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<String> 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<UUID, QMenu> 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<Quest> 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<QuestQMenu> questMenus = new ArrayList<>(); + for (Category category : plugin.getQuestManager().getCategories()) { + QuestQMenu questQMenu = new QuestQMenu(plugin, qPlayer, category.getId(), categoryQMenu); + List<Quest> 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<Quest> quests = new ArrayList<>(); + for (Map.Entry<String, Quest> 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<QuestSortWrapper> quests = new ArrayList<>(); + for (Map.Entry<String, Quest> 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<Integer, MenuElement> 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<Quest> 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<String, String> 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<String, String> placeholders) { + ItemStack newItemStack = is.clone(); + List<String> lore = newItemStack.getItemMeta().getLore(); + List<String> newLore = new ArrayList<>(); + ItemMeta ism = newItemStack.getItemMeta(); + Player player = Bukkit.getPlayer(owner.getPlayerUUID()); + if (lore != null) { + for (String s : lore) { + for (Map.Entry<String, String> 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<String, String> 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<QuestSortWrapper> { + + 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<Integer, String> 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<QuestSortWrapper> 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<Integer, String> 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<String, String> 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<String> lore = newItemStack.getItemMeta().getLore(); + List<String> 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<String> 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<String, String> 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<String, String> 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<String, String> 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<String, String> 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<String, String> placeholders) { + ItemStack newItemStack = is.clone(); + List<String> lore = newItemStack.getItemMeta().getLore(); + List<String> newLore = new ArrayList<>(); + ItemMeta ism = newItemStack.getItemMeta(); + Player player = Bukkit.getPlayer(owner.getPlayerUUID()); + if (lore != null) { + for (String s : lore) { + for (Map.Entry<String, String> 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<String, String> 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<String> loreNormal; + private List<String> loreStarted; + private final List<String> globalLoreAppendNormal; + private final List<String> globalLoreAppendNotStarted; + private final List<String> globalLoreAppendStarted; + private final List<String> globalLoreAppendTracked; + private ItemStack startingItemStack; + + public QItemStack(BukkitQuestsPlugin plugin, String name, List<String> loreNormal, List<String> 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<String> getLoreNormal() { + return loreNormal; + } + + public void setLoreNormal(List<String> loreNormal) { + this.loreNormal = loreNormal; + } + + public List<String> getLoreStarted() { + return loreStarted; + } + + public void setLoreStarted(List<String> 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<String> formattedLore = new ArrayList<>(); + List<String> 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<String, QItemStack> questRegistry = new HashMap<>(); + private final Map<String, ItemStack> 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<QuestProgress> completionQueue = new LinkedList<>(); + private final Queue<QuestProgressFile> 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<String> quests; +// +// public DailyQuestController(Quests plugin) { +// this.plugin = plugin; +// refreshDailyQuests(); +// scheduleNewTask(); +// } +// +// public void cancel() { +// Bukkit.getScheduler().cancelTask(refreshTaskId); +// } +// +// public List<String> 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<String> 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<UUID> 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<String, String> 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<String, QuestProgress> 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<QuestProgress> 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<UUID, ReentrantLock> 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<QuestProgress> 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBreed(CreatureSpawnEvent e) { + if (!e.getSpawnReason().equals(SpawnReason.BREEDING)) { + return; + } + + Entity ent = e.getEntity(); + List<Entity> 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<ConfigValue> creatorConfigValues = new ArrayList<>(); +// private HashMap<Location, UUID> 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<ConfigValue> 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<Location, UUID> brewingStands = new HashMap<>(); + + public BrewingTaskType(BukkitQuestsPlugin plugin) { + super("brewing", TaskUtils.TASK_ATTRIBUTION_STRING, "Brew a potion."); + this.plugin = plugin; + } + + @Override + public List<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + if (config.get("block") == null && config.get("blocks") == null) { + TaskUtils.configValidateExists(root + ".block", config.get("block"), problems, "block", super.getType()); + } else { + Object configBlock; + String source; + if (config.containsKey("block")) { + source = "block"; + } else { + source = "blocks"; + } + configBlock = config.get(source); + List<String> checkBlocks = new ArrayList<>(); + if (configBlock instanceof List) { + checkBlocks.addAll((List) configBlock); + } else { + checkBlocks.add(String.valueOf(configBlock)); + } + + for (String materialName : checkBlocks) { + String[] split = materialName.split(":"); + if (Material.getMaterial(String.valueOf(split[0])) == null) { + problems.add(new 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<String> 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".command", config.get("command"), problems, "command", super.getType()); + TaskUtils.configValidateBoolean(root + ".ignore-case", config.get("ignore-case"), problems, true, "ignore-case", super.getType()); + return problems; + } + + @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<String> commands = new ArrayList<>(); + if (configCommand instanceof List) { + commands.addAll((List) configCommand); + } else { + commands.add(String.valueOf(configCommand)); + } + + boolean ignoreCasing = false; + if (configIgnoreCase != null) { + ignoreCasing = (boolean) task.getConfigValue("ignore-case"); + } + String message = e.getMessage(); + if (message.length() >= 1) { + message = message.substring(1); + } + + for (String command : commands) { + if (ignoreCasing && command.equalsIgnoreCase(message)) { + taskProgress.setCompleted(true); + } else if (!ignoreCasing && command.equals(message)) { + taskProgress.setCompleted(true); + } + } + } + } + } + } +} diff --git a/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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".x", config.get("x"), problems, "x", super.getType())) + TaskUtils.configValidateInt(root + ".x", config.get("x"), problems, false, false, "x"); + if (TaskUtils.configValidateExists(root + ".y", config.get("y"), problems, "y", super.getType())) + TaskUtils.configValidateInt(root + ".y", config.get("y"), problems, false, false, "y"); + if (TaskUtils.configValidateExists(root + ".z", config.get("z"), problems, "z", super.getType())) + TaskUtils.configValidateInt(root + ".z", config.get("z"), problems, false, false, "z"); + if (TaskUtils.configValidateExists(root + ".distance", config.get("distance"), problems, "distance", super.getType())) + TaskUtils.configValidateInt(root + ".distance", config.get("distance"), problems, false, true, "distance"); + return problems; + } + +// private HashMap<String, HashMap<String, Integer>> distanceSquaredCache = new HashMap<>(); +// +// @Override +// public void onReady() { +// distanceSquaredCache.clear(); +// for (Quest quest : super.getRegisteredQuests()) { +// HashMap<String, Integer> squaredDistances = new HashMap<>(); +// for (Task task : quest.getTasksOfType(super.getType())) { +// int distance = (int) task.getConfigValue("distance"); +// squaredDistances.put(task.getId(), distance); +// } +// distanceSquaredCache.put(quest.getId(), squaredDistances); +// } +// } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMove(PlayerMoveEvent event) { + if (event.getFrom().getBlockX() == event.getTo().getBlockX() && event.getFrom().getBlockZ() == event.getTo().getBlockZ()) { + 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".item", config.get("item"), problems, "item", super.getType())) { + Object configBlock = config.get("item"); + if (configBlock instanceof ConfigurationSection) { + ConfigurationSection section = (ConfigurationSection) configBlock; + String itemloc = "item"; + if (!section.contains("item")) { + itemloc = "type"; + } + if (!section.contains(itemloc)) { + problems.add(new 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + if (config.get("block") == null && config.get("blocks") == null) { + TaskUtils.configValidateExists(root + ".block", config.get("block"), problems, "block", super.getType()); + } else { + Object configBlock; + String source; + if (config.containsKey("block")) { + source = "block"; + } else { + source = "blocks"; + } + configBlock = config.get(source); + List<String> checkBlocks = new ArrayList<>(); + if (configBlock instanceof List) { + checkBlocks.addAll((List) configBlock); + } else { + checkBlocks.add(String.valueOf(configBlock)); + } + + for (String materialName : checkBlocks) { + String[] split = materialName.split(":"); + if (Material.getMaterial(String.valueOf(split[0])) == null) { + problems.add(new 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<String> 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".mob", config.get("mob"), problems, "mob", super.getType())) { + try { + EntityType.valueOf(String.valueOf(config.get("mob"))); + } catch (IllegalArgumentException ex) { + problems.add(new 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<String> 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + TaskUtils.configValidateBoolean(root + ".hostile", config.get("hostile"), problems, true, "hostile"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".minutes", config.get("minutes"), problems, "minutes", super.getType())) + TaskUtils.configValidateInt(root + ".minutes", config.get("minutes"), problems, false, true, "minutes"); + return problems; + } + + + @Override + public void onReady() { + 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".world", config.get("world"), problems, "world", super.getType()); + if (TaskUtils.configValidateExists(root + ".x", config.get("x"), problems, "x", super.getType())) + TaskUtils.configValidateInt(root + ".x", config.get("x"), problems, false, false, "x"); + if (TaskUtils.configValidateExists(root + ".y", config.get("y"), problems, "y", super.getType())) + TaskUtils.configValidateInt(root + ".y", config.get("y"), problems, false, false, "y"); + if (TaskUtils.configValidateExists(root + ".z", config.get("z"), problems, "z", super.getType())) + TaskUtils.configValidateInt(root + ".z", config.get("z"), problems, false, false, "z"); + TaskUtils.configValidateInt(root + ".distance-padding", config.get("distance-padding"), problems, true, true, "distance-padding"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".distance", config.get("distance"), problems, "distance", super.getType())) + TaskUtils.configValidateInt(root + ".distance", config.get("distance"), problems, false, true, "distance"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".level", config.get("level"), problems, "level", super.getType())) + TaskUtils.configValidateInt(root + ".level", config.get("level"), problems, false, false, "level"); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".level", config.get("level"), problems, "level", super.getType())) + TaskUtils.configValidateInt(root + ".level", config.get("level"), problems, false, false, "level"); + return problems; + } + + + 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<String, Object> 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".item", config.get("item"), problems, "item", super.getType())) { + Object configBlock = config.get("item"); + if (configBlock instanceof ConfigurationSection) { + ConfigurationSection section = (ConfigurationSection) configBlock; + String itemloc = "item"; + if (!section.contains("item")) { + itemloc = "type"; + } + if (!section.contains(itemloc)) { + problems.add(new 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".npc-name", config.get("npc-name"), problems, "npc-name", super.getType()); + TaskUtils.configValidateBoolean(root + ".remove-items-when-complete", config.get("remove-items-when-complete"), problems, true, "remove-items-when-complete", super.getType()); + return problems; + } + + @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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, false, "amount"); + return problems; + } + + @Override + public void onStart(Quest quest, Task task, UUID playerUUID) { + Player player = Bukkit.getPlayer(playerUUID); + Essentials ess = (Essentials) Bukkit.getPluginManager().getPlugin("Essentials"); + if (player != null && player.isOnline() && ess != null) { + QPlayer qPlayer = 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, false, "amount"); + return problems; + } + + @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<ConfigValue> 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<QuestsConfigLoader.ConfigProblem> detectProblemsInConfig(String root, HashMap<String, Object> config) { +// ArrayList<QuestsConfigLoader.ConfigProblem> problems = new ArrayList<>(); +// if (TaskUtils.configValidateExists(root + ".value", config.get("value"), problems, "value", super.getType())) +// TaskUtils.configValidateInt(root + ".value", config.get("value"), problems, false, false, "value"); +// return problems; +// } +// +// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) +// public void onIslandLevel(IslandWorthCalculatedEvent event) { +// Island island = event.getIsland(); +// for (String player : island.members) { +// UUID uuid; +// try { +// uuid = UUID.fromString(player); +// } catch (Exception e) { +// 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<ConfigValue> 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".name", config.get("name"), problems, "name", super.getType()); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, true, "amount"); + 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + TaskUtils.configValidateExists(root + ".placeholder", config.get("placeholder"), problems, "placeholder", super.getType()); + boolean evalExists = TaskUtils.configValidateExists(root + ".evaluates", config.get("evaluates"), problems, "evaluates", super.getType()); + + if (config.containsKey("operator")) { + String operatorStr = (String) config.get("operator"); + Operator operator = null; + try { + operator = Operator.valueOf(operatorStr); + } catch (IllegalArgumentException ex) { + problems.add(new 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, false, "amount"); + 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".amount", config.get("amount"), problems, "amount", super.getType())) + TaskUtils.configValidateInt(root + ".amount", config.get("amount"), problems, false, false, "amount"); + 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<ConfigProblem> validateConfig(String root, HashMap<String, Object> config) { + ArrayList<ConfigProblem> problems = new ArrayList<>(); + if (TaskUtils.configValidateExists(root + ".level", config.get("level"), problems, "level", super.getType())) + TaskUtils.configValidateInt(root + ".level", config.get("level"), problems, false, false, "level"); + return problems; + } + + @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<String> color(List<String> s) { + if (s == null || s.size() == 0) return s; + + List<String> 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<String, String> placeholders) { + ItemStack newItemStack = is.clone(); + List<String> lore = newItemStack.getItemMeta().getLore(); + List<String> newLore = new ArrayList<>(); + ItemMeta ism = newItemStack.getItemMeta(); + Player player = Bukkit.getPlayer(owner); + if (lore != null) { + for (String s : lore) { + for (Map.Entry<String, String> 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<String, String> 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 = "<built-in>"; + + 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<String> allowedWorldNames = (List<String>) 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<ConfigProblem> 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<ConfigProblem> 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<ConfigProblem> 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; + } +} |
