diff options
Diffstat (limited to 'src')
51 files changed, 4743 insertions, 0 deletions
diff --git a/src/config.yml b/src/config.yml new file mode 100644 index 00000000..948a415b --- /dev/null +++ b/src/config.yml @@ -0,0 +1,747 @@ +# | =================================================== | +# | Thank you for downloading and trying out my plugin: | +# | Quests | +# | https://www.spigotmc.org/resources/23696/ | +# | Created by fatpigsarefat | +# | | +# | =x= | +# | | +# | File comments should help | +# | you with the new config | +# | and guide you with making | +# | quests | +# | | +# | =x= | +# | | +# | Have Discord & need help? | +# | https://www.discord.gg/8amrJnX | +# | =================================================== | + +# !! READ ME !! +# +# A quest is a series of tasks which players must complete for a reward and may require a previous quest to start. +# A task is an objective such as breaking blocks or obtaining items. +# A reward is a command executed by the SERVER. Use {player} to get the players name. +# +# A quest can have a 'rewardstring' (this is optional). They will be sent to the player when they complete the quest. +# An example of the rewardstring in use can be seen in the quest example4. +# +# Each quest will have ONE "display" item, this is the item shown to the player in the GUI. +# The display item will have a "name", a "type" and TWO lores. +# The name is the name of the item, the type is the material and the lore is the text underneath the item (when mouse-over-ing). +# The first lore you must give is called 'lore-normal'. This is the lore seen if the player has not started the quest. +# The second lore you must give is 'lore-started'. This will be appended to the first lore IF the player has started the quest - useful for putting progression. +# Within the lores you can get the players" progress for each task. Use {TASKID:progress} (replace TASKID with the ID of the task). +# +# Quests can be put inside a category. When a player does /quests they will first see a menu of categories. They can click one and another menu of quests +# under that category will show up. Categories can be disabled. +# +# !! READ ME !! + +# Everything inside of this section is a quest +quests: + # This is the quest ID ("example"). This MUST be unique against all other quest IDs. + example1: + # Everything inside of this section defines tasks the player must complete to progress. + tasks: + # This is the task ID ("mining"). This can share the same name as the quest ID but MUST be unique with all other task IDs in the same quest. + mining: + # This defines what type of task this is. In this instance, it is "blockbreak" (breaking blocks) + # NOTE: guides to set up each type of task is on the plugin page! + type: "blockbreak" + # This defines the amount of blocks which need to be broken + amount: 30 + # You can have multiple tasks for each quest (example further down). + # Everything inside of this section defines the display item. + display: + # This is the name of the item. This allows color codes. + name: "&cExample I (Single Task)" + # This is the lore of the item if the player has not started the quest. This allows color codes and task/player placeholders. + lore-normal: + - "&7This quest requires you to:" + - "&7 - Break 30 blocks." + - "" + - "&7Rewards:" + - "&7 - 10 diamonds." + # This lore will be appended to the bottom of the above lore when the player starts their quest. + # To get the players progress through a task, use {TASKID:progress} and replace TASKID with the ID of the task. + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {mining:progress}/30 blocks broken." + # This is the material of the item. It is recommended to stick to bukkit names. + type: "WOOD_PICKAXE" + # List all commands to be executed by the server when the player completes the quest. Use {player} to get the players name. + rewards: + - "give {player} diamond 10" + # Everything inside this section define quest-specific options + options: + # This is the category for the quest, it will appear under the "examples" category. Categories can be disabled. + category: "examples" + # Set the quest IDs of required quests here, leave empty if none. + requires: + - "" + # Set if the quest can be repeated after being completed for the first time. + repeatable: false + # Define the cooldown on quests. The above (repeatable) must be true for this to take effect. + cooldown: + # If true, players will have to wait between repeating quests. + enabled: true + # Time (in minutes) + time: 1440 + + # This is a quest which requires the previous quest to be complete to start. + example2: + tasks: + # Unlike the previous quest, this quest has multiple tasks. + mining: + type: "blockbreak" + amount: 100 + building: + type: "blockplace" + amount: 100 + display: + name: "&cExample II (Multiple Tasks)" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Break 100 blocks." + - "&7 - Place 100 blocks." + - "" + - "&7Rewards:" + - "&7 - 15 diamonds." + - "&7 - $50 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {mining:progress}/100 blocks broken." + - "&7 - {building:progress}/100 blocks placed." + type: "GRASS" + rewards: + - "give {player} diamond 15" + - "eco give {player} 50" + options: + category: "examples" + # Unlike the previous quest, this quest has "example1" as a required quest. You cannot start this quest without "example1" quest complete. + requires: + - "example1" + repeatable: false + cooldown: + enabled: true + time: 1440 + + # This is a quest which requires the previous quest to be complete to start. + # Unlike the previous quest, this one can be re-done but it has a 10 minute cooldown. + example3: + tasks: + # Unlike the previous two quests, this quest specifies a specific block to be broken. + mining: + type: "blockbreakcertain" + amount: 81 + block: 14 # (gold ore) + building: + type: "blockplacecertain" + amount: 9 + block: 41 # (gold blocks) + display: + name: "&cExample III (Repeatable, 10 minute cooldown)" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Break 81 gold ore." + - "&7 - Place 9 gold blocks." + - "" + - "&7Rewards:" + - "&7 - 30 diamonds." + - "&7 - $10 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {mining:progress}/81 gold ore broken." + - "&7 - {building:progress}/9 gold blocks placed." + type: "GOLD_ORE" + rewards: + - "give {player} diamond 30" + - "eco give {player} 10" + options: + category: "examples" + requires: + - "example2" + # This quest is repeatable, it has cooldowns enabled (meaning the player must wait before repeating it) and the time set to 10 (minutes). + repeatable: true + cooldown: + enabled: true + time: 10 + + # This is a quest which requires the previous quest to be complete to start. + # Unlike the previous quests, this quest has a reward string. + example4: + tasks: + mobkilling: + type: "mobkilling" + amount: 3 + display: + name: "&cExample IV (Reward String)" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Kill 3 mobs." + - "" + - "&7Rewards:" + - "&7 - $50 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {mobkilling:progress}/3 mobs killed." + type: "STRING" + rewards: + - "eco give {player} 50" + # Here you can list messages which will be sent to the player (if they are online) upon completion. + rewardstring: + - ' &8* &c$10 &7was added to your in-game balance.' + - ' &8* &c30 diamonds &7was added to your inventory.' + options: + category: "examples" + requires: + - "example3" + repeatable: true + cooldown: + enabled: true + time: 1440 + + # This is the end of the config example quests. + # Hopefully you should be able to understand the quest config from this. + # -------------------------------------------------------------------------------------- + # Below are some basic quests. You should be able to understand what to do from reading these. + # These quests show off the other task types this plugin has to offer by default. + # Developers can add their own (look at the wiki on GitHub for details). + + mining1: + tasks: + mining: + type: "blockbreak" + amount: 100 + display: + name: "&cNovice Miner" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Break 100 blocks." + - "" + - "&7Rewards:" + - "&7 - $50 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {mining:progress}/100 blocks broken." + type: "WOOD_PICKAXE" + rewards: + - "eco give {player} 50" + options: + category: "easy" + requires: + - "" + repeatable: true + cooldown: + enabled: true + time: 1440 + + building1: + tasks: + building: + type: "blockplace" + amount: 100 + display: + name: "&cNovice Builder" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Place 100 blocks." + - "" + - "&7Rewards:" + - "&7 - $50 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {building:progress}/100 blocks placed." + type: "STONE" + rewards: + - "eco give {player} 50" + options: + category: "easy" + requires: + - "" + repeatable: true + cooldown: + enabled: true + time: 1440 + + youmonster: + tasks: + mobkilling: + type: "mobkilling" + amount: 10 + hostile: false + display: + name: "&cYou Monster" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Kill 10 non-hostile animals." + - "" + - "&7Rewards:" + - "&7 - $1 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {mobkilling:progress}/10 non-hostile animals." + type: "PORK" + rewards: + - "eco give {player} 1" + options: + category: "easy" + requires: + - '' + repeatable: true + cooldown: + enabled: true + time: 1440 + + mobkiller: + tasks: + mobkilling: + type: "mobkilling" + amount: 10 + hostile: true + display: + name: "&cMonster Slayer" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Kill 10 hostile monsters." + - "" + - "&7Rewards:" + - "&7 - $50 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {mobkilling:progress}/10 hostile monsters killed." + type: "WOOD_SWORD" + rewards: + - "eco give {player} 50" + options: + category: "easy" + requires: + - '' + repeatable: true + cooldown: + enabled: true + time: 1440 + + walking1: + tasks: + walking: + type: "walking" + distance: 1000 + display: + name: "&cAdventurer" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Walk 1km." + - "" + - "&7Rewards:" + - "&7 - $50 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {walking:progress}m/1000m walked." + type: "LEATHER_BOOTS" + rewards: + - "eco give {player} 50" + options: + category: "easy" + requires: + - '' + repeatable: true + cooldown: + enabled: true + time: 1440 + + playerkiller: + tasks: + playerkilling: + type: "playerkilling" + amount: 10 + display: + name: "&cMurderer" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Kill 10 players." + - "" + - "&7Rewards:" + - "&7 - $10 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {playerkilling:progress}/10 players killed." + type: "IRON_SWORD" + rewards: + - "eco give {player} 50" + options: + category: "medium" + requires: + - '' + repeatable: true + cooldown: + enabled: true + time: 1440 + + fisher: + tasks: + fishing: + type: "fishing" + amount: 10 + display: + name: "&cProfessional Fisher" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Catch 10 items from the sea." + - "" + - "&7Rewards:" + - "&7 - $30 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {fishing:progress}/10 items caught." + type: "FISHING_ROD" + rewards: + - "eco give {player} 30" + options: + category: "medium" + requires: + - '' + repeatable: true + cooldown: + enabled: true + time: 1440 + + animals1: + tasks: + milking: + type: "milking" + amount: 10 + shearing: + type: "shearing" + amount: 10 + taming: + type: "taming" + amount: 3 + display: + name: "&cAnimal Keeper" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Milk 10 cows." + - "&7 - Shear 10 sheep." + - "&7 - Tame 3 animals as pets." + - "" + - "&7Rewards:" + - "&7 - $50 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {milking:progress}/10 cows milked." + - "&7 - {shearing:progress}/10 sheep sheared." + - "&7 - {taming:progress}/3 animals tamed." + type: "MILK_BUCKET" + rewards: + - "eco give {player} 50" + options: + category: "medium" + requires: + - '' + repeatable: true + cooldown: + enabled: true + time: 1440 + + mining2: + tasks: + mining: + type: "blockbreak" + amount: 350 + ironmining: + type: "blockbreakcertain" + block: IRON_ORE + amount: 20 + display: + name: "&cSkilled Miner" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Break 350 blocks." + - "&7 - Break 20 iron ore." + - "" + - "&7Rewards:" + - "&7 - $150 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {mining:progress}/350 blocks broken." + - "&7 - {ironmining:progress}/20 iron ore broken." + type: "IRON_PICKAXE" + rewards: + - "eco give {player} 150" + options: + category: "medium" + requires: + - "mining1" + repeatable: true + cooldown: + enabled: true + time: 1440 + + building2: + tasks: + building: + type: "blockplace" + amount: 350 + woodbuilding: + type: "blockplacecertain" + block: 5 + amount: 20 + bricksbuilding: + type: "blockplacecertain" + block: 45 + amount: 20 + redwoolbuilding: + type: "blockplacecertain" + block: 35 + amount: 20 + data: 14 + display: + name: "&cVariety Builder" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Place 350 blocks." + - "&7 - Place 20 oak wood." + - "&7 - Place 20 bricks." + - "&7 - Place 20 red wool." + - "" + - "&7Rewards:" + - "&7 - $150 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {building:progress}/350 blocks placed." + - "&7 - {woodbuilding:progress}/20 oak wood placed." + - "&7 - {bricksbuilding:progress}/20 bricks placed." + - "&7 - {redwoolbuilding:progress}/20 red wool placed." + type: "WOOL" + rewards: + - "eco give {player} 150" + options: + category: "medium" + requires: + - "building1" + repeatable: true + cooldown: + enabled: true + time: 1440 + + walking2: + tasks: + walking: + type: "walking" + distance: 10000 + display: + name: "&cMountaineer" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Walk 10km." + - "" + - "&7Rewards:" + - "&7 - $500 added to your in-game balance." + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {walking:progress}m/10000m walked." + type: "LEATHER_BOOTS" + rewards: + - "eco give {player} 500" + options: + category: "medium" + requires: + - 'walking1' + repeatable: true + cooldown: + enabled: true + time: 1440 + + askyblock: + tasks: + islandlevel: + type: "askyblock_level" + level: 50 + display: + name: "&cIslander (ASkyBlock)" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Reach island level 50" + - "" + - "&7Rewards:" + - "&7 - $30 added to your in-game balance." + - '' + - '&cRequires plugin ASkyBlock!' + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {islandlevel:progress}/50 island level." + type: "GRASS" + rewards: + - "eco give {player} 30" + options: + category: "dependent" + requires: + - '' + repeatable: false + cooldown: + enabled: true + time: 1440 + + uskyblock: + tasks: + islandlevel: + type: "uskyblock_level" + level: 50 + display: + name: "&cIslander (uSkyBlock)" + lore-normal: + - "&7This quest requires you to:" + - "&7 - Reach island level 50" + - "" + - "&7Rewards:" + - "&7 - $30 added to your in-game balance." + - '' + - '&cRequires plugin uSkyBlock!' + lore-started: + - "" + - "&7Your current progression:" + - "&7 - {islandlevel:progress}/50 island level." + type: "GRASS" + rewards: + - "eco give {player} 30" + options: + category: "dependent" + requires: + - '' + repeatable: false + cooldown: + enabled: true + time: 1440 + +# Categories are a way of grouping up quests. +# When a player uses /quests, a menu of categories will be presented to them. +# When a player clicks ona category, a list of quests under that category will show. +# If categories are disabled, all quests will be shown under one big GUI. +# Players can access specific categories by command using /quests c [category]. +# If a quest does not have a category, it will not be shown. +categories: + examples: + display: + name: "&cExample Quests" + lore: + - "&7This category contains example quests" + - "&7which are commented in the config." + - "&7The comments should guide you with" + - "&7how the config works." + - '' + - '&cIt is highly recommended you read this' + - '&csection and all the comments so you can' + - '&cmake the most of this plugin.' + type: "327" + easy: + display: + name: "&cEasy Difficulty Quests" + lore: + - "&7This category contains easy quests." + - "&7They do not require you to do much but" + - "&7rewards are low." + type: "260" + medium: + display: + name: "&cIntermediate Difficulty Quests" + lore: + - "&7This category contains intermediate quests." + - "&7These quests are more challenging than the" + - "&7previous with greater rewards." + type: "264" + dependent: + display: + name: "&cDependent Quests" + lore: + - "&7This category contains quests which are dependent" + - "&7on other plugins being installed such as &cASkyBlock," + - "&cuSkyBlock &7and &cCitizens&7." + type: "GRASS" + +# The items listed below are placeholder items for quests which the player cannot start. +gui: + back-button: + name: "&cReturn" + lore: + - "&7Return to the categories menu." + type: "ARROW" + quest-locked-display: + name: "&c&lQuest Locked" + lore: + - "&7You have not completed the requirements" + - "&7for this quest (&c{quest}&7)." + - '' + - '&7Requires: &c{requirements}' + - '&7to be completed to unlock.' + type: "160:14" + quest-cooldown-display: + name: "&e&lQuest On Cooldown" + lore: + - "&7You have recently completed this quest" + - "&7(&e{quest}&7) and you must" + - "&7wait another &e{time} &7to unlock again." + type: "160:1" + quest-completed-display: + name: "&a&lQuest Complete" + lore: + - "&7You have completed this quest" + - "&7(&a{quest}&7) and cannot." + - '&7repeat it.' + type: "160:5" + +options: + # If categories are disabled, quests will be put into one big gui. + categories-enabled: true + # If true, the gui size will automatically change based on the amount of quests inside it. + trim-gui-size: true + titles-enabled: true + # Players cannot start any more quests than this at a single time + quest-started-limit: 2 + +titles: + quest-start: + title: "&cQuest Started" + subtitle: "&7{quest}" + quest-complete: + title: "&cQuest Complete" + subtitle: "&7{quest}" + +messages: + quest-start: "&7Quest &c{quest} &7started!" + quest-complete: "&7Quest &c{quest} &7completed!" + quest-start-limit: "&7Players are limited to &c{limit} &7started quests at a time." + quest-start-disabled: "&7You cannot repeat this quest." + quest-start-locked: "&7You have not unlocked this quest yet." + quest-start-cooldown: "&7You have recently completed this quest. You have to wait &c{time} &7until you are able to restart it." + quest-updater: "&cQuests > &7A new version &c{newver} &7was found on Spigot (your version: &c{oldver}&7). Please update me! <3 - Link: {link}" + command-quest-start-doesntexist: "&7The specified quest '&c{quest}&7' does not exist." + command-category-open-disabled: "&7Categories are disabled." + command-category-open-doesntexist: "&7The specified category '&c{category}&7' does not exist." + command-quest-admin-playernotfound: "&7Player '&c{player}&7' could not be found." + command-quest-openquests-admin-success: "&7Opened Quest GUI for player &c{player}&7." + command-quest-opencategory-admin-success: "&7Opened category &c{category} &7for player &c{player}&7." + command-quest-start-admin-success: "&7Successfully started quest '&c{quest}&7' for player &c{player}&7." + command-quest-complete-admin-success: "&7Successfully completed quest '&c{quest}&7' for player &c{player}&7." + command-quest-reset-admin-success: "&7Successfully reset quest '&c{quest}&7' for player &c{player}&7." + command-quest-fullreset-admin-success: "&7Successfully reset player &c{player}&7." + command-quest-start-admin-fail: "&7Quest '&c{quest}&7' could not be started for player &c{player}&7. They may not have unlocked it, on cooldown, etc." + command-quest-complete-admin-fail: "&7Failed to complete '&c{quest}&7' for player &c{player}&7. They may have not started it." + command-taskview-admin-fail: "&7Task type '&c{task}&7' does not exist." diff --git a/src/me/fatpigsarefat/quests/Quests.java b/src/me/fatpigsarefat/quests/Quests.java new file mode 100644 index 00000000..2c3a7880 --- /dev/null +++ b/src/me/fatpigsarefat/quests/Quests.java @@ -0,0 +1,426 @@ +package me.fatpigsarefat.quests; + +import com.google.common.io.ByteStreams; +import me.fatpigsarefat.quests.bstats.Metrics; +import me.fatpigsarefat.quests.commands.CommandQuests; +import me.fatpigsarefat.quests.events.EventInventory; +import me.fatpigsarefat.quests.events.EventPlayerJoin; +import me.fatpigsarefat.quests.events.EventPlayerLeave; +import me.fatpigsarefat.quests.obj.misc.QItemStack; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.QPlayerManager; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Category; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.QuestManager; +import me.fatpigsarefat.quests.quests.Task; +import me.fatpigsarefat.quests.quests.tasktypes.*; +import me.fatpigsarefat.quests.title.*; +import me.fatpigsarefat.quests.updater.Updater; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; + +public class Quests extends JavaPlugin { + + private static Quests instance; + private static QuestManager questManager; + private static QPlayerManager qPlayerManager; + private static TaskTypeManager taskTypeManager; + private static Updater updater; + private static Title title; + private boolean brokenConfig = false; + + public static Quests getInstance() { + return instance; + } + + public static QuestManager getQuestManager() { + return questManager; + } + + public static QPlayerManager getPlayerManager() { + return qPlayerManager; + } + + public static TaskTypeManager getTaskTypeManager() { + return taskTypeManager; + } + + public boolean isBrokenConfig() { + return brokenConfig; + } + + public static Title getTitle() { + return title; + } + + public static Updater getUpdater() { + return updater; + } + + public static String convertToFormat(long m) { + long hours = m / 60; + long minutesLeft = m - hours * 60; + + String formattedTime = ""; + + if (hours < 10) + formattedTime = formattedTime + "0"; + formattedTime = formattedTime + hours + "h"; + + formattedTime = formattedTime + " "; + + if (minutesLeft < 10) + formattedTime = formattedTime + "0"; + formattedTime = formattedTime + minutesLeft + "m"; + + return formattedTime; + } + + @Override + public void onEnable() { + instance = this; + taskTypeManager = new TaskTypeManager(); + questManager = new QuestManager(); + qPlayerManager = new QPlayerManager(); + + dataGenerator(); + setupTitle(); + + taskTypeManager.registerTaskType(new MiningTaskType()); + taskTypeManager.registerTaskType(new MiningCertainTaskType()); + taskTypeManager.registerTaskType(new BuildingTaskType()); + taskTypeManager.registerTaskType(new BuildingCertainTaskType()); + taskTypeManager.registerTaskType(new MobkillingTaskType()); + taskTypeManager.registerTaskType(new MobkillingCertainTaskType()); + taskTypeManager.registerTaskType(new PlayerkillingTaskType()); + taskTypeManager.registerTaskType(new FishingTaskType()); + taskTypeManager.registerTaskType(new WalkingTaskType()); + taskTypeManager.registerTaskType(new TamingTaskType()); + taskTypeManager.registerTaskType(new MilkingTaskType()); + taskTypeManager.registerTaskType(new ShearingTaskType()); + if (Bukkit.getPluginManager().isPluginEnabled("ASkyBlock")) { + taskTypeManager.registerTaskType(new ASkyBlockLevelType()); + } + if (Bukkit.getPluginManager().isPluginEnabled("uSkyBlock")) { + taskTypeManager.registerTaskType(new uSkyBlockLevelType()); + } + + Bukkit.getPluginCommand("quests").setExecutor(new CommandQuests()); + Bukkit.getPluginManager().registerEvents(new EventPlayerJoin(), this); + Bukkit.getPluginManager().registerEvents(new EventInventory(), this); + Bukkit.getPluginManager().registerEvents(new EventPlayerLeave(), this); + + Metrics metrics = new Metrics(this); + this.getLogger().log(Level.INFO, "Metrics started. This can be disabled at /plugins/bStats/config.yml."); + + new BukkitRunnable() { + @Override + public void run() { + reloadQuests(); + + for (Player player : Bukkit.getOnlinePlayers()) { + qPlayerManager.loadPlayer(player.getUniqueId()); + } + } + }.runTask(this); + new BukkitRunnable() { + @Override + public void run() { + for (QPlayer qPlayer : qPlayerManager.getQPlayers()) { + qPlayer.getQuestProgressFile().saveToDisk(); + } + } + }.runTaskTimerAsynchronously(this, 12000L, 12000L); + new BukkitRunnable() { + @Override + public void run() { + for (QPlayer qPlayer : qPlayerManager.getQPlayers()) { + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + for (Map.Entry<String, Quest> entry : Quests.getQuestManager().getQuests().entrySet()) { + String id = entry.getKey(); + Quest quest = entry.getValue(); + QuestProgress questProgress = questProgressFile.getQuestProgress(quest); + if (questProgress != null && questProgress.isStarted()) { + boolean complete = true; + for (TaskProgress taskProgress : questProgress.getTaskProgress()) { + if (!taskProgress.isCompleted()) { + complete = false; + break; + } + } + if (complete) { + questProgressFile.completeQuest(quest); + } + } + } + } + } + }.runTaskTimerAsynchronously(this, 20L, 20L); + new BukkitRunnable() { + @Override + public void run() { + updater = new Updater(Quests.this); + updater.check(); + } + }.runTaskAsynchronously(this); + } + + @Override + public void onDisable() { + for (QPlayer qPlayer : qPlayerManager.getQPlayers()) { + qPlayer.getQuestProgressFile().saveToDisk(); + } + } + + public void reloadQuests() { + questManager.getQuests().clear(); + questManager.getCategories().clear(); + taskTypeManager.resetTaskTypes(); + + // test file integrity + try { + YamlConfiguration config = new YamlConfiguration(); + config.load(new File(String.valueOf(Quests.this.getDataFolder() + File.separator + "config.yml"))); + } catch (Exception ex) { + Quests.this.getLogger().log(Level.SEVERE, "You have a YAML error in your Quests config. If this is your first time using Quests, please remove the Quests folder and RESTART (not reload!) the server and try again."); + brokenConfig = true; + } + + for (String id : getConfig().getConfigurationSection("categories").getKeys(false)) { + ItemStack displayItem = getItemStack("categories." + id + ".display"); + Category category = new Category(id, displayItem); + questManager.registerCategory(category); + } + + for (String id : getConfig().getConfigurationSection("quests").getKeys(false)) { + String root = "quests." + id; + + QItemStack displayItem = getQItemStack(root + ".display"); + List<String> rewards = getConfig().getStringList(root + ".rewards"); + List<String> requirements = getConfig().getStringList(root + ".options.requires"); + List<String> rewardString = getConfig().getStringList(root + ".options.rewardstring"); + boolean repeatable = getConfig().getBoolean(root + ".options.repeatable", false); + boolean cooldown = getConfig().getBoolean(root + ".options.cooldown.enabled", false); + int cooldownTime = getConfig().getInt(root + ".options.cooldown.time", 10); + String category = getConfig().getString(root + ".options.category"); + + if (rewardString == null) { + rewardString = new ArrayList<>(); + } + if (requirements == null) { + rewardString = new ArrayList<>(); + } + if (rewards == null) { + rewardString = new ArrayList<>(); + } + if (category == null) { + category = ""; + } + + + Quest quest; + if (category.equals("")) { + quest = new Quest(id, displayItem, rewards, requirements, repeatable, cooldown, cooldownTime, rewardString); + } else { + quest = new Quest(id, displayItem, rewards, requirements, repeatable, cooldown, cooldownTime, rewardString, category); + Category c = questManager.getCategoryById(category); + if (c != null) { + c.registerQuestId(id); + } + } + + for (String taskId : getConfig().getConfigurationSection(root + ".tasks").getKeys(false)) { + String taskRoot = root + ".tasks." + taskId; + String taskType = getConfig().getString(taskRoot + ".type"); + + Task task = new Task(taskId, taskType); + + for (String key : getConfig().getConfigurationSection(taskRoot).getKeys(false)) { + task.addConfigValue(key, getConfig().get(taskRoot + "." + key)); + } + + quest.registerTask(task); + } + + this.getLogger().log(Level.INFO, "Registering quest " + quest.getId() + " with " + quest.getTasks().size() + " tasks."); + questManager.registerQuest(quest); + taskTypeManager.registerQuestTasksWithTaskTypes(quest); + } + } + + private QItemStack getQItemStack(String path) { + String cName = this.getConfig().getString(path + ".name", path + ".name"); + String cType = this.getConfig().getString(path + ".type", path + ".type"); + List<String> cLoreNormal = this.getConfig().getStringList(path + ".lore-normal"); + List<String> cLoreStarted = this.getConfig().getStringList(path + ".lore-started"); + + String name; + Material type = null; + int data = 0; + List<String> loreNormal = new ArrayList<>(); + if (cLoreNormal != null) { + for (String s : cLoreNormal) { + loreNormal.add(ChatColor.translateAlternateColorCodes('&', s)); + } + } + List<String> loreStarted = new ArrayList<>(); + if (cLoreStarted != null) { + for (String s : cLoreStarted) { + loreStarted.add(ChatColor.translateAlternateColorCodes('&', s)); + } + } + name = ChatColor.translateAlternateColorCodes('&', cName); + + if (StringUtils.isNumeric(cType)) { + type = Material.getMaterial(Integer.parseInt(cType)); + } else if (Material.getMaterial(cType) != null) { + type = Material.getMaterial(cType); + } else if (cType.contains(":")) { + String[] parts = cType.split(":"); + if (parts.length > 1) { + if (StringUtils.isNumeric(parts[0])) { + type = Material.getMaterial(Integer.parseInt(parts[0])); + } else 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; + } + + QItemStack is = new QItemStack(name, loreNormal, loreStarted, type, data); + + return is; + } + + public ItemStack getItemStack(String path) { + String cName = this.getConfig().getString(path + ".name", path + ".name"); + String cType = this.getConfig().getString(path + ".type", path + ".type"); + List<String> cLore = this.getConfig().getStringList(path + ".lore"); + + String name; + Material type = null; + int data = 0; + List<String> lore = new ArrayList<>(); + if (cLore != null) { + for (String s : cLore) { + lore.add(ChatColor.translateAlternateColorCodes('&', s)); + } + } + name = ChatColor.translateAlternateColorCodes('&', cName); + + if (StringUtils.isNumeric(cType)) { + type = Material.getMaterial(Integer.parseInt(cType)); + } else if (Material.getMaterial(cType) != null) { + type = Material.getMaterial(cType); + } else if (cType.contains(":")) { + String[] parts = cType.split(":"); + if (parts.length > 1) { + if (StringUtils.isNumeric(parts[0])) { + type = Material.getMaterial(Integer.parseInt(parts[0])); + } else 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; + } + + ItemStack is = new ItemStack(type, 1, (short) data); + ItemMeta ism = is.getItemMeta(); + ism.setLore(lore); + ism.setDisplayName(name); + is.setItemMeta(ism); + + return is; + } + + private boolean setupTitle() { + String version; + try { + version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; + } catch (ArrayIndexOutOfBoundsException e) { + return false; + } + boolean success = false; + getLogger().info("Your server is running version " + version); + if (version.equals("v1_8_R3")) { + title = new Title_v1_8_R3(); + success = true; + } else if (version.equals("v1_8_R2")) { + title = new Title_v1_8_R2(); + success = true; + } else if (version.equals("v1_8_R1")) { + title = new Title_v1_8_R1(); + success = true; + } else if (version.equals("v1_9_R2")) { + title = new Title_v1_9_R2(); + success = true; + } else if (version.equals("v1_9_R1")) { + title = new Title_v1_9_R1(); + success = true; + } else if (version.equals("v1_10_R1")) { + title = new Title_v1_10_R1(); + success = true; + } else if (version.equals("v1_11_R1")) { + title = new Title_v1_11_R1(); + success = true; + } else if (version.equals("v1_12_R1")) { + title = new Title_v1_12_R1(); + success = true; + } else { + title = new Title_Other(); + } + return success; + } + + private void dataGenerator() { + 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 = Quests.class.getClassLoader().getResourceAsStream("config.yml")) { + OutputStream out = new FileOutputStream(config); + ByteStreams.copy(in, out); + } catch (IOException e) { + e.printStackTrace(); + } + } catch (IOException e) { + e.printStackTrace(); + return; + } + } + } +} diff --git a/src/me/fatpigsarefat/quests/bstats/Metrics.java b/src/me/fatpigsarefat/quests/bstats/Metrics.java new file mode 100644 index 00000000..5a8a21b3 --- /dev/null +++ b/src/me/fatpigsarefat/quests/bstats/Metrics.java @@ -0,0 +1,661 @@ +package me.fatpigsarefat.quests.bstats; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.ServicePriority; +import org.bukkit.plugin.java.JavaPlugin; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import javax.net.ssl.HttpsURLConnection; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.zip.GZIPOutputStream; + +/** + * bStats collects some data for plugin authors. + * + * Check out https://bStats.org/ to learn more about bStats! + */ +public class Metrics { + + static { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D + final String defaultPackage = new String( + new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); + final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure nobody just copy & pastes the example and use the wrong package names + if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + // The version of this bStats class + public static final int B_STATS_VERSION = 1; + + // The url to which the data is sent + private static final String URL = "https://bStats.org/submitData/bukkit"; + + // Should failed requests be logged? + private static boolean logFailedRequests; + + // The uuid of the server + private static String serverUUID; + + // The plugin + private final JavaPlugin plugin; + + // A list with all custom charts + private final List<CustomChart> charts = new ArrayList<>(); + + /** + * Class constructor. + * + * @param plugin The plugin which stats should be submitted. + */ + public Metrics(JavaPlugin plugin) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null!"); + } + this.plugin = plugin; + + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + + // Check if the config file exists + if (!config.isSet("serverUuid")) { + + // Add default values + config.addDefault("enabled", true); + // Every server gets it's unique random id. + config.addDefault("serverUuid", UUID.randomUUID().toString()); + // Should failed request be logged? + config.addDefault("logFailedRequests", false); + + // Inform the server owners about bStats + config.options().header( + "bStats collects some data for plugin authors like how many servers are using their plugins.\n" + + "To honor their work, you should not disable it.\n" + + "This has nearly no effect on the server performance!\n" + + "Check out https://bStats.org/ to learn more :)" + ).copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { } + } + + // Load the data + serverUUID = config.getString("serverUuid"); + logFailedRequests = config.getBoolean("logFailedRequests", false); + if (config.getBoolean("enabled", true)) { + boolean found = false; + // Search for all other bStats Metrics classes to see if we are the first one + for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + found = true; // We aren't the first + break; + } catch (NoSuchFieldException ignored) { } + } + // Register our service + Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal); + if (!found) { + // We are the first! + startSubmitting(); + } + } + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + if (chart == null) { + throw new IllegalArgumentException("Chart cannot be null!"); + } + charts.add(chart); + } + + /** + * Starts the Scheduler which submits our data every 30 minutes. + */ + private void startSubmitting() { + final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + if (!plugin.isEnabled()) { // Plugin was disabled + timer.cancel(); + return; + } + // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler + // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) + Bukkit.getScheduler().runTask(plugin, new Runnable() { + @Override + public void run() { + submitData(); + } + }); + } + }, 1000*60*5, 1000*60*30); + // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start + // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! + // WARNING: Just don't do it! + } + + /** + * Gets the plugin specific data. + * This method is called using Reflection. + * + * @return The plugin specific data. + */ + public JSONObject getPluginData() { + JSONObject data = new JSONObject(); + + String pluginName = plugin.getDescription().getName(); + String pluginVersion = plugin.getDescription().getVersion(); + + data.put("pluginName", pluginName); // Append the name of the plugin + data.put("pluginVersion", pluginVersion); // Append the version of the plugin + JSONArray customCharts = new JSONArray(); + for (CustomChart customChart : charts) { + // Add the data of the custom charts + JSONObject chart = customChart.getRequestJsonObject(); + if (chart == null) { // If the chart is null, we skip it + continue; + } + customCharts.add(chart); + } + data.put("customCharts", customCharts); + + return data; + } + + /** + * Gets the server specific data. + * + * @return The server specific data. + */ + private JSONObject getServerData() { + // Minecraft specific data + int playerAmount; + try { + // Around MC 1.8 the return type was changed to a collection from an array, + // This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed + } + int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; + String bukkitVersion = org.bukkit.Bukkit.getVersion(); + bukkitVersion = bukkitVersion.substring(bukkitVersion.indexOf("MC: ") + 4, bukkitVersion.length() - 1); + + // OS/Java specific data + String javaVersion = System.getProperty("java.version"); + String osName = System.getProperty("os.name"); + String osArch = System.getProperty("os.arch"); + String osVersion = System.getProperty("os.version"); + int coreCount = Runtime.getRuntime().availableProcessors(); + + JSONObject data = new JSONObject(); + + data.put("serverUUID", serverUUID); + + data.put("playerAmount", playerAmount); + data.put("onlineMode", onlineMode); + data.put("bukkitVersion", bukkitVersion); + + data.put("javaVersion", javaVersion); + data.put("osName", osName); + data.put("osArch", osArch); + data.put("osVersion", osVersion); + data.put("coreCount", coreCount); + + return data; + } + + /** + * Collects the data and sends it afterwards. + */ + private void submitData() { + final JSONObject data = getServerData(); + + JSONArray pluginData = new JSONArray(); + // Search for all other bStats Metrics classes to get their plugin data + for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + + for (RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) { + try { + pluginData.add(provider.getService().getMethod("getPluginData").invoke(provider.getProvider())); + } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { } + } + } catch (NoSuchFieldException ignored) { } + } + + data.put("plugins", pluginData); + + // Create a new thread for the connection to the bStats server + new Thread(new Runnable() { + @Override + public void run() { + try { + // Send the data + sendData(data); + } catch (Exception e) { + // Something went wrong! :( + if (logFailedRequests) { + plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); + } + } + } + }).start(); + } + + /** + * Sends the data to the bStats server. + * + * @param data The data to send. + * @throws Exception If the request failed. + */ + private static void sendData(JSONObject data) throws Exception { + if (data == null) { + throw new IllegalArgumentException("Data cannot be null!"); + } + if (Bukkit.isPrimaryThread()) { + throw new IllegalAccessException("This method must not be called from the main thread!"); + } + HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); + + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + + // Add headers + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format + connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); + + // Send data + connection.setDoOutput(true); + DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream()); + outputStream.write(compressedData); + outputStream.flush(); + outputStream.close(); + + connection.getInputStream().close(); // We don't care about the response - Just send our data :) + } + + /** + * Gzips the given String. + * + * @param str The string to gzip. + * @return The gzipped String. + * @throws IOException If the compression failed. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + GZIPOutputStream gzip = new GZIPOutputStream(outputStream); + gzip.write(str.getBytes("UTF-8")); + gzip.close(); + return outputStream.toByteArray(); + } + + /** + * Represents a custom chart. + */ + public static abstract class CustomChart { + + // The id of the chart + final String chartId; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + */ + CustomChart(String chartId) { + if (chartId == null || chartId.isEmpty()) { + throw new IllegalArgumentException("ChartId cannot be null or empty!"); + } + this.chartId = chartId; + } + + private JSONObject getRequestJsonObject() { + JSONObject chart = new JSONObject(); + chart.put("chartId", chartId); + try { + JSONObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + chart.put("data", data); + } catch (Throwable t) { + if (logFailedRequests) { + Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t); + } + return null; + } + return chart; + } + + protected abstract JSONObject getChartData() throws Exception; + + } + + /** + * Represents a custom simple pie. + */ + public static class SimplePie extends CustomChart { + + private final Callable<String> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable<String> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + data.put("value", value); + return data; + } + } + + /** + * Represents a custom advanced pie. + */ + public static class AdvancedPie extends CustomChart { + + private final Callable<Map<String, Integer>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map<String, Integer> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry<String, Integer> entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; // Skip this invalid + } + allSkipped = false; + values.put(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + } + + /** + * Represents a custom drilldown pie. + */ + public static class DrilldownPie extends CustomChart { + + private final Callable<Map<String, Map<String, Integer>>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map<String, Map<String, Integer>> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) { + JSONObject value = new JSONObject(); + boolean allSkipped = true; + for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) { + value.put(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + values.put(entryValues.getKey(), value); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + } + + /** + * Represents a custom single line chart. + */ + public static class SingleLineChart extends CustomChart { + + private final Callable<Integer> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable<Integer> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + data.put("value", value); + return data; + } + + } + + /** + * Represents a custom multi line chart. + */ + public static class MultiLineChart extends CustomChart { + + private final Callable<Map<String, Integer>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map<String, Integer> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry<String, Integer> entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; // Skip this invalid + } + allSkipped = false; + values.put(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + + } + + /** + * Represents a custom simple bar chart. + */ + public static class SimpleBarChart extends CustomChart { + + private final Callable<Map<String, Integer>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map<String, Integer> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry<String, Integer> entry : map.entrySet()) { + JSONArray categoryValues = new JSONArray(); + categoryValues.add(entry.getValue()); + values.put(entry.getKey(), categoryValues); + } + data.put("values", values); + return data; + } + + } + + /** + * Represents a custom advanced bar chart. + */ + public static class AdvancedBarChart extends CustomChart { + + private final Callable<Map<String, int[]>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map<String, int[]> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry<String, int[]> entry : map.entrySet()) { + if (entry.getValue().length == 0) { + continue; // Skip this invalid + } + allSkipped = false; + JSONArray categoryValues = new JSONArray(); + for (int categoryValue : entry.getValue()) { + categoryValues.add(categoryValue); + } + values.put(entry.getKey(), categoryValues); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + + } +}
\ No newline at end of file diff --git a/src/me/fatpigsarefat/quests/commands/CommandQuests.java b/src/me/fatpigsarefat/quests/commands/CommandQuests.java new file mode 100644 index 00000000..c6ffe540 --- /dev/null +++ b/src/me/fatpigsarefat/quests/commands/CommandQuests.java @@ -0,0 +1,222 @@ +package me.fatpigsarefat.quests.commands; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.obj.Messages; +import me.fatpigsarefat.quests.obj.Options; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.quests.Category; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.tasktypes.TaskType; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class CommandQuests implements CommandExecutor { + + public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { + if (Quests.getInstance().isBrokenConfig()) { + sender.sendMessage(ChatColor.RED + "You have a YAML error in your config and Quests cannot load. If this is your first time using Quests, please " + + "delete the Quests folder and RESTART (not reload!) the server. If you have modified the config, check for errors in a YAML parser."); + 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 = Quests.getPlayerManager().getPlayer(player.getUniqueId()); + qPlayer.openQuests(); + 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")) { + Quests.getInstance().reloadConfig(); + Quests.getInstance().reloadQuests(); + sender.sendMessage(ChatColor.GRAY + "Quests was reloaded."); + return true; + } else if (args[1].equalsIgnoreCase("types")) { + sender.sendMessage(ChatColor.GRAY + "Registered task types:"); + for (TaskType taskType : Quests.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.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 : Quests.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.length == 4) { + if (args[1].equalsIgnoreCase("opengui")) { + if (args[2].equalsIgnoreCase("q") || args[2].equalsIgnoreCase("quests")) { + Player player = Bukkit.getPlayer(args[3]); + if (player != null) { + QPlayer qPlayer = Quests.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer != null) { + qPlayer.openQuests(); + 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")) { + showAdminHelp(sender, "moddata"); + return true; + } + } else if (args.length == 5) { + if (args[2].equalsIgnoreCase("c") || args[2].equalsIgnoreCase("category")) { + if (!Options.CATEGORIES_ENABLED.getBooleanValue()) { + sender.sendMessage(Messages.COMMAND_CATEGORY_OPEN_DISABLED.getMessage()); + return true; + } + Category category = Quests.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 = Quests.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer != null) { + qPlayer.openCategory(category); + sender.sendMessage(Messages.COMMAND_QUEST_OPENCATEGORY_ADMIN_SUCCESS.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; + } + } + + showAdminHelp(sender, null); + return true; + } + if (sender instanceof Player && (args[0].equalsIgnoreCase("q") || args[0].equalsIgnoreCase("quests"))) { + Player player = (Player) sender; + if (args.length >= 2) { + Quest quest = Quests.getQuestManager().getQuestById(args[1]); + if (quest == null) { + sender.sendMessage(Messages.COMMAND_QUEST_START_DOESNTEXIST.getMessage().replace("{quest}", args[1])); + } else { + QPlayer qPlayer = Quests.getPlayerManager().getPlayer(player.getUniqueId()); + if (qPlayer == null) { + // shit + fan + sender.sendMessage(ChatColor.RED + "An error occurred finding your player."); + } else { + qPlayer.getQuestProgressFile().startQuest(quest); + } + } + return true; + } + } else if (sender instanceof Player && (args[0].equalsIgnoreCase("c") || args[0].equalsIgnoreCase("category"))) { + if (!Options.CATEGORIES_ENABLED.getBooleanValue()) { + sender.sendMessage(Messages.COMMAND_CATEGORY_OPEN_DISABLED.getMessage()); + return true; + } + Player player = (Player) sender; + if (args.length >= 2) { + Category category = Quests.getQuestManager().getCategoryById(args[1]); + if (category == null) { + sender.sendMessage(Messages.COMMAND_CATEGORY_OPEN_DOESNTEXIST.getMessage().replace("{category}", args[1])); + } else { + QPlayer qPlayer = Quests.getPlayerManager().getPlayer(player.getUniqueId()); + qPlayer.openCategory(category); + return true; + } + return true; + } + } + showHelp(sender); + return true; + } else { + sender.sendMessage(ChatColor.RED + "Only admin commands are available to non-player senders."); + } + return true; + } + + private void showHelp(CommandSender sender) { + sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "------------=[" + ChatColor.RED + " Quests v" + Quests.getInstance() + .getDescription().getVersion() + " " + ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "]=------------"); + sender.sendMessage(ChatColor.GRAY + "The following commands are available: "); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/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> " + ChatColor.DARK_GRAY + ": start 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 fatpigsarefat " + 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/quest <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 reload " + ChatColor.DARK_GRAY + ": reload Quests configuration"); + } + sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "-----=[" + ChatColor.RED + " requires permission: quests.admin " + + ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "]=-----"); + } +} diff --git a/src/me/fatpigsarefat/quests/events/EventInventory.java b/src/me/fatpigsarefat/quests/events/EventInventory.java new file mode 100644 index 00000000..fae87623 --- /dev/null +++ b/src/me/fatpigsarefat/quests/events/EventInventory.java @@ -0,0 +1,73 @@ +package me.fatpigsarefat.quests.events; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.obj.Options; +import me.fatpigsarefat.quests.obj.misc.QMenu; +import me.fatpigsarefat.quests.obj.misc.QMenuCategory; +import me.fatpigsarefat.quests.obj.misc.QMenuQuest; +import me.fatpigsarefat.quests.quests.Quest; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.UUID; + +public class EventInventory implements Listener { + + private static HashMap<UUID, QMenu> tracker = new HashMap<>(); + private ArrayList<UUID> buffer = new ArrayList<>(); + + public static void track(UUID uuid, QMenu qMenu) { + tracker.put(uuid, qMenu); + } + + @EventHandler + public void onEvent(InventoryClickEvent event) { + if (tracker.containsKey(event.getWhoClicked().getUniqueId())) { + event.setCancelled(true); + QMenu qMenu = tracker.get(event.getWhoClicked().getUniqueId()); + + if (qMenu instanceof QMenuQuest) { + QMenuQuest qMenuQuest = (QMenuQuest) qMenu; + + //TODO check page clicks + + if (Options.CATEGORIES_ENABLED.getBooleanValue() && qMenuQuest.getBackButtonLocation() == event.getSlot()) { + QMenuCategory qMenuCategory = qMenuQuest.getSuperMenu(); + buffer.add(event.getWhoClicked().getUniqueId()); + event.getWhoClicked().openInventory(qMenuCategory.toInventory(1)); + tracker.put(event.getWhoClicked().getUniqueId(), qMenuCategory); + + } else if (qMenuQuest.getSlotsToMenu().containsKey(event.getSlot())) { + String questid = qMenuQuest.getSlotsToMenu().get(event.getSlot()); + Quest quest = Quests.getQuestManager().getQuestById(questid); + if (qMenuQuest.getOwner().getQuestProgressFile().startQuest(quest)) { + event.getWhoClicked().closeInventory(); + } + } + } else if (qMenu instanceof QMenuCategory) { + QMenuCategory qMenuCategory = (QMenuCategory) qMenu; + + if (qMenuCategory.getSlotsToMenu().containsKey(event.getSlot())) { + QMenuQuest qMenuQuest = qMenuCategory.getSlotsToMenu().get(event.getSlot()); + buffer.add(event.getWhoClicked().getUniqueId()); + event.getWhoClicked().openInventory(qMenuQuest.toInventory(1)); + tracker.put(event.getWhoClicked().getUniqueId(), qMenuQuest); + } + } + } + } + + @EventHandler + public void onEvent(InventoryCloseEvent event) { + if (buffer.contains(event.getPlayer().getUniqueId())) { + buffer.remove(event.getPlayer().getUniqueId()); + } else if (tracker.containsKey(event.getPlayer().getUniqueId())) { + tracker.remove(event.getPlayer().getUniqueId()); + } + } + +} diff --git a/src/me/fatpigsarefat/quests/events/EventPlayerJoin.java b/src/me/fatpigsarefat/quests/events/EventPlayerJoin.java new file mode 100644 index 00000000..26805748 --- /dev/null +++ b/src/me/fatpigsarefat/quests/events/EventPlayerJoin.java @@ -0,0 +1,21 @@ +package me.fatpigsarefat.quests.events; + +import me.fatpigsarefat.quests.Quests; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +import java.util.UUID; + +public class EventPlayerJoin implements Listener { + + @EventHandler + public void onEvent(PlayerJoinEvent event) { + UUID playerUuid = event.getPlayer().getUniqueId(); + Quests.getPlayerManager().loadPlayer(playerUuid); + if (Quests.getUpdater().isUpdateReady() && event.getPlayer().hasPermission("quests.admin")) { + event.getPlayer().sendMessage(Quests.getUpdater().getMessage()); + } + } + +} diff --git a/src/me/fatpigsarefat/quests/events/EventPlayerLeave.java b/src/me/fatpigsarefat/quests/events/EventPlayerLeave.java new file mode 100644 index 00000000..15d09a8e --- /dev/null +++ b/src/me/fatpigsarefat/quests/events/EventPlayerLeave.java @@ -0,0 +1,25 @@ +package me.fatpigsarefat.quests.events; + +import me.fatpigsarefat.quests.Quests; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.UUID; + +public class EventPlayerLeave implements Listener { + + @EventHandler + public void onEvent(PlayerQuitEvent event) { + UUID playerUuid = event.getPlayer().getUniqueId(); + new BukkitRunnable() { + @Override + public void run() { + Quests.getPlayerManager().getPlayer(playerUuid).getQuestProgressFile().saveToDisk(); + Quests.getPlayerManager().removePlayer(playerUuid); + } + }.runTaskAsynchronously(Quests.getInstance()); + } + +} diff --git a/src/me/fatpigsarefat/quests/obj/Items.java b/src/me/fatpigsarefat/quests/obj/Items.java new file mode 100644 index 00000000..c8f8b7b8 --- /dev/null +++ b/src/me/fatpigsarefat/quests/obj/Items.java @@ -0,0 +1,23 @@ +package me.fatpigsarefat.quests.obj; + +import me.fatpigsarefat.quests.Quests; +import org.bukkit.inventory.ItemStack; + +public enum Items { + + BACK_BUTTON("gui.back-button"), + QUEST_LOCKED("gui.quest-locked-display"), + QUEST_COOLDOWN("gui.quest-cooldown-display"), + QUEST_COMPLETED("gui.quest-completed-display"); + + String path; + + Items(String path) { + this.path = path; + } + + public ItemStack getItem() { + return Quests.getInstance().getItemStack(path); + } + +} diff --git a/src/me/fatpigsarefat/quests/obj/Messages.java b/src/me/fatpigsarefat/quests/obj/Messages.java new file mode 100644 index 00000000..60eac35d --- /dev/null +++ b/src/me/fatpigsarefat/quests/obj/Messages.java @@ -0,0 +1,45 @@ +package me.fatpigsarefat.quests.obj; + +import me.fatpigsarefat.quests.Quests; +import org.bukkit.ChatColor; + +public enum Messages { + + QUEST_START("messages.quest-start"), + QUEST_COMPLETE("messages.quest-complete"), + 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_UPDATER("messages.quest-updater"), + COMMAND_QUEST_START_DOESNTEXIST("messages.command-quest-start-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"); + + private String path; + + Messages(String path) { + this.path = path; + } + + public String getMessage() { + if (Quests.getInstance().getConfig().contains(path)) { + String message = Quests.getInstance().getConfig().getString(path); + if (message != null) { + return path; + } + } + return path; + } + +} diff --git a/src/me/fatpigsarefat/quests/obj/Options.java b/src/me/fatpigsarefat/quests/obj/Options.java new file mode 100644 index 00000000..d4b63499 --- /dev/null +++ b/src/me/fatpigsarefat/quests/obj/Options.java @@ -0,0 +1,48 @@ +package me.fatpigsarefat.quests.obj; + +import me.fatpigsarefat.quests.Quests; +import org.bukkit.ChatColor; + +import java.util.ArrayList; +import java.util.List; + +public enum Options { + + CATEGORIES_ENABLED("options.categories-enabled"), + TRIM_GUI_SIZE("options.trim-gui-size"), + QUESTS_START_LIMIT("options.quest-started-limit"), + TITLES_ENABLED("options.titles-enabled"); + + private String path; + + Options(String path) { + this.path = path; + } + + public int getIntValue() { + return Quests.getInstance().getConfig().getInt(path); + } + + public String getStringValue() { + return Quests.getInstance().getConfig().getString(path); + } + + public boolean getBooleanValue() { + return Quests.getInstance().getConfig().getBoolean(path); + } + + public List<String> getStringListValue() { + return Quests.getInstance().getConfig().getStringList(path); + } + + public static String color(String s) { + return ChatColor.translateAlternateColorCodes('&', s); + } + public static List<String> color(List<String> s) { + List<String> colored = new ArrayList<>(); + for (String line : s) { + colored.add(ChatColor.translateAlternateColorCodes('&', line)); + } + return colored; + } +} diff --git a/src/me/fatpigsarefat/quests/obj/misc/QItemStack.java b/src/me/fatpigsarefat/quests/obj/misc/QItemStack.java new file mode 100644 index 00000000..efde9f51 --- /dev/null +++ b/src/me/fatpigsarefat/quests/obj/misc/QItemStack.java @@ -0,0 +1,108 @@ +package me.fatpigsarefat.quests.obj.misc; + +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import org.bukkit.Material; +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.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class QItemStack { + + private String name; + private List<String> loreNormal; + private List<String> loreStarted; + private Material type; + private int data; + + public QItemStack(String name, List<String> loreNormal, List<String> loreStarted, Material type, int data) { + this.name = name; + this.loreNormal = loreNormal; + this.loreStarted = loreStarted; + this.type = type; + } + + 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 Material getType() { + return type; + } + + public void setType(Material type) { + this.type = type; + } + + public int getData() { + return data; + } + + public void setData(int data) { + this.data = data; + } + + public ItemStack toItemStack(QuestProgress questProgress) { + ItemStack is = new ItemStack(type, 1, (short) data); + ItemMeta ism = is.getItemMeta(); + ism.setDisplayName(name); + List<String> formattedLore = new ArrayList<>(); + List<String> tempLore = new ArrayList<>(); + tempLore.addAll(loreNormal); + if (questProgress != null && questProgress.isStarted()) { + tempLore.addAll(loreStarted); + ism.addEnchant(Enchantment.ARROW_INFINITE, 1, true); + try { + is.getItemMeta().addItemFlags(ItemFlag.HIDE_ENCHANTS); + } catch (Exception ignored) { + + } + } + if (questProgress != null) { + for (String s : tempLore) { + 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)); + } + } + } + formattedLore.add(s); + } + } + ism.setLore(formattedLore); + is.setItemMeta(ism); + return is; + } +} diff --git a/src/me/fatpigsarefat/quests/obj/misc/QMenu.java b/src/me/fatpigsarefat/quests/obj/misc/QMenu.java new file mode 100644 index 00000000..13629600 --- /dev/null +++ b/src/me/fatpigsarefat/quests/obj/misc/QMenu.java @@ -0,0 +1,12 @@ +package me.fatpigsarefat.quests.obj.misc; + +import me.fatpigsarefat.quests.player.QPlayer; + +import java.util.HashMap; + +public interface QMenu { + + QPlayer getOwner(); + HashMap<?, ?> getSlotsToMenu(); + +} diff --git a/src/me/fatpigsarefat/quests/obj/misc/QMenuCategory.java b/src/me/fatpigsarefat/quests/obj/misc/QMenuCategory.java new file mode 100644 index 00000000..449f81d6 --- /dev/null +++ b/src/me/fatpigsarefat/quests/obj/misc/QMenuCategory.java @@ -0,0 +1,92 @@ +package me.fatpigsarefat.quests.obj.misc; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.obj.Options; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.quests.Category; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.List; + +public class QMenuCategory implements QMenu { + + private final int pageSize = 45; + private HashMap<Integer, QMenuQuest> slotsToMenuQuest = new HashMap<>(); + private QPlayer owner; + + public QMenuCategory(QPlayer owner) { + this.owner = owner; + } + + public void populate(List<QMenuQuest> menuQuests) { + int slot = 0; + for (QMenuQuest qMenuQuest : menuQuests) { + slotsToMenuQuest.put(slot, qMenuQuest); + slot++; + } + } + + @Override + public HashMap<Integer, QMenuQuest> getSlotsToMenu() { + return slotsToMenuQuest; + } + + @Override + public QPlayer getOwner() { + return owner; + } + + public Inventory toInventory(int page) { + int pageMin = pageSize * (page - 1); + int pageMax = pageSize * page; + String title = "Quest Categories"; + + ItemStack pageIs = new ItemStack(Material.DIRT); + + Inventory inventory = Bukkit.createInventory(null, 54, title); //TODO make configurable title + + for (int pointer = pageMin; pointer < pageMax; pointer++) { + if (slotsToMenuQuest.containsKey(pointer)) { + Category category = Quests.getQuestManager().getCategoryById(slotsToMenuQuest.get(pointer).getCategoryName()); + if (category != null) { + inventory.setItem(pointer, category.getDisplayItem()); + } + } + } + + inventory.setItem(49, pageIs); + + if (Options.TRIM_GUI_SIZE.getBooleanValue() && 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 < pageMax; slot++) { + if (slot >= trimmedInventory.getSize()){ + break; + } + trimmedInventory.setItem(slot, inventory.getItem(slot)); + } + return trimmedInventory; + } else { + return inventory; + } + + } + +} diff --git a/src/me/fatpigsarefat/quests/obj/misc/QMenuQuest.java b/src/me/fatpigsarefat/quests/obj/misc/QMenuQuest.java new file mode 100644 index 00000000..4df9df89 --- /dev/null +++ b/src/me/fatpigsarefat/quests/obj/misc/QMenuQuest.java @@ -0,0 +1,177 @@ +package me.fatpigsarefat.quests.obj.misc; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.obj.Items; +import me.fatpigsarefat.quests.obj.Options; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.quests.Quest; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class QMenuQuest implements QMenu { + + private HashMap<Integer, String> slotsToQuestIds = new HashMap<>(); + private int backButtonLocation = -1; + private boolean backButtonEnabled = true; + private QMenuCategory superMenu; + private String categoryName; + private final int pageSize = 45; + private QPlayer owner; + + public QMenuQuest(QPlayer owner, String categoryName, QMenuCategory superMenu) { + this.owner = owner; + this.categoryName = categoryName; + this.superMenu = superMenu; + } + + public void populate(List<Quest> quests) { + int slot = 0; + for (Quest quest : quests) { + slotsToQuestIds.put(slot, quest.getId()); + slot++; + } + } + + @Override + public HashMap<Integer, String> getSlotsToMenu() { + return slotsToQuestIds; + } + + @Override + public QPlayer getOwner() { + return owner; + } + + public String getCategoryName() { + return categoryName; + } + + public Inventory toInventory(int page) { + int pageMin = pageSize * (page - 1); + int pageMax = pageSize * page; + String title = "Quests"; + + ItemStack pageIs = new ItemStack(Material.DIRT); + ItemStack back = Items.BACK_BUTTON.getItem(); + + Inventory inventory = Bukkit.createInventory(null, 54, title); //TODO make configurable title + + int invSlot = 0; + for (int pointer = pageMin; pointer < pageMax; pointer++) { + if (slotsToQuestIds.containsKey(pointer)) { + Quest quest = Quests.getQuestManager().getQuestById(slotsToQuestIds.get(pointer)); + QuestProgress questProgress = owner.getQuestProgressFile().getQuestProgress(quest); + long cooldown = owner.getQuestProgressFile().getCooldownFor(quest); + if (!owner.getQuestProgressFile().hasMetRequirements(quest)) { + List<String> quests = new ArrayList<>(); + for (String requirement : quest.getRequirements()) { + quests.add(Quests.getQuestManager().getQuestById(requirement).getDisplayNameStripped()); + } + Map<String, String> placeholders = new HashMap<>(); + placeholders.put("{quest}", quest.getDisplayNameStripped()); + placeholders.put("{requirements}", String.join(", ", quests)); + ItemStack is = replaceItemStack(Items.QUEST_LOCKED.getItem(), placeholders); + inventory.setItem(invSlot, is); + } else if (!quest.isRepeatable() && questProgress.isCompletedBefore()) { + Map<String, String> placeholders = new HashMap<>(); + placeholders.put("{quest}", quest.getDisplayNameStripped()); + ItemStack is = replaceItemStack(Items.QUEST_COMPLETED.getItem(), placeholders); + inventory.setItem(invSlot, is); + } else if (cooldown > 0) { + Map<String, String> placeholders = new HashMap<>(); + placeholders.put("{time}", Quests.convertToFormat(TimeUnit.MINUTES.convert(cooldown, TimeUnit.MILLISECONDS))); + placeholders.put("{quest}", quest.getDisplayNameStripped()); + ItemStack is = replaceItemStack(Items.QUEST_COOLDOWN.getItem(), placeholders); + inventory.setItem(invSlot, is); + } else { + inventory.setItem(invSlot, Quests.getQuestManager().getQuestById(quest.getId()).getDisplayItem().toItemStack(questProgress)); + } + } + invSlot++; + } + + inventory.setItem(49, pageIs); + + if (Options.CATEGORIES_ENABLED.getBooleanValue() && backButtonEnabled) { + inventory.setItem(45, back); + backButtonLocation = 45; + } + + if (Options.TRIM_GUI_SIZE.getBooleanValue() && 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; + } else if (Options.CATEGORIES_ENABLED.getBooleanValue() && 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 (Options.CATEGORIES_ENABLED.getBooleanValue()) { + trimmedInventory.setItem(slot, back); + backButtonLocation = slot; + } + break; + } + trimmedInventory.setItem(slot, inventory.getItem(slot)); + } + return trimmedInventory; + } else { + return inventory; + } + + //TODO add page controls + } + + public boolean isBackButtonEnabled() { + return backButtonEnabled; + } + + public void setBackButtonEnabled(boolean backButtonEnabled) { + this.backButtonEnabled = backButtonEnabled; + } + + public int getBackButtonLocation() { + return backButtonLocation; + } + + public QMenuCategory getSuperMenu() { + return superMenu; + } + + public ItemStack replaceItemStack(ItemStack is, Map<String, String> placeholders) { + ItemStack newItemStack = is.clone(); + List<String> lore = newItemStack.getItemMeta().getLore(); + List<String> newLore = new ArrayList<>(); + for (String s : lore) { + for (Map.Entry<String, String> entry : placeholders.entrySet()) { + s = s.replace(entry.getKey(), entry.getValue()); + } + newLore.add(s); + } + ItemMeta ism = newItemStack.getItemMeta(); + ism.setLore(newLore); + newItemStack.setItemMeta(ism); + return newItemStack; + } +} diff --git a/src/me/fatpigsarefat/quests/player/QPlayer.java b/src/me/fatpigsarefat/quests/player/QPlayer.java new file mode 100644 index 00000000..27e9283d --- /dev/null +++ b/src/me/fatpigsarefat/quests/player/QPlayer.java @@ -0,0 +1,101 @@ +package me.fatpigsarefat.quests.player; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.events.EventInventory; +import me.fatpigsarefat.quests.obj.Options; +import me.fatpigsarefat.quests.obj.misc.QMenu; +import me.fatpigsarefat.quests.obj.misc.QMenuCategory; +import me.fatpigsarefat.quests.obj.misc.QMenuQuest; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.quests.Category; +import me.fatpigsarefat.quests.quests.Quest; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class QPlayer { + + private UUID uuid; + private QuestProgressFile questProgressFile; + + public QPlayer(UUID uuid, QuestProgressFile questProgressFile) { + this.uuid = uuid; + this.questProgressFile = questProgressFile; + } + + public UUID getUuid() { + return uuid; + } + + public void openCategory(Category category) { + Player player = Bukkit.getPlayer(uuid); + if (player == null) { + return; + } + + QMenuQuest qMenuQuest = new QMenuQuest(Quests.getPlayerManager().getPlayer(player.getUniqueId()), category.getId(), null); + List<Quest> quests = new ArrayList<>(); + for (String questid : category.getRegisteredQuestIds()) { + Quest quest = Quests.getQuestManager().getQuestById(questid); + if (quest != null) { + quests.add(quest); + } + } + qMenuQuest.populate(quests); + qMenuQuest.setBackButtonEnabled(false); + + player.openInventory(qMenuQuest.toInventory(1)); + EventInventory.track(player.getUniqueId(), qMenuQuest); + } + + public void openQuests() { + Player player = Bukkit.getPlayer(uuid); + if (player == null) { + return; + } + + if (Options.CATEGORIES_ENABLED.getBooleanValue()) { + QMenuCategory qMenuCategory = new QMenuCategory(Quests.getPlayerManager().getPlayer(player.getUniqueId())); + List<QMenuQuest> questMenus = new ArrayList<>(); + for (Category category : Quests.getQuestManager().getCategories()) { + QMenuQuest qMenuQuest = new QMenuQuest(Quests.getPlayerManager().getPlayer(player.getUniqueId()), category.getId(), qMenuCategory); + List<Quest> quests = new ArrayList<>(); + for (String questid : category.getRegisteredQuestIds()) { + Quest quest = Quests.getQuestManager().getQuestById(questid); + if (quest != null) { + quests.add(quest); + } + } + qMenuQuest.populate(quests); + questMenus.add(qMenuQuest); + } + qMenuCategory.populate(questMenus); + + player.openInventory(qMenuCategory.toInventory(1)); + EventInventory.track(player.getUniqueId(), qMenuCategory); + } else { + QMenuQuest qMenuQuest = new QMenuQuest(Quests.getPlayerManager().getPlayer(player.getUniqueId()), "", null); + List<Quest> quests = new ArrayList<>(); + for (Map.Entry<String, Quest> entry : Quests.getQuestManager().getQuests().entrySet()) { + quests.add(entry.getValue()); + } + qMenuQuest.populate(quests); + qMenuQuest.setBackButtonEnabled(false); + + player.openInventory(qMenuQuest.toInventory(1)); + EventInventory.track(player.getUniqueId(), qMenuQuest); + } + } + + public QuestProgressFile getQuestProgressFile() { + return questProgressFile; + } + + public QuestProgressFile setQuestProgressFile() { + return questProgressFile; + } +} diff --git a/src/me/fatpigsarefat/quests/player/QPlayerManager.java b/src/me/fatpigsarefat/quests/player/QPlayerManager.java new file mode 100644 index 00000000..2d18bcf3 --- /dev/null +++ b/src/me/fatpigsarefat/quests/player/QPlayerManager.java @@ -0,0 +1,86 @@ +package me.fatpigsarefat.quests.player; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class QPlayerManager { + + private List<QPlayer> qPlayers = new ArrayList<>(); + + public void addPlayer(QPlayer qPlayer) { + qPlayers.add(qPlayer); + } + + public QPlayer getPlayer(UUID uuid) { + for (QPlayer qPlayer : qPlayers) { + if (qPlayer.getUuid().equals(uuid)) { + return qPlayer; + } + } + return null; + } + + public void removePlayer(UUID uuid) { + QPlayer toRemove = null; + for (QPlayer qPlayer : qPlayers) { + if (qPlayer.getUuid().equals(uuid)) { + toRemove = qPlayer; + break; + } + } + if (toRemove != null) { + qPlayers.remove(toRemove); + } + } + + public List<QPlayer> getQPlayers() { + return qPlayers; + } + + public void loadPlayer(UUID uuid) { + if (getPlayer(uuid) == null) { + QuestProgressFile questProgressFile = new QuestProgressFile(uuid); + + File directory = new File(Quests.getInstance().getDataFolder() + File.separator + "playerdata"); + if (directory.exists() && directory.isDirectory()) { + File file = new File(Quests.getInstance().getDataFolder() + File.separator + "playerdata" + File.separator + uuid.toString() + ".yml"); + if (file.exists()) { + YamlConfiguration data = YamlConfiguration.loadConfiguration(file); + if (data.contains("quest-progress")) { + 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(id, completed, completedBefore, completionDate, uuid, started, true); + + for (String taskid : data.getConfigurationSection("quest-progress." + id + ".task-progress").getKeys(false)) { + boolean taskCompleted = data.getBoolean("quest-progress." + id + ".task-progress." + taskid + ".completed"); + Object taskProgression = data.get("quest-progress." + id + ".task-progress." + taskid + ".progress"); + + TaskProgress taskProgress = new TaskProgress(taskid, taskProgression, uuid, taskCompleted); + questProgress.addTaskProgress(taskProgress); + } + + questProgressFile.addQuestProgress(questProgress); + } + } + } + } + + QPlayer qPlayer = new QPlayer(uuid, questProgressFile); + + Quests.getPlayerManager().addPlayer(qPlayer); + } + } + +} diff --git a/src/me/fatpigsarefat/quests/player/questprogressfile/QuestProgress.java b/src/me/fatpigsarefat/quests/player/questprogressfile/QuestProgress.java new file mode 100644 index 00000000..c4fe87b2 --- /dev/null +++ b/src/me/fatpigsarefat/quests/player/questprogressfile/QuestProgress.java @@ -0,0 +1,96 @@ +package me.fatpigsarefat.quests.player.questprogressfile; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class QuestProgress { + + private List<TaskProgress> taskProgress = new ArrayList<>(); + private String questid; + private boolean started; + private boolean completed; + private boolean completedBefore; + private long completionDate; + private UUID player; + private boolean modified; + + public QuestProgress(String questid, boolean completed, boolean completedBefore, long completionDate, UUID player, boolean started) { + this.questid = questid; + this.completed = completed; + this.completedBefore = completedBefore; + this.completionDate = completionDate; + this.player = player; + this.started = started; + } + + public QuestProgress(String questid, boolean completed, boolean completedBefore, long completionDate, UUID player, boolean started, boolean modified) { + this(questid, completed, completedBefore, completionDate, player, started); + this.modified = modified; + } + + public String getQuestId() { + return questid; + } + + public boolean isCompleted() { + return completed; + } + + public void setStarted(boolean started) { + this.started = started; + this.modified = true; + } + + public boolean isStarted() { + return started; + } + + public void setCompleted(boolean completed) { + this.completed = completed; + this.modified = true; + } + + public long getCompletionDate() { + return completionDate; + } + + public void setCompletionDate(long completionDate) { + this.completionDate = completionDate; + this.modified = true; + } + + public UUID getPlayer() { + return player; + } + + public boolean isCompletedBefore() { + return completedBefore; + } + + public void setCompletedBefore(boolean completedBefore) { + this.completedBefore = completedBefore; + this.modified = true; + } + + public void addTaskProgress(TaskProgress taskProgress) { + this.taskProgress.add(taskProgress); + } + + public List<TaskProgress> getTaskProgress() { + return taskProgress; + } + + public TaskProgress getTaskProgress(String taskId) { + for (TaskProgress taskProgress : this.taskProgress) { + if (taskProgress.getTaskId().equals(taskId)) { + return taskProgress; + } + } + return null; + } + + public boolean isWorthSaving() { + return modified; + } +} diff --git a/src/me/fatpigsarefat/quests/player/questprogressfile/QuestProgressFile.java b/src/me/fatpigsarefat/quests/player/questprogressfile/QuestProgressFile.java new file mode 100644 index 00000000..bfc80ad3 --- /dev/null +++ b/src/me/fatpigsarefat/quests/player/questprogressfile/QuestProgressFile.java @@ -0,0 +1,234 @@ +package me.fatpigsarefat.quests.player.questprogressfile; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.obj.Messages; +import me.fatpigsarefat.quests.obj.Options; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.Task; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +public class QuestProgressFile { + + private List<QuestProgress> questProgress = new ArrayList<>(); + private UUID player; + + public QuestProgressFile(UUID player) { + this.player = player; + } + + //TODO change back to quest id to save performance + + public boolean completeQuest(Quest quest) { + QuestProgress questProgress = getQuestProgress(quest); + questProgress.setStarted(false); + questProgress.setCompleted(true); + questProgress.setCompletedBefore(true); + questProgress.setCompletionDate(System.currentTimeMillis()); + if (Bukkit.getPlayer(player) != null) { + Player player = Bukkit.getPlayer(this.player); + for (String s : quest.getRewards()) { + Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), s.replace("{player}", player.getName())); + } + player.sendMessage(Messages.QUEST_COMPLETE.getMessage().replace("{quest}", quest.getDisplayNameStripped())); + if (Options.TITLES_ENABLED.getBooleanValue()) { + Quests.getTitle().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)); + } + } + return true; + } + + public boolean startQuest(Quest quest) { + if (getStartedQuests().size() >= Options.QUESTS_START_LIMIT.getIntValue()) { + if (Bukkit.getPlayer(player) != null) { + Player player = Bukkit.getPlayer(getPlayer()); + player.sendMessage(Messages.QUEST_START_LIMIT.getMessage().replace("{limit}", String.valueOf(Options.QUESTS_START_LIMIT.getIntValue()))); + } + return false; + } + QuestProgress questProgress = getQuestProgress(quest); + if (!quest.isRepeatable() && questProgress.isCompletedBefore()) { + if (Bukkit.getPlayer(player) != null) { + Player player = Bukkit.getPlayer(getPlayer()); + player.sendMessage(Messages.QUEST_START_DISABLED.getMessage()); + } + return false; + } + long cooldown = getCooldownFor(quest); + if (cooldown > 0) { + if (Bukkit.getPlayer(player) != null) { + Player player = Bukkit.getPlayer(getPlayer()); + player.sendMessage(Messages.QUEST_START_COOLDOWN.getMessage().replace("{time}", String.valueOf(Quests.convertToFormat(TimeUnit.MINUTES.convert(cooldown, TimeUnit.MILLISECONDS))))); + } + return false; + } + if (!hasMetRequirements(quest)) { + if (Bukkit.getPlayer(player) != null) { + Player player = Bukkit.getPlayer(getPlayer()); + player.sendMessage(Messages.QUEST_START_LOCKED.getMessage()); + } + return false; + } + questProgress.setStarted(true); + for (TaskProgress taskProgress : questProgress.getTaskProgress()) { + taskProgress.setCompleted(false); + taskProgress.setProgress(null); + } + questProgress.setCompleted(false); + if (Bukkit.getPlayer(player) != null) { + Player player = Bukkit.getPlayer(getPlayer()); + player.sendMessage(Messages.QUEST_START.getMessage().replace("{quest}", quest.getDisplayNameStripped())); + if (Options.TITLES_ENABLED.getBooleanValue()) { + Quests.getTitle().sendTitle(player, Messages.TITLE_QUEST_START_TITLE.getMessage().replace("{quest}", quest + .getDisplayNameStripped()), Messages.TITLE_QUEST_START_SUBTITLE.getMessage().replace("{quest}", quest + .getDisplayNameStripped())); + } + } + return true; + } + + public void addQuestProgress(QuestProgress questProgress) { + this.questProgress.add(questProgress); + } + + public List<Quest> getStartedQuests() { + List<Quest> startedQuests = new ArrayList<>(); + for (QuestProgress questProgress : questProgress) { + if (questProgress.isStarted()) { + startedQuests.add(Quests.getQuestManager().getQuestById(questProgress.getQuestId())); + } + } + return startedQuests; + } + + public boolean hasQuestProgress(Quest quest) { + for (QuestProgress questProgress : this.questProgress) { + if (questProgress.getQuestId().equals(quest.getId())) { + return true; + } + } + return false; + } + + public boolean hasStartedQuest(Quest quest) { + //TODO always return true if the need for starting quests is disabled & requirements are met + if (hasQuestProgress(quest)) { + if (getQuestProgress(quest).isStarted()) { + return true; + } + } + return false; + } + + public long getCooldownFor(Quest quest) { + QuestProgress questProgress = getQuestProgress(quest); + if (quest.isCooldownEnabled() && questProgress.isCompleted()) { + if (questProgress.getCompletionDate() > 0) { + long date = questProgress.getCompletionDate(); + return (date + TimeUnit.MILLISECONDS.convert(quest.getCooldown(), TimeUnit.MINUTES)) - System.currentTimeMillis(); + } + } + return 0; + } + + public boolean hasMetRequirements(Quest quest) { + for (String id : quest.getRequirements()) { + Quest q = Quests.getQuestManager().getQuestById(id); + if (q == null) { + continue; + } + if (hasQuestProgress(q) && !getQuestProgress(q).isCompletedBefore()) { + return false; + } else if (!hasQuestProgress(q)) { + return false; + } + } + return true; + } + + public UUID getPlayer() { + return player; + } + + public QuestProgress getQuestProgress(Quest quest) { + for (QuestProgress questProgress : this.questProgress) { + if (questProgress.getQuestId().equals(quest.getId())) { + return questProgress; + } + } + if (generateBlankQuestProgress(quest.getId())) { + return getQuestProgress(quest); + } + return null; + } + + public boolean generateBlankQuestProgress(String questid) { + if (Quests.getQuestManager().getQuestById(questid) != null) { + Quest quest = Quests.getQuestManager().getQuestById(questid); + QuestProgress questProgress = new QuestProgress(quest.getId(), false, false, 0, player, false, false); + for (Task task : quest.getTasks()) { + TaskProgress taskProgress = new TaskProgress(task.getId(), null, player, false); + questProgress.addTaskProgress(taskProgress); + } + + this.questProgress.add(questProgress); + return true; + } + return false; + } + + public void saveToDisk() { + File directory = new File(Quests.getInstance().getDataFolder() + File.separator + "playerdata"); + if (!directory.exists() && !directory.isDirectory()) { + directory.mkdirs(); + } + File file = new File(Quests.getInstance().getDataFolder() + File.separator + "playerdata" + File.separator + player.toString() + ".yml"); + if (!file.exists()) { + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + YamlConfiguration data = YamlConfiguration.loadConfiguration(file); + data.set("quest-progress", null); + for (QuestProgress questProgress : this.questProgress) { + if (!questProgress.isWorthSaving()) { + continue; + } + data.set("quest-progress." + questProgress.getQuestId() + ".started", questProgress.isStarted()); + data.set("quest-progress." + questProgress.getQuestId() + ".completed", questProgress.isCompleted()); + data.set("quest-progress." + questProgress.getQuestId() + ".completed-before", questProgress.isCompletedBefore()); + 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()); + } + } + + try { + data.save(file); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} + diff --git a/src/me/fatpigsarefat/quests/player/questprogressfile/TaskProgress.java b/src/me/fatpigsarefat/quests/player/questprogressfile/TaskProgress.java new file mode 100644 index 00000000..3b896334 --- /dev/null +++ b/src/me/fatpigsarefat/quests/player/questprogressfile/TaskProgress.java @@ -0,0 +1,41 @@ +package me.fatpigsarefat.quests.player.questprogressfile; + +import java.util.UUID; + +public class TaskProgress { + + private String taskid; + private Object progress; + private UUID player; + private boolean completed; + + public TaskProgress(String taskid, Object progress, UUID player, boolean completed) { + this.taskid = taskid; + this.progress = progress; + this.completed = completed; + } + + public String getTaskId() { + return taskid; + } + + public Object getProgress() { + return progress; + } + + public void setProgress(Object progress) { + this.progress = progress; + } + + public UUID getPlayer() { + return player; + } + + public boolean isCompleted() { + return completed; + } + + public void setCompleted(boolean complete) { + this.completed = complete; + } +} diff --git a/src/me/fatpigsarefat/quests/quests/Category.java b/src/me/fatpigsarefat/quests/quests/Category.java new file mode 100644 index 00000000..b17f6db7 --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/Category.java @@ -0,0 +1,42 @@ +package me.fatpigsarefat.quests.quests; + +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; + +public class Category { + + private String id; + private ItemStack displayItem; + private List<String> registeredQuestIds = new ArrayList<>(); + + public Category(String id, ItemStack displayItem) { + this.id = id; + this.displayItem = displayItem; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public ItemStack getDisplayItem() { + return displayItem; + } + + public void setDisplayItem(ItemStack displayItem) { + this.displayItem = displayItem; + } + + public void registerQuestId(String questid) { + registeredQuestIds.add(questid); + } + + public List<String> getRegisteredQuestIds() { + return registeredQuestIds; + } +} diff --git a/src/me/fatpigsarefat/quests/quests/Quest.java b/src/me/fatpigsarefat/quests/quests/Quest.java new file mode 100644 index 00000000..239cd4fe --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/Quest.java @@ -0,0 +1,96 @@ +package me.fatpigsarefat.quests.quests; + +import me.fatpigsarefat.quests.obj.misc.QItemStack; +import org.bukkit.ChatColor; + +import java.util.ArrayList; +import java.util.List; + +public class Quest { + + private List<Task> tasks = new ArrayList<>(); + private String id; + private QItemStack displayItem; + private List<String> rewards; + private List<String> requirements; + private List<String> rewardString; + private boolean repeatable; + private boolean cooldownEnabled; + private int cooldown; + private String categoryid; + + + public Quest(String id, QItemStack displayItem, List<String> rewards, List<String> requirements, boolean repeatable, boolean cooldownEnabled, int cooldown, List<String> rewardString, String categoryid) { + this(id, displayItem, rewards, requirements, repeatable, cooldownEnabled, cooldown, rewardString); + this.categoryid = categoryid; + } + + public Quest(String id, QItemStack displayItem, List<String> rewards, List<String> requirements, boolean repeatable, boolean cooldownEnabled, int cooldown, List<String> rewardString) { + this.id = id; + this.displayItem = displayItem; + this.rewards = rewards; + this.requirements = requirements; + this.repeatable = repeatable; + this.cooldownEnabled = cooldownEnabled; + this.cooldown = cooldown; + this.rewardString = rewardString; + } + + public void registerTask(Task task) { + tasks.add(task); + } + + public List<Task> getTasks() { + return tasks; + } + + public List<Task> getTasksOfType(String type) { + List<Task> tasks = new ArrayList<>(); + for (Task task : this.tasks) { + if (task.getType().equals(type)) { + tasks.add(task); + } + } + return tasks; + } + + public List<String> getRewardString() { + return rewardString; + } + + public String getId() { + return id; + } + + public QItemStack getDisplayItem() { + return displayItem; + } + + public List<String> getRewards() { + return rewards; + } + + public List<String> getRequirements() { + return requirements; + } + + public boolean isRepeatable() { + return repeatable; + } + + public boolean isCooldownEnabled() { + return cooldownEnabled; + } + + public int getCooldown() { + return cooldown; + } + + public String getCategoryId() { + return categoryid; + } + + public String getDisplayNameStripped() { + return ChatColor.stripColor(this.displayItem.getName()); + } +} diff --git a/src/me/fatpigsarefat/quests/quests/QuestManager.java b/src/me/fatpigsarefat/quests/quests/QuestManager.java new file mode 100644 index 00000000..1ec6ea63 --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/QuestManager.java @@ -0,0 +1,38 @@ +package me.fatpigsarefat.quests.quests; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class QuestManager { + + private Map<String, Quest> quests = new LinkedHashMap<>(); + private List<Category> categories = new ArrayList<>(); + + public void registerQuest(Quest quest) { + quests.put(quest.getId(), quest); + } + + public Quest getQuestById(String id) { + return quests.get(id); + } + + public Map<String, Quest> getQuests() { + return quests; + } + + public void registerCategory(Category category) { categories.add(category); } + + public List<Category> getCategories() { + return categories; + } + + public Category getCategoryById(String id) { + for (Category category : categories) { + if (category.getId().equals(id)) return category; + } + return null; + } + +} diff --git a/src/me/fatpigsarefat/quests/quests/Task.java b/src/me/fatpigsarefat/quests/quests/Task.java new file mode 100644 index 00000000..fb209145 --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/Task.java @@ -0,0 +1,38 @@ +package me.fatpigsarefat.quests.quests; + +import java.util.HashMap; +import java.util.Map; + +public class Task { + + private Map<String, Object> configValues = new HashMap<>(); + + private String id; + private String type; + + public Task(String id, String type) { + this.id = id; + this.type = type; + } + + public String getId() { + return id; + } + + public String getType() { + return type; + } + + public Object getConfigValue(String key) { + return configValues.getOrDefault(key, null); + } + + public Map<String, Object> getConfigValues() { + return configValues; + } + + public void addConfigValue(String key, Object value) { + configValues.put(key, value); + } + +} diff --git a/src/me/fatpigsarefat/quests/quests/tasktypes/ASkyBlockLevelType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/ASkyBlockLevelType.java new file mode 100644 index 00000000..e86b5a0b --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/ASkyBlockLevelType.java @@ -0,0 +1,52 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import com.wasteofplastic.askyblock.events.IslandPostLevelEvent; +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.Task; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +public final class ASkyBlockLevelType extends TaskType { + + public ASkyBlockLevelType() { + super("askyblock_level", "fatpigsarefat", "Reach a certain island level for ASkyBlock."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onIslandLevel(IslandPostLevelEvent event) { + QPlayer qPlayer = Quests.getPlayerManager().getPlayer(event.getPlayer()); + if (qPlayer == null) { + return; + } + + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + + for (Quest quest : super.getRegisteredQuests()) { + if (questProgressFile.hasStartedQuest(quest)) { + QuestProgress questProgress = questProgressFile.getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + long islandLevelNeeded = (long) (int) task.getConfigValue("level"); + + taskProgress.setProgress(event.getLongLevel()); + + if (((long) taskProgress.getProgress()) >= islandLevelNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/src/me/fatpigsarefat/quests/quests/tasktypes/BuildingCertainTaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/BuildingCertainTaskType.java new file mode 100644 index 00000000..8a2add5d --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/BuildingCertainTaskType.java @@ -0,0 +1,72 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.Task; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockPlaceEvent; + +public final class BuildingCertainTaskType extends TaskType { + + public BuildingCertainTaskType() { + super("blockplacecertain", "fatpigsarefat", "Place a set amount of a specific block."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) { + QPlayer qPlayer = Quests.getPlayerManager().getPlayer(event.getPlayer().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; + } + + Material material; + Object configBlock = task.getConfigValue("block"); + Object configData = task.getConfigValue("data"); + + if (StringUtils.isNumeric(String.valueOf(configBlock))) { + material = Material.getMaterial((int) configBlock); + } else { + material = Material.getMaterial(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/src/me/fatpigsarefat/quests/quests/tasktypes/BuildingTaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/BuildingTaskType.java new file mode 100644 index 00000000..17d8247b --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/BuildingTaskType.java @@ -0,0 +1,55 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.Task; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockPlaceEvent; + +public final class BuildingTaskType extends TaskType { + + public BuildingTaskType() { + super("blockplace", "fatpigsarefat", "Place a set amount of blocks."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) { + QPlayer qPlayer = Quests.getPlayerManager().getPlayer(event.getPlayer().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 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/src/me/fatpigsarefat/quests/quests/tasktypes/FishingTaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/FishingTaskType.java new file mode 100644 index 00000000..fac0bbda --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/FishingTaskType.java @@ -0,0 +1,61 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.Task; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerFishEvent; + +public final class FishingTaskType extends TaskType { + + public FishingTaskType() { + super("fishing", "fatpigsarefat", "Catch a set amount of items from the sea."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onFishCaught(PlayerFishEvent event) { + if (event.getState() == PlayerFishEvent.State.CAUGHT_FISH) { + return; + } + Player player = event.getPlayer(); + + 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 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/src/me/fatpigsarefat/quests/quests/tasktypes/MilkingTaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/MilkingTaskType.java new file mode 100644 index 00000000..81a08dca --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/MilkingTaskType.java @@ -0,0 +1,64 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.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; + +public final class MilkingTaskType extends TaskType { + + public MilkingTaskType() { + super("milking", "fatpigsarefat", "Milk a set amount of cows."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMilk(PlayerInteractEntityEvent event) { + if (!(event.getRightClicked() instanceof Cow) || (event.getPlayer().getItemInHand().getType() != Material.BUCKET)) { + return; + } + + Player player = event.getPlayer(); + + 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 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/src/me/fatpigsarefat/quests/quests/tasktypes/MiningCertainTaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/MiningCertainTaskType.java new file mode 100644 index 00000000..a53d2373 --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/MiningCertainTaskType.java @@ -0,0 +1,72 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.Task; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockBreakEvent; + +public final class MiningCertainTaskType extends TaskType { + + public MiningCertainTaskType() { + super("blockbreakcertain", "fatpigsarefat", "Break a set amount of a specific block."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockBreakEvent event) { + QPlayer qPlayer = Quests.getPlayerManager().getPlayer(event.getPlayer().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; + } + + Material material; + Object configBlock = task.getConfigValue("block"); + Object configData = task.getConfigValue("data"); + + if (StringUtils.isNumeric(String.valueOf(configBlock))) { + material = Material.getMaterial((int) configBlock); + } else { + material = Material.getMaterial(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/src/me/fatpigsarefat/quests/quests/tasktypes/MiningTaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/MiningTaskType.java new file mode 100644 index 00000000..a0bcb4bf --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/MiningTaskType.java @@ -0,0 +1,56 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.Task; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockBreakEvent; + +public final class MiningTaskType extends TaskType { + + public MiningTaskType() { + // type, author, description + super("blockbreak", "fatpigsarefat", "Break a set amount of blocks."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockBreak(BlockBreakEvent event) { + QPlayer qPlayer = Quests.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); // get the qplayer so you can get their progress + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); // the quest progress file stores progress about all quests and tasks + + for (Quest quest : super.getRegisteredQuests()) { // iterate through all quests which are registered to use this task type + if (questProgressFile.hasStartedQuest(quest)) { // check if the player has actually started the quest before progressing it + QuestProgress questProgress = questProgressFile.getQuestProgress(quest); // get their progress for the specific quest + + for (Task task : quest.getTasksOfType(super.getType())) { // get all tasks of this type + 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/src/me/fatpigsarefat/quests/quests/tasktypes/MobkillingCertainTaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/MobkillingCertainTaskType.java new file mode 100644 index 00000000..11848918 --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/MobkillingCertainTaskType.java @@ -0,0 +1,91 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.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; + +public final class MobkillingCertainTaskType extends TaskType { + + public MobkillingCertainTaskType() { + super("mobkillingcertain", "fatpigsarefat", "Kill a set amount of a specific entity type."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMobKill(EntityDeathEvent event) { + Entity killer = event.getEntity().getKiller(); + Entity mob = event.getEntity(); + + if (mob instanceof Player) { + return; + } + + if (killer == null) { + return; + } + + Player player = event.getEntity().getKiller(); + + 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; + } + + String configEntity = (String) task.getConfigValue("mob"); + String configName = (String) task.getConfigValue("name"); + + EntityType entity = EntityType.fromName(configEntity); + if (entity == null) { + continue; + } + + if (configName != null) { + configName = ChatColor.translateAlternateColorCodes('&', configName); + if (!mob.getCustomName().equals(configName)) { + return; + } + } + + 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/src/me/fatpigsarefat/quests/quests/tasktypes/MobkillingTaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/MobkillingTaskType.java new file mode 100644 index 00000000..cdc3449d --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/MobkillingTaskType.java @@ -0,0 +1,87 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.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; + +public final class MobkillingTaskType extends TaskType { + + public MobkillingTaskType() { + super("mobkilling", "fatpigsarefat", "Kill a set amount of entities."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMobKill(EntityDeathEvent event) { + Entity killer = event.getEntity().getKiller(); + Entity mob = event.getEntity(); + + if (mob instanceof Player) { + return; + } + + if (killer == null) { + return; + } + + Player player = event.getEntity().getKiller(); + + 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; + } + + 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/src/me/fatpigsarefat/quests/quests/tasktypes/PlayerkillingTaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/PlayerkillingTaskType.java new file mode 100644 index 00000000..2edf5282 --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/PlayerkillingTaskType.java @@ -0,0 +1,70 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.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; + +public final class PlayerkillingTaskType extends TaskType { + + public PlayerkillingTaskType() { + super("playerkilling", "fatpigsarefat", "Kill a set amount of players."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onMobKill(EntityDeathEvent event) { + Entity killer = event.getEntity().getKiller(); + Entity mob = event.getEntity(); + + if (!(mob instanceof Player)) { + return; + } + + if (killer == null) { + return; + } + + Player player = event.getEntity().getKiller(); + + 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 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/src/me/fatpigsarefat/quests/quests/tasktypes/ShearingTaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/ShearingTaskType.java new file mode 100644 index 00000000..57e36980 --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/ShearingTaskType.java @@ -0,0 +1,63 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.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; + +public final class ShearingTaskType extends TaskType { + + public ShearingTaskType() { + super("shearing", "fatpigsarefat", "Shear a set amount of sheep."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onShear(PlayerShearEntityEvent event) { + if (!(event.getEntity() instanceof Sheep)) { + return; + } + + Player player = event.getPlayer(); + + 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 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/src/me/fatpigsarefat/quests/quests/tasktypes/TamingTaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/TamingTaskType.java new file mode 100644 index 00000000..5227d6fe --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/TamingTaskType.java @@ -0,0 +1,62 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.Task; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityTameEvent; + +public final class TamingTaskType extends TaskType { + + public TamingTaskType() { + super("taming", "fatpigsarefat", "Tame a set amount of animals."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onTame(EntityTameEvent event) { + if (!(event.getOwner() instanceof Player)) { + return; + } + + Player player = (Player) event.getOwner(); + + 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 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/src/me/fatpigsarefat/quests/quests/tasktypes/TaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/TaskType.java new file mode 100644 index 00000000..d84d13ba --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/TaskType.java @@ -0,0 +1,52 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.quests.Quest; +import org.bukkit.event.Listener; + +import java.util.ArrayList; +import java.util.List; + +public abstract class TaskType implements Listener { + + private List<Quest> quests = new ArrayList<>(); + private String type; + private String author; + private String description; + + public TaskType(String type, String author, String description) { + this.type = type; + this.author = author; + this.description = description; + } + + public TaskType(String type) { + this.type = type; + } + + public final void registerQuest(Quest quest) { + if (!quests.contains(quest)) { + quests.add(quest); + } + } + + public final void unregisterAll() { + quests.clear(); + } + + public final List<Quest> getRegisteredQuests() { + return quests; + } + + + public final String getType() { + return type; + } + + public String getAuthor() { + return author; + } + + public String getDescription() { + return description; + } +} diff --git a/src/me/fatpigsarefat/quests/quests/tasktypes/TaskTypeManager.java b/src/me/fatpigsarefat/quests/quests/tasktypes/TaskTypeManager.java new file mode 100644 index 00000000..163e128c --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/TaskTypeManager.java @@ -0,0 +1,40 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.Task; +import org.bukkit.Bukkit; + +import java.util.ArrayList; +import java.util.logging.Level; + +public class TaskTypeManager { + + private ArrayList<TaskType> taskTypes = new ArrayList<>(); + + public ArrayList<TaskType> getTaskTypes() { + return taskTypes; + } + + public void resetTaskTypes() { + for (TaskType taskType : taskTypes) { + taskType.getRegisteredQuests().clear(); + } + } + + public void registerTaskType(TaskType taskType) { + Bukkit.getPluginManager().registerEvents(taskType, Quests.getInstance()); + Quests.getInstance().getLogger().log(Level.INFO, "Task type " + taskType.getType() + " has been registered."); + taskTypes.add(taskType); + } + + public void registerQuestTasksWithTaskTypes(Quest quest) { + for (Task task : quest.getTasks()) { + for (TaskType taskType : taskTypes) { + if (taskType.getType().equalsIgnoreCase(task.getType())) { + taskType.registerQuest(quest); + } + } + } + } +} diff --git a/src/me/fatpigsarefat/quests/quests/tasktypes/WalkingTaskType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/WalkingTaskType.java new file mode 100644 index 00000000..0256096e --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/WalkingTaskType.java @@ -0,0 +1,62 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.Task; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerMoveEvent; + +public final class WalkingTaskType extends TaskType { + + public WalkingTaskType() { + super("walking", "fatpigsarefat", "Walk a set distance."); + } + + @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(); + + 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 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/src/me/fatpigsarefat/quests/quests/tasktypes/uSkyBlockLevelType.java b/src/me/fatpigsarefat/quests/quests/tasktypes/uSkyBlockLevelType.java new file mode 100644 index 00000000..89950c25 --- /dev/null +++ b/src/me/fatpigsarefat/quests/quests/tasktypes/uSkyBlockLevelType.java @@ -0,0 +1,52 @@ +package me.fatpigsarefat.quests.quests.tasktypes; + +import me.fatpigsarefat.quests.Quests; +import me.fatpigsarefat.quests.player.QPlayer; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgress; +import me.fatpigsarefat.quests.player.questprogressfile.QuestProgressFile; +import me.fatpigsarefat.quests.player.questprogressfile.TaskProgress; +import me.fatpigsarefat.quests.quests.Quest; +import me.fatpigsarefat.quests.quests.Task; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import us.talabrek.ultimateskyblock.api.event.uSkyBlockScoreChangedEvent; + +public final class uSkyBlockLevelType extends TaskType { + + public uSkyBlockLevelType() { + super("uskyblock_level", "fatpigsarefat", "Reach a certain island level for uSkyBlock."); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onIslandLevel(uSkyBlockScoreChangedEvent event) { + QPlayer qPlayer = Quests.getPlayerManager().getPlayer(event.getPlayer().getUniqueId()); + if (qPlayer == null) { + return; + } + + QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + + for (Quest quest : super.getRegisteredQuests()) { + if (questProgressFile.hasStartedQuest(quest)) { + QuestProgress questProgress = questProgressFile.getQuestProgress(quest); + + for (Task task : quest.getTasksOfType(super.getType())) { + TaskProgress taskProgress = questProgress.getTaskProgress(task.getId()); + + if (taskProgress.isCompleted()) { + continue; + } + + double islandLevelNeeded = (double) (int) task.getConfigValue("level"); + + taskProgress.setProgress(event.getScore().getScore()); + + if (((double) taskProgress.getProgress()) >= islandLevelNeeded) { + taskProgress.setCompleted(true); + } + } + } + } + } + +} diff --git a/src/me/fatpigsarefat/quests/title/Title.java b/src/me/fatpigsarefat/quests/title/Title.java new file mode 100644 index 00000000..4851440b --- /dev/null +++ b/src/me/fatpigsarefat/quests/title/Title.java @@ -0,0 +1,8 @@ +package me.fatpigsarefat.quests.title; + +import org.bukkit.entity.Player; + +public interface Title { + + public void sendTitle(Player player, String message, String submessage); +}
\ No newline at end of file diff --git a/src/me/fatpigsarefat/quests/title/Title_Other.java b/src/me/fatpigsarefat/quests/title/Title_Other.java new file mode 100644 index 00000000..eef4bc07 --- /dev/null +++ b/src/me/fatpigsarefat/quests/title/Title_Other.java @@ -0,0 +1,19 @@ +package me.fatpigsarefat.quests.title; + +import org.bukkit.entity.Player; + +public class Title_Other implements Title { + + @Override + public void sendTitle(Player player, String message, String submessage) { + /* + I'm too lazy to do a null check each time I want to send a title, so here. + Anyway, hello there programmer! I see you're rummaging through my source code. + Try not to leave a mess please. If you see anything dodgy or looks like it + could do with a little improvement make a pull request. + Also join my discord: https://discord.gg/8amrJnX + Have a great day! + - fatpigsarefat + */ + } +} diff --git a/src/me/fatpigsarefat/quests/title/Title_v1_10_R1.java b/src/me/fatpigsarefat/quests/title/Title_v1_10_R1.java new file mode 100644 index 00000000..b91cdbfc --- /dev/null +++ b/src/me/fatpigsarefat/quests/title/Title_v1_10_R1.java @@ -0,0 +1,22 @@ +package me.fatpigsarefat.quests.title; + +import net.minecraft.server.v1_10_R1.IChatBaseComponent.ChatSerializer; +import net.minecraft.server.v1_10_R1.PacketPlayOutTitle; +import net.minecraft.server.v1_10_R1.PacketPlayOutTitle.EnumTitleAction; +import org.bukkit.craftbukkit.v1_10_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class Title_v1_10_R1 implements Title { + + @Override + public void sendTitle(Player player, String message, String submessage) { + message = "{\"text\":\"" + message + "\"}"; + PacketPlayOutTitle title = new PacketPlayOutTitle(EnumTitleAction.TITLE, ChatSerializer.a(message), 10, 100, + 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(title); + submessage = "{\"text\":\"" + submessage + "\"}"; + PacketPlayOutTitle subtitle = new PacketPlayOutTitle(EnumTitleAction.SUBTITLE, ChatSerializer.a(submessage), 10, + 100, 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(subtitle); + } +} diff --git a/src/me/fatpigsarefat/quests/title/Title_v1_11_R1.java b/src/me/fatpigsarefat/quests/title/Title_v1_11_R1.java new file mode 100644 index 00000000..1cb522e1 --- /dev/null +++ b/src/me/fatpigsarefat/quests/title/Title_v1_11_R1.java @@ -0,0 +1,22 @@ +package me.fatpigsarefat.quests.title; + +import net.minecraft.server.v1_11_R1.IChatBaseComponent.ChatSerializer; +import net.minecraft.server.v1_11_R1.PacketPlayOutTitle; +import net.minecraft.server.v1_11_R1.PacketPlayOutTitle.EnumTitleAction; +import org.bukkit.craftbukkit.v1_11_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class Title_v1_11_R1 implements Title { + + @Override + public void sendTitle(Player player, String message, String submessage) { + message = "{\"text\":\"" + message + "\"}"; + PacketPlayOutTitle title = new PacketPlayOutTitle(EnumTitleAction.TITLE, ChatSerializer.a(message), 10, 100, + 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(title); + submessage = "{\"text\":\"" + submessage + "\"}"; + PacketPlayOutTitle subtitle = new PacketPlayOutTitle(EnumTitleAction.SUBTITLE, ChatSerializer.a(submessage), 10, + 100, 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(subtitle); + } +} diff --git a/src/me/fatpigsarefat/quests/title/Title_v1_12_R1.java b/src/me/fatpigsarefat/quests/title/Title_v1_12_R1.java new file mode 100644 index 00000000..61a221fa --- /dev/null +++ b/src/me/fatpigsarefat/quests/title/Title_v1_12_R1.java @@ -0,0 +1,22 @@ +package me.fatpigsarefat.quests.title; + +import net.minecraft.server.v1_12_R1.IChatBaseComponent.ChatSerializer; +import net.minecraft.server.v1_12_R1.PacketPlayOutTitle; +import net.minecraft.server.v1_12_R1.PacketPlayOutTitle.EnumTitleAction; +import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class Title_v1_12_R1 implements Title { + + @Override + public void sendTitle(Player player, String message, String submessage) { + message = "{\"text\":\"" + message + "\"}"; + PacketPlayOutTitle title = new PacketPlayOutTitle(EnumTitleAction.TITLE, ChatSerializer.a(message), 10, 100, + 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(title); + submessage = "{\"text\":\"" + submessage + "\"}"; + PacketPlayOutTitle subtitle = new PacketPlayOutTitle(EnumTitleAction.SUBTITLE, ChatSerializer.a(submessage), 10, + 100, 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(subtitle); + } +} diff --git a/src/me/fatpigsarefat/quests/title/Title_v1_8_R1.java b/src/me/fatpigsarefat/quests/title/Title_v1_8_R1.java new file mode 100644 index 00000000..e6c7dbcb --- /dev/null +++ b/src/me/fatpigsarefat/quests/title/Title_v1_8_R1.java @@ -0,0 +1,23 @@ +package me.fatpigsarefat.quests.title; + +import net.minecraft.server.v1_8_R1.ChatSerializer; +import net.minecraft.server.v1_8_R1.EnumTitleAction; +import net.minecraft.server.v1_8_R1.PacketPlayOutTitle; +import org.bukkit.craftbukkit.v1_8_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class Title_v1_8_R1 implements Title { + + @Override + public void sendTitle(Player player, String message, String submessage) { + message = "{\"text\":\"" + message + "\"}"; + PacketPlayOutTitle title = new PacketPlayOutTitle(EnumTitleAction.TITLE, ChatSerializer.a(message), 10, 100, + 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(title); + submessage = "{\"text\":\"" + submessage + "\"}"; + PacketPlayOutTitle subtitle = new PacketPlayOutTitle(EnumTitleAction.SUBTITLE, ChatSerializer.a(submessage), 10, + 100, 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(subtitle); + } + +}
\ No newline at end of file diff --git a/src/me/fatpigsarefat/quests/title/Title_v1_8_R2.java b/src/me/fatpigsarefat/quests/title/Title_v1_8_R2.java new file mode 100644 index 00000000..3e76e001 --- /dev/null +++ b/src/me/fatpigsarefat/quests/title/Title_v1_8_R2.java @@ -0,0 +1,22 @@ +package me.fatpigsarefat.quests.title; + +import net.minecraft.server.v1_8_R2.IChatBaseComponent.ChatSerializer; +import net.minecraft.server.v1_8_R2.PacketPlayOutTitle; +import net.minecraft.server.v1_8_R2.PacketPlayOutTitle.EnumTitleAction; +import org.bukkit.craftbukkit.v1_8_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class Title_v1_8_R2 implements Title { + + @Override + public void sendTitle(Player player, String message, String submessage) { + message = "{\"text\":\"" + message + "\"}"; + PacketPlayOutTitle title = new PacketPlayOutTitle(EnumTitleAction.TITLE, ChatSerializer.a(message), 10, 100, + 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(title); + submessage = "{\"text\":\"" + submessage + "\"}"; + PacketPlayOutTitle subtitle = new PacketPlayOutTitle(EnumTitleAction.SUBTITLE, ChatSerializer.a(submessage), 10, + 100, 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(subtitle); + } +}
\ No newline at end of file diff --git a/src/me/fatpigsarefat/quests/title/Title_v1_8_R3.java b/src/me/fatpigsarefat/quests/title/Title_v1_8_R3.java new file mode 100644 index 00000000..933bd098 --- /dev/null +++ b/src/me/fatpigsarefat/quests/title/Title_v1_8_R3.java @@ -0,0 +1,22 @@ +package me.fatpigsarefat.quests.title; + +import net.minecraft.server.v1_8_R3.IChatBaseComponent.ChatSerializer; +import net.minecraft.server.v1_8_R3.PacketPlayOutTitle; +import net.minecraft.server.v1_8_R3.PacketPlayOutTitle.EnumTitleAction; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class Title_v1_8_R3 implements Title { + + @Override + public void sendTitle(Player player, String message, String submessage) { + message = "{\"text\":\"" + message + "\"}"; + PacketPlayOutTitle title = new PacketPlayOutTitle(EnumTitleAction.TITLE, ChatSerializer.a(message), 10, 100, + 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(title); + submessage = "{\"text\":\"" + submessage + "\"}"; + PacketPlayOutTitle subtitle = new PacketPlayOutTitle(EnumTitleAction.SUBTITLE, ChatSerializer.a(submessage), 10, + 100, 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(subtitle); + } +} diff --git a/src/me/fatpigsarefat/quests/title/Title_v1_9_R1.java b/src/me/fatpigsarefat/quests/title/Title_v1_9_R1.java new file mode 100644 index 00000000..b42b4920 --- /dev/null +++ b/src/me/fatpigsarefat/quests/title/Title_v1_9_R1.java @@ -0,0 +1,22 @@ +package me.fatpigsarefat.quests.title; + +import net.minecraft.server.v1_9_R1.IChatBaseComponent.ChatSerializer; +import net.minecraft.server.v1_9_R1.PacketPlayOutTitle; +import net.minecraft.server.v1_9_R1.PacketPlayOutTitle.EnumTitleAction; +import org.bukkit.craftbukkit.v1_9_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class Title_v1_9_R1 implements Title { + + @Override + public void sendTitle(Player player, String message, String submessage) { + message = "{\"text\":\"" + message + "\"}"; + PacketPlayOutTitle title = new PacketPlayOutTitle(EnumTitleAction.TITLE, ChatSerializer.a(message), 10, 100, + 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(title); + submessage = "{\"text\":\"" + submessage + "\"}"; + PacketPlayOutTitle subtitle = new PacketPlayOutTitle(EnumTitleAction.SUBTITLE, ChatSerializer.a(submessage), 10, + 100, 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(subtitle); + } +} diff --git a/src/me/fatpigsarefat/quests/title/Title_v1_9_R2.java b/src/me/fatpigsarefat/quests/title/Title_v1_9_R2.java new file mode 100644 index 00000000..5f69ccfd --- /dev/null +++ b/src/me/fatpigsarefat/quests/title/Title_v1_9_R2.java @@ -0,0 +1,22 @@ +package me.fatpigsarefat.quests.title; + +import net.minecraft.server.v1_9_R2.IChatBaseComponent.ChatSerializer; +import net.minecraft.server.v1_9_R2.PacketPlayOutTitle; +import net.minecraft.server.v1_9_R2.PacketPlayOutTitle.EnumTitleAction; +import org.bukkit.craftbukkit.v1_9_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class Title_v1_9_R2 implements Title { + + @Override + public void sendTitle(Player player, String message, String submessage) { + message = "{\"text\":\"" + message + "\"}"; + PacketPlayOutTitle title = new PacketPlayOutTitle(EnumTitleAction.TITLE, ChatSerializer.a(message), 10, 100, + 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(title); + submessage = "{\"text\":\"" + submessage + "\"}"; + PacketPlayOutTitle subtitle = new PacketPlayOutTitle(EnumTitleAction.SUBTITLE, ChatSerializer.a(submessage), 10, + 100, 10); + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(subtitle); + } +} diff --git a/src/me/fatpigsarefat/quests/updater/Updater.java b/src/me/fatpigsarefat/quests/updater/Updater.java new file mode 100644 index 00000000..0dca333d --- /dev/null +++ b/src/me/fatpigsarefat/quests/updater/Updater.java @@ -0,0 +1,59 @@ +package me.fatpigsarefat.quests.updater; + +import me.fatpigsarefat.quests.obj.Messages; +import org.bukkit.plugin.Plugin; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.logging.Level; + +public class Updater { + + private static final int PROJECT_ID = 23696; + private String installedVersion; + private String returnedVersion; + private URL api; + private Plugin plugin; + private boolean updateReady; + + public Updater(Plugin plugin) { + this.plugin = plugin; + this.installedVersion = plugin.getDescription().getVersion(); + try { + this.api = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + PROJECT_ID); + } catch (MalformedURLException ignored) { + // shit + fan + } + } + + public String getLink() { + return "https://www.spigotmc.org/resources/" + PROJECT_ID; + } + + public boolean check() { + try { + URLConnection con = api.openConnection(); + returnedVersion = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine(); + if (!returnedVersion.equals(installedVersion)) { + plugin.getLogger().log(Level.INFO, "A new version " + returnedVersion + " was found on Spigot (your version: " + installedVersion + "). Please update me! <3 - Link: " + getLink()); + updateReady = true; + } + } catch (IOException e) { + plugin.getLogger().log(Level.WARNING, "Failed to check for updates. You can check manually at " + getLink()); + // probably offline + } + return false; + } + + public boolean isUpdateReady() { + return updateReady; + } + + public String getMessage() { + return Messages.QUEST_UPDATER.getMessage().replace("{newver}", returnedVersion).replace("{oldver}", installedVersion).replace("{link}", getLink()); + } +}
\ No newline at end of file diff --git a/src/plugin.yml b/src/plugin.yml new file mode 100644 index 00000000..16409321 --- /dev/null +++ b/src/plugin.yml @@ -0,0 +1,17 @@ +name: Quests +version: 2.0.0 +main: me.fatpigsarefat.quests.Quests +author: fatpigsarefat +softdepend: [ASkyBlock, uSkyBlock] +prefix: Quests + +commands: + quests: + description: Description + usage: /quests + permission: quests.command + aliases: [q, quest] + +permissions: + quests.command: + description: Quests permission
\ No newline at end of file |
