aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/me/fatpigsarefat
diff options
context:
space:
mode:
authorfatpigsarefat <fatpigsarefat@outlook.com>2018-07-21 21:25:00 +0100
committerfatpigsarefat <fatpigsarefat@outlook.com>2018-07-21 21:25:01 +0100
commitbcd4d141c04768c2ed3d00d4963e4f40424b5bc4 (patch)
treeb79a965aaa19bee8f859f1de5272feae2fbb0153 /src/main/java/me/fatpigsarefat
parent56aae6d737aa523f23160256b5022b8cce8fe9c5 (diff)
Now using Maven
- pom.xml was added - Source files moved - .gitignore adjusted to allow .xml - All Title classes changed to use Bukkit method instead
Diffstat (limited to 'src/main/java/me/fatpigsarefat')
-rw-r--r--src/main/java/me/fatpigsarefat/quests/Quests.java452
-rw-r--r--src/main/java/me/fatpigsarefat/quests/blocktype/Block.java34
-rw-r--r--src/main/java/me/fatpigsarefat/quests/blocktype/SimilarBlocks.java93
-rw-r--r--src/main/java/me/fatpigsarefat/quests/bstats/Metrics.java661
-rw-r--r--src/main/java/me/fatpigsarefat/quests/commands/CommandQuests.java342
-rw-r--r--src/main/java/me/fatpigsarefat/quests/events/EventInventory.java87
-rw-r--r--src/main/java/me/fatpigsarefat/quests/events/EventPlayerJoin.java25
-rw-r--r--src/main/java/me/fatpigsarefat/quests/events/EventPlayerLeave.java25
-rw-r--r--src/main/java/me/fatpigsarefat/quests/obj/Items.java26
-rw-r--r--src/main/java/me/fatpigsarefat/quests/obj/Messages.java58
-rw-r--r--src/main/java/me/fatpigsarefat/quests/obj/Options.java53
-rw-r--r--src/main/java/me/fatpigsarefat/quests/obj/misc/QItemStack.java114
-rw-r--r--src/main/java/me/fatpigsarefat/quests/obj/misc/QMenu.java12
-rw-r--r--src/main/java/me/fatpigsarefat/quests/obj/misc/QMenuCategory.java92
-rw-r--r--src/main/java/me/fatpigsarefat/quests/obj/misc/QMenuDaily.java121
-rw-r--r--src/main/java/me/fatpigsarefat/quests/obj/misc/QMenuQuest.java224
-rw-r--r--src/main/java/me/fatpigsarefat/quests/obj/misc/creator/QMenuCreator.java70
-rw-r--r--src/main/java/me/fatpigsarefat/quests/player/QPlayer.java123
-rw-r--r--src/main/java/me/fatpigsarefat/quests/player/QPlayerManager.java78
-rw-r--r--src/main/java/me/fatpigsarefat/quests/player/questprogressfile/QuestProgress.java106
-rw-r--r--src/main/java/me/fatpigsarefat/quests/player/questprogressfile/QuestProgressFile.java254
-rw-r--r--src/main/java/me/fatpigsarefat/quests/player/questprogressfile/TaskProgress.java41
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/Category.java42
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/Quest.java96
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/QuestManager.java38
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/Task.java38
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/ConfigValue.java29
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/TaskType.java56
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/TaskTypeManager.java40
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/ASkyBlockLevelType.java64
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/BuildingCertainTaskType.java103
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/BuildingTaskType.java68
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/FarmingTaskType.java94
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/FishingTaskType.java74
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/InventoryTaskType.java116
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MilkingTaskType.java77
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MiningCertainTaskType.java102
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MiningTaskType.java72
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MobkillingCertainTaskType.java108
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MobkillingTaskType.java101
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/PlayerkillingTaskType.java84
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/PlaytimeTaskType.java54
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/PositionTaskType.java87
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/ShearingTaskType.java76
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/TamingTaskType.java75
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/WalkingTaskType.java75
-rw-r--r--src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/uSkyBlockLevelType.java65
-rw-r--r--src/main/java/me/fatpigsarefat/quests/title/Title.java8
-rw-r--r--src/main/java/me/fatpigsarefat/quests/title/Title_Bukkit.java11
-rw-r--r--src/main/java/me/fatpigsarefat/quests/title/Title_BukkitNoTimings.java13
-rw-r--r--src/main/java/me/fatpigsarefat/quests/title/Title_Other.java19
-rw-r--r--src/main/java/me/fatpigsarefat/quests/title/Title_v1_10_R1.java22
-rw-r--r--src/main/java/me/fatpigsarefat/quests/title/Title_v1_11_R1.java22
-rw-r--r--src/main/java/me/fatpigsarefat/quests/title/Title_v1_12_R1.java22
-rw-r--r--src/main/java/me/fatpigsarefat/quests/title/Title_v1_8_R1.java23
-rw-r--r--src/main/java/me/fatpigsarefat/quests/title/Title_v1_8_R2.java22
-rw-r--r--src/main/java/me/fatpigsarefat/quests/title/Title_v1_8_R3.java22
-rw-r--r--src/main/java/me/fatpigsarefat/quests/title/Title_v1_9_R1.java22
-rw-r--r--src/main/java/me/fatpigsarefat/quests/title/Title_v1_9_R2.java22
-rw-r--r--src/main/java/me/fatpigsarefat/quests/updater/Updater.java65
60 files changed, 5218 insertions, 0 deletions
diff --git a/src/main/java/me/fatpigsarefat/quests/Quests.java b/src/main/java/me/fatpigsarefat/quests/Quests.java
new file mode 100644
index 00000000..7904738b
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/Quests.java
@@ -0,0 +1,452 @@
+package me.fatpigsarefat.quests;
+
+import com.google.common.io.ByteStreams;
+import me.fatpigsarefat.quests.blocktype.SimilarBlocks;
+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.TaskTypeManager;
+import me.fatpigsarefat.quests.quests.tasktypes.types.*;
+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 InventoryTaskType());
+ taskTypeManager.registerTaskType(new WalkingTaskType());
+ taskTypeManager.registerTaskType(new TamingTaskType());
+ taskTypeManager.registerTaskType(new MilkingTaskType());
+ taskTypeManager.registerTaskType(new ShearingTaskType());
+ taskTypeManager.registerTaskType(new PositionTaskType());
+ taskTypeManager.registerTaskType(new PlaytimeTaskType());
+ 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.");
+
+ SimilarBlocks.addBlocks();
+
+ 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()) {
+ if (qPlayer.isOnlyDataLoaded()) {
+ continue;
+ }
+ qPlayer.getQuestProgressFile().saveToDisk();
+ }
+ }
+ }.runTaskTimerAsynchronously(this, 12000L, 12000L);
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ for (QPlayer qPlayer : qPlayerManager.getQPlayers()) {
+ if (qPlayer.isOnlyDataLoaded()) {
+ continue;
+ }
+ 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()) {
+ if (qPlayer.isOnlyDataLoaded()) {
+ continue;
+ }
+ 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 + ".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) {
+ requirements = new ArrayList<>();
+ }
+ if (rewards == null) {
+ rewards = 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_BukkitNoTimings();
+ success = true;
+ } else if (version.equals("v1_8_R2")) {
+ title = new Title_BukkitNoTimings();
+ success = true;
+ } else if (version.equals("v1_8_R1")) {
+ title = new Title_BukkitNoTimings();
+ success = true;
+ } else if (version.equals("v1_9_R2")) {
+ title = new Title_BukkitNoTimings();
+ success = true;
+ } else if (version.equals("v1_9_R1")) {
+ title = new Title_BukkitNoTimings();
+ success = true;
+ } else if (version.equals("v1_10_R1")) {
+ title = new Title_BukkitNoTimings();
+ success = true;
+ } else if (version.equals("v1_11_R1")) {
+ title = new Title_Bukkit();
+ success = true;
+ } else if (version.equals("v1_12_R1")) {
+ title = new Title_Bukkit();
+ success = true;
+ } else if (version.equals("v1_13_R1")) {
+ title = new Title_Bukkit();
+ success = true;
+ } else {
+ title = new Title_Other();
+ }
+ if (title instanceof Title_Bukkit) {
+ getLogger().info("Titles have been enabled.");
+ } else if (title instanceof Title_BukkitNoTimings) {
+ getLogger().info("Titles have been enabled, although they have limited timings.");
+ } else {
+ getLogger().info("Titles are not supported for this version.");
+ }
+ 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/main/java/me/fatpigsarefat/quests/blocktype/Block.java b/src/main/java/me/fatpigsarefat/quests/blocktype/Block.java
new file mode 100644
index 00000000..f9b61039
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/blocktype/Block.java
@@ -0,0 +1,34 @@
+package me.fatpigsarefat.quests.blocktype;
+
+import org.bukkit.Material;
+
+public class Block {
+
+ private Material material;
+ private short data;
+
+ public Block(Material material, short data) {
+ this.material = material;
+ this.data = data;
+ }
+
+ public Block(Material material) {
+ this.material = material;
+ }
+
+ public Material getMaterial() {
+ return material;
+ }
+
+ public short getData() {
+ return data;
+ }
+
+ public void setMaterial(Material material) {
+ this.material = material;
+ }
+
+ public void setData(short data) {
+ this.data = data;
+ }
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/blocktype/SimilarBlocks.java b/src/main/java/me/fatpigsarefat/quests/blocktype/SimilarBlocks.java
new file mode 100644
index 00000000..11b9f16d
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/blocktype/SimilarBlocks.java
@@ -0,0 +1,93 @@
+package me.fatpigsarefat.quests.blocktype;
+
+import org.bukkit.Material;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SimilarBlocks {
+
+ private static HashMap<Block, Block> similarBlocks = new HashMap<>();
+
+ public static void addBlocks() {
+ // Redstone Ore
+ similarBlocks.put(new Block(Material.REDSTONE_ORE), new Block(Material.GLOWING_REDSTONE_ORE));
+ similarBlocks.put(new Block(Material.GLOWING_REDSTONE_ORE), new Block(Material.REDSTONE_ORE));
+
+ // Oak Door
+ similarBlocks.put(new Block(Material.WOODEN_DOOR, (short) 0), new Block(Material.WOODEN_DOOR));
+ similarBlocks.put(new Block(Material.WOODEN_DOOR, (short) 1), new Block(Material.WOODEN_DOOR));
+ similarBlocks.put(new Block(Material.WOODEN_DOOR, (short) 2), new Block(Material.WOODEN_DOOR));
+ similarBlocks.put(new Block(Material.WOODEN_DOOR, (short) 3), new Block(Material.WOODEN_DOOR));
+
+ // Dark Oak Door
+ similarBlocks.put(new Block(Material.DARK_OAK_DOOR, (short) 0), new Block(Material.DARK_OAK_DOOR));
+ similarBlocks.put(new Block(Material.DARK_OAK_DOOR, (short) 1), new Block(Material.DARK_OAK_DOOR));
+ similarBlocks.put(new Block(Material.DARK_OAK_DOOR, (short) 2), new Block(Material.DARK_OAK_DOOR));
+ similarBlocks.put(new Block(Material.DARK_OAK_DOOR, (short) 3), new Block(Material.DARK_OAK_DOOR));
+
+ // Acacia Door
+ similarBlocks.put(new Block(Material.ACACIA_DOOR, (short) 0), new Block(Material.ACACIA_DOOR));
+ similarBlocks.put(new Block(Material.ACACIA_DOOR, (short) 1), new Block(Material.ACACIA_DOOR));
+ similarBlocks.put(new Block(Material.ACACIA_DOOR, (short) 2), new Block(Material.ACACIA_DOOR));
+ similarBlocks.put(new Block(Material.ACACIA_DOOR, (short) 3), new Block(Material.ACACIA_DOOR));
+
+ // Birch Door
+ similarBlocks.put(new Block(Material.BIRCH_DOOR, (short) 0), new Block(Material.BIRCH_DOOR));
+ similarBlocks.put(new Block(Material.BIRCH_DOOR, (short) 1), new Block(Material.BIRCH_DOOR));
+ similarBlocks.put(new Block(Material.BIRCH_DOOR, (short) 2), new Block(Material.BIRCH_DOOR));
+ similarBlocks.put(new Block(Material.BIRCH_DOOR, (short) 3), new Block(Material.BIRCH_DOOR));
+
+ // Jungle Door
+ similarBlocks.put(new Block(Material.JUNGLE_DOOR, (short) 0), new Block(Material.JUNGLE_DOOR));
+ similarBlocks.put(new Block(Material.JUNGLE_DOOR, (short) 1), new Block(Material.JUNGLE_DOOR));
+ similarBlocks.put(new Block(Material.JUNGLE_DOOR, (short) 2), new Block(Material.JUNGLE_DOOR));
+ similarBlocks.put(new Block(Material.JUNGLE_DOOR, (short) 3), new Block(Material.JUNGLE_DOOR));
+
+ // Spruce Door
+ similarBlocks.put(new Block(Material.SPRUCE_DOOR, (short) 0), new Block(Material.SPRUCE_DOOR));
+ similarBlocks.put(new Block(Material.SPRUCE_DOOR, (short) 1), new Block(Material.SPRUCE_DOOR));
+ similarBlocks.put(new Block(Material.SPRUCE_DOOR, (short) 2), new Block(Material.SPRUCE_DOOR));
+ similarBlocks.put(new Block(Material.SPRUCE_DOOR, (short) 3), new Block(Material.SPRUCE_DOOR));
+
+ // Iron Door
+ similarBlocks.put(new Block(Material.IRON_DOOR, (short) 0), new Block(Material.IRON_DOOR));
+ similarBlocks.put(new Block(Material.IRON_DOOR, (short) 1), new Block(Material.IRON_DOOR));
+ similarBlocks.put(new Block(Material.IRON_DOOR, (short) 2), new Block(Material.IRON_DOOR));
+ similarBlocks.put(new Block(Material.IRON_DOOR, (short) 3), new Block(Material.IRON_DOOR));
+
+ // Oak Log
+ similarBlocks.put(new Block(Material.LOG, (short) 4), new Block(Material.LOG, (short) 0));
+ similarBlocks.put(new Block(Material.LOG, (short) 8), new Block(Material.LOG, (short) 0));
+
+ // Spruce Log
+ similarBlocks.put(new Block(Material.LOG, (short) 5), new Block(Material.LOG, (short) 1));
+ similarBlocks.put(new Block(Material.LOG, (short) 9), new Block(Material.LOG, (short) 1));
+
+ // Birch Log
+ similarBlocks.put(new Block(Material.LOG, (short) 6), new Block(Material.LOG, (short) 2));
+ similarBlocks.put(new Block(Material.LOG, (short) 10), new Block(Material.LOG, (short) 2));
+
+ // Jungle Log
+ similarBlocks.put(new Block(Material.LOG, (short) 7), new Block(Material.LOG, (short) 3));
+ similarBlocks.put(new Block(Material.LOG, (short) 11), new Block(Material.LOG, (short) 3));
+
+ // Acacia Log
+ similarBlocks.put(new Block(Material.LOG_2, (short) 4), new Block(Material.LOG, (short) 0));
+ similarBlocks.put(new Block(Material.LOG_2, (short) 8), new Block(Material.LOG, (short) 0));
+
+ // Dark Oak Log
+ similarBlocks.put(new Block(Material.LOG_2, (short) 5), new Block(Material.LOG, (short) 1));
+ similarBlocks.put(new Block(Material.LOG_2, (short) 9), new Block(Material.LOG, (short) 1));
+ }
+
+ public static Block getSimilarBlock(Block block) {
+ for (Map.Entry<Block, Block> entry : similarBlocks.entrySet()) {
+ if (entry.getKey().getMaterial() == block.getMaterial() && entry.getKey().getData() == block.getData()) {
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/bstats/Metrics.java b/src/main/java/me/fatpigsarefat/quests/bstats/Metrics.java
new file mode 100644
index 00000000..5a8a21b3
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/commands/CommandQuests.java b/src/main/java/me/fatpigsarefat/quests/commands/CommandQuests.java
new file mode 100644
index 00000000..8c9baec7
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/commands/CommandQuests.java
@@ -0,0 +1,342 @@
+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.player.questprogressfile.QuestProgressFile;
+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.OfflinePlayer;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.util.UUID;
+
+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[1].equalsIgnoreCase("update")) {
+ sender.sendMessage(ChatColor.GRAY + "Checking for updates...");
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ Quests.getUpdater().check();
+ if (Quests.getUpdater().isUpdateReady()) {
+ sender.sendMessage(Quests.getUpdater().getMessage());
+ } else {
+ sender.sendMessage(ChatColor.GRAY + "No updates were found.");
+ }
+ }
+ }.runTaskAsynchronously(Quests.getInstance());
+ 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")) {
+ Player player;
+ OfflinePlayer ofp;
+ UUID uuid;
+ String name;
+ if ((player = Bukkit.getPlayer(args[3])) != null) {
+ uuid = player.getUniqueId();
+ name = player.getName();
+ } else if ((ofp = Bukkit.getOfflinePlayer(args[3])) != null) {
+ uuid = ofp.getUniqueId();
+ name = ofp.getName();
+ } else {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_PLAYERNOTFOUND.getMessage().replace("{player}", args[3]));
+ return true;
+ }
+ if (args[2].equalsIgnoreCase("fullreset")) {
+ if (Quests.getPlayerManager().getPlayer(uuid) == null) {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_LOADDATA.getMessage().replace("{player}", name));
+ Quests.getPlayerManager().loadPlayer(uuid, true);
+ }
+ if (Quests.getPlayerManager().getPlayer(uuid) == null) {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_NODATA.getMessage().replace("{player}", name));
+ return true;
+ }
+ QuestProgressFile questProgressFile = Quests.getPlayerManager().getPlayer(uuid).getQuestProgressFile();
+ questProgressFile.clear();
+ questProgressFile.saveToDisk();
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_FULLRESET.getMessage().replace("{player}", name));
+ return true;
+ }
+ if (Quests.getPlayerManager().getPlayer(uuid).isOnlyDataLoaded()) {
+ Quests.getPlayerManager().removePlayer(uuid);
+ }
+ showAdminHelp(sender, "moddata");
+ return true;
+ }
+ } else if (args.length == 5) {
+ if (args[1].equalsIgnoreCase("opengui")) {
+ if (args[2].equalsIgnoreCase("c") || args[2].equalsIgnoreCase("category")) {
+ if (!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;
+ }
+ } else if (args[1].equalsIgnoreCase("moddata")) {
+ boolean success = false;
+ Player player;
+ OfflinePlayer ofp;
+ UUID uuid;
+ String name;
+ if ((player = Bukkit.getPlayer(args[3])) != null) {
+ uuid = player.getUniqueId();
+ name = player.getName();
+ } else if ((ofp = Bukkit.getOfflinePlayer(args[3])) != null) {
+ uuid = ofp.getUniqueId();
+ name = ofp.getName();
+ } else {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_PLAYERNOTFOUND.getMessage().replace("{player}", args[3]));
+ return true;
+ }
+ if (Quests.getPlayerManager().getPlayer(uuid) == null) {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_LOADDATA.getMessage().replace("{player}", name));
+ Quests.getPlayerManager().loadPlayer(uuid, true);
+ }
+ if (Quests.getPlayerManager().getPlayer(uuid) == null) {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_NODATA.getMessage().replace("{player}", name));
+ success = true;
+ }
+ QuestProgressFile questProgressFile = Quests.getPlayerManager().getPlayer(uuid).getQuestProgressFile();
+ Quest quest = Quests.getQuestManager().getQuestById(args[4]);
+ if (quest == null) {
+ sender.sendMessage(Messages.COMMAND_QUEST_START_DOESNTEXIST.getMessage().replace("{quest}", args[4]));
+ success = true;
+ }
+ if (args[2].equalsIgnoreCase("reset")) {
+ questProgressFile.generateBlankQuestProgress(quest.getId());
+ questProgressFile.saveToDisk();
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_RESET_SUCCESS.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ success = true;
+ } else if (args[2].equalsIgnoreCase("start")) {
+ int response = questProgressFile.startQuest(quest);
+ if (response == 1) {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILLIMIT.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ return true;
+ } else if (response == 2) {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILCOMPLETE.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ return true;
+ } else if (response == 3) {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILCOOLDOWN.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ return true;
+ } else if (response == 4) {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILLOCKED.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ return true;
+ }
+ questProgressFile.saveToDisk();
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_SUCCESS.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ success = true;
+ } else if (args[2].equalsIgnoreCase("complete")) {
+ questProgressFile.completeQuest(quest);
+ questProgressFile.saveToDisk();
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_COMPLETE_SUCCESS.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ success = true;
+ }
+ if (Quests.getPlayerManager().getPlayer(uuid).isOnlyDataLoaded()) {
+ Quests.getPlayerManager().removePlayer(uuid);
+ }
+ if (!success) {
+ showAdminHelp(sender, "moddata");
+ }
+ 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.DARK_GRAY + " * " + ChatColor.RED + "/quests a update " + ChatColor.DARK_GRAY + ": check for updates");
+ }
+ sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "-----=[" + ChatColor.RED + " requires permission: quests.admin " +
+ ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "]=-----");
+ }
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/events/EventInventory.java b/src/main/java/me/fatpigsarefat/quests/events/EventInventory.java
new file mode 100644
index 00000000..9911c216
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/events/EventInventory.java
@@ -0,0 +1,87 @@
+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.ClickType;
+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;
+
+ if (qMenuQuest.getPagePrevLocation() == event.getSlot()) {
+ buffer.add(event.getWhoClicked().getUniqueId());
+ event.getWhoClicked().openInventory(qMenuQuest.toInventory(qMenuQuest.getCurrentPage() - 1));
+
+ } else if (qMenuQuest.getPageNextLocation() == event.getSlot()) {
+ buffer.add(event.getWhoClicked().getUniqueId());
+ event.getWhoClicked().openInventory(qMenuQuest.toInventory(qMenuQuest.getCurrentPage() + 1));
+
+ } else 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 (event.getSlot() < qMenuQuest.getPageSize() && qMenuQuest.getSlotsToMenu().containsKey(event.getSlot() + (((qMenuQuest
+ .getCurrentPage()) - 1) * qMenuQuest.getPageSize()))) {
+ String questid = qMenuQuest.getSlotsToMenu().get(event.getSlot());
+ Quest quest = Quests.getQuestManager().getQuestById(questid);
+ if (event.getClick() == ClickType.LEFT) {
+ if (qMenuQuest.getOwner().getQuestProgressFile().startQuest(quest) == 0) {
+ event.getWhoClicked().closeInventory();
+ }
+ } else if (event.getClick() == ClickType.RIGHT) {
+ if (qMenuQuest.getOwner().getQuestProgressFile().cancelQuest(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/main/java/me/fatpigsarefat/quests/events/EventPlayerJoin.java b/src/main/java/me/fatpigsarefat/quests/events/EventPlayerJoin.java
new file mode 100644
index 00000000..14062af0
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/events/EventPlayerJoin.java
@@ -0,0 +1,25 @@
+package me.fatpigsarefat.quests.events;
+
+import me.fatpigsarefat.quests.Quests;
+import me.fatpigsarefat.quests.obj.Messages;
+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.getInstance().getDescription().getVersion().contains("beta") && event.getPlayer().hasPermission("quests.admin")) {
+ event.getPlayer().sendMessage(Messages.BETA_REMINDER.getMessage());
+ }
+ if (Quests.getUpdater().isUpdateReady() && event.getPlayer().hasPermission("quests.admin")) {
+ event.getPlayer().sendMessage(Quests.getUpdater().getMessage());
+ }
+ }
+
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/events/EventPlayerLeave.java b/src/main/java/me/fatpigsarefat/quests/events/EventPlayerLeave.java
new file mode 100644
index 00000000..15d09a8e
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/obj/Items.java b/src/main/java/me/fatpigsarefat/quests/obj/Items.java
new file mode 100644
index 00000000..1ffeabc8
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/obj/Items.java
@@ -0,0 +1,26 @@
+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"),
+ PAGE_PREV("gui.page-prev"),
+ PAGE_NEXT("gui.page-next"),
+ PAGE_DESCRIPTION("gui.page-desc");
+
+ String path;
+
+ Items(String path) {
+ this.path = path;
+ }
+
+ public ItemStack getItem() {
+ return Quests.getInstance().getItemStack(path);
+ }
+
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/obj/Messages.java b/src/main/java/me/fatpigsarefat/quests/obj/Messages.java
new file mode 100644
index 00000000..ddcb23cb
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/obj/Messages.java
@@ -0,0 +1,58 @@
+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_CANCEL("messages.quest-cancel"),
+ 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_CANCEL_NOTSTARTED("messages.quest-cancel-notstarted"),
+ 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"),
+ BETA_REMINDER("messages.beta-reminder"),
+ COMMAND_QUEST_ADMIN_LOADDATA("messages.command-quest-admin-loaddata"),
+ COMMAND_QUEST_ADMIN_NODATA("messages.command-quest-admin-nodata"),
+ COMMAND_QUEST_ADMIN_FULLRESET("messages.command-quest-admin-fullreset"),
+ COMMAND_QUEST_ADMIN_START_FAILLOCKED("messages.command-quest-admin-start-faillocked"),
+ COMMAND_QUEST_ADMIN_START_FAILCOOLDOWN("messages.command-quest-admin-start-failcooldown"),
+ COMMAND_QUEST_ADMIN_START_FAILCOMPLETE("messages.command-quest-admin-start-failcomplete"),
+ COMMAND_QUEST_ADMIN_START_FAILLIMIT("messages.command-quest-admin-start-faillimit"),
+ COMMAND_QUEST_ADMIN_START_SUCCESS("messages.command-quest-admin-start-success"),
+ COMMAND_QUEST_ADMIN_COMPLETE_SUCCESS("messages.command-quest-admin-complete-success"),
+ COMMAND_QUEST_ADMIN_RESET_SUCCESS("messages.command-quest-admin-reset-success");
+
+ 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 ChatColor.translateAlternateColorCodes('&', message);
+ }
+ }
+ return path;
+ }
+
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/obj/Options.java b/src/main/java/me/fatpigsarefat/quests/obj/Options.java
new file mode 100644
index 00000000..920f1132
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/obj/Options.java
@@ -0,0 +1,53 @@
+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"),
+ GUI_HIDE_LOCKED("options.gui-hide-locked"),
+ GUITITLE_QUESTS_CATEGORY("options.guinames.quests-category"),
+ GUITITLE_QUESTS("options.guinames.quests-menu"),
+ GUITITLE_DAILY_QUESTS("options.guinames.daily-quests"),
+ ALLOW_QUEST_CANCEL("options.allow-quest-cancel");
+
+ 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/main/java/me/fatpigsarefat/quests/obj/misc/QItemStack.java b/src/main/java/me/fatpigsarefat/quests/obj/misc/QItemStack.java
new file mode 100644
index 00000000..81cefc3b
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/obj/misc/QItemStack.java
@@ -0,0 +1,114 @@
+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;
+ this.data = data;
+ }
+
+ 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 {
+ ism.addItemFlags(ItemFlag.HIDE_ENCHANTS);
+ ism.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
+ } 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));
+ }
+ if (parts[1].equals("complete")) {
+ String str = String.valueOf(questProgress.getTaskProgress(parts[0]).isCompleted());
+ s = s.replace("{" + m.group(1) + "}", str);
+ }
+ }
+ }
+ formattedLore.add(s);
+ }
+ }
+ ism.setLore(formattedLore);
+ is.setItemMeta(ism);
+ return is;
+ }
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/obj/misc/QMenu.java b/src/main/java/me/fatpigsarefat/quests/obj/misc/QMenu.java
new file mode 100644
index 00000000..13629600
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/obj/misc/QMenuCategory.java b/src/main/java/me/fatpigsarefat/quests/obj/misc/QMenuCategory.java
new file mode 100644
index 00000000..61d1ac57
--- /dev/null
+++ b/src/main/java/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 = Options.GUITITLE_QUESTS_CATEGORY.getStringValue();
+
+ ItemStack pageIs = new ItemStack(Material.DIRT);
+
+ Inventory inventory = Bukkit.createInventory(null, 54, 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/main/java/me/fatpigsarefat/quests/obj/misc/QMenuDaily.java b/src/main/java/me/fatpigsarefat/quests/obj/misc/QMenuDaily.java
new file mode 100644
index 00000000..9b50f7ee
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/obj/misc/QMenuDaily.java
@@ -0,0 +1,121 @@
+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.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 QMenuDaily 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 QMenuDaily(QPlayer owner, QMenuCategory superMenu) {
+ this.owner = owner;
+ this.superMenu = superMenu;
+ }
+
+ public void populate(List<Quest> quests) {
+ int slot = 11;
+ for (Quest quest : quests) {
+ slotsToQuestIds.put(slot, quest.getId());
+ slot++;
+ if (slot == 16) {
+ break;
+ }
+ }
+ }
+
+ @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 = Options.GUITITLE_DAILY_QUESTS.toString();
+
+ Inventory inventory = Bukkit.createInventory(null, 27, title);
+
+ //TODO daily quests
+
+// int invSlot = 11;
+// for (int pointer = pageMin; pointer < pageMax; pointer++) {
+// if (slotsToQuestIds.containsKey(pointer)) {
+// Quest quest = Quests.getQuestManager().getQuestById(slotsToQuestIds.get(pointer));
+// QuestProgress questProgress = owner.getQuestProgressFile().getQuestProgress(quest);
+// long cooldown = owner.getQuestProgressFile().getCooldownFor(quest);
+// if (!owner.getQuestProgressFile().hasMetRequirements(quest)) {
+// List<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++;
+// }
+
+ return inventory;
+ }
+
+ 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/main/java/me/fatpigsarefat/quests/obj/misc/QMenuQuest.java b/src/main/java/me/fatpigsarefat/quests/obj/misc/QMenuQuest.java
new file mode 100644
index 00000000..50e264e7
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/obj/misc/QMenuQuest.java
@@ -0,0 +1,224 @@
+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.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 int pagePrevLocation = -1;
+ private int pageNextLocation = -1;
+ private int currentPage = -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) {
+ if (Options.GUI_HIDE_LOCKED.getBooleanValue()) {
+ QuestProgress questProgress = owner.getQuestProgressFile().getQuestProgress(quest);
+ long cooldown = owner.getQuestProgressFile().getCooldownFor(quest);
+ if (!owner.getQuestProgressFile().hasMetRequirements(quest) || (!quest.isRepeatable() && questProgress.isCompletedBefore()) || cooldown > 0) {
+ continue;
+ }
+ }
+ 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 int getPagePrevLocation() {
+ return pagePrevLocation;
+ }
+
+ public int getPageNextLocation() {
+ return pageNextLocation;
+ }
+
+ public int getCurrentPage() {
+ return currentPage;
+ }
+
+ public int getPageSize() {
+ return pageSize;
+ }
+
+ public Inventory toInventory(int page) {
+ currentPage = page;
+ int pageMin = pageSize * (page - 1);
+ int pageMax = pageSize * page;
+ String title = Options.GUITITLE_QUESTS.getStringValue();
+
+ ItemStack pageIs;
+ ItemStack pagePrevIs;
+ ItemStack pageNextIs;
+ ItemStack back = Items.BACK_BUTTON.getItem();
+
+ Inventory inventory = Bukkit.createInventory(null, 54, 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++;
+ }
+
+ pageNextLocation = -1;
+ pagePrevLocation = -1;
+
+ Map<String, String> pageplaceholders = new HashMap<>();
+ pageplaceholders.put("{prevpage}", String.valueOf(page - 1));
+ pageplaceholders.put("{nextpage}", String.valueOf(page + 1));
+ pageplaceholders.put("{page}", String.valueOf(page));
+ pageIs = replaceItemStack(Items.PAGE_DESCRIPTION.getItem(), pageplaceholders);
+ pagePrevIs = replaceItemStack(Items.PAGE_PREV.getItem(), pageplaceholders);
+ pageNextIs = replaceItemStack(Items.PAGE_NEXT.getItem(), pageplaceholders);
+
+ if (Options.CATEGORIES_ENABLED.getBooleanValue() && backButtonEnabled) {
+ inventory.setItem(45, back);
+ backButtonLocation = 45;
+ }
+ if (slotsToQuestIds.size() > pageSize) {
+ inventory.setItem(49, pageIs);
+ if (page != 1) {
+ inventory.setItem(48, pagePrevIs);
+ pagePrevLocation = 48;
+ }
+ if (Math.ceil((double) slotsToQuestIds.size() / ((double) 45)) != page) {
+ inventory.setItem(50, pageNextIs);
+ pageNextLocation = 50;
+ }
+ } else if (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;
+ }
+
+ return inventory;
+ }
+
+ 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<>();
+ ItemMeta ism = newItemStack.getItemMeta();
+ if (lore != null) {
+ for (String s : lore) {
+ for (Map.Entry<String, String> entry : placeholders.entrySet()) {
+ s = s.replace(entry.getKey(), entry.getValue());
+ ism.setDisplayName(ism.getDisplayName().replace(entry.getKey(), entry.getValue()));
+ }
+ newLore.add(s);
+ }
+ }
+ ism.setLore(newLore);
+ newItemStack.setItemMeta(ism);
+ return newItemStack;
+ }
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/obj/misc/creator/QMenuCreator.java b/src/main/java/me/fatpigsarefat/quests/obj/misc/creator/QMenuCreator.java
new file mode 100644
index 00000000..0436e203
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/obj/misc/creator/QMenuCreator.java
@@ -0,0 +1,70 @@
+package me.fatpigsarefat.quests.obj.misc.creator;
+
+import me.fatpigsarefat.quests.obj.misc.QMenu;
+import me.fatpigsarefat.quests.player.QPlayer;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+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;
+
+public class QMenuCreator implements QMenu {
+
+ private QPlayer owner;
+
+ public QMenuCreator(QPlayer owner) {
+ this.owner = owner;
+ }
+
+ @Override
+ public HashMap<Integer, String> getSlotsToMenu() {
+ return null;
+ }
+
+ @Override
+ public QPlayer getOwner() {
+ return owner;
+ }
+
+ public Inventory toInventory(int page) {
+ String title = "Quest Creator";
+
+ Inventory inventory = Bukkit.createInventory(null, 9, title);
+
+ ItemStack newQuest = new ItemStack(Material.STAINED_GLASS_PANE, 1, (short) 5);
+ ItemMeta newQuestM = newQuest.getItemMeta();
+ List<String> newQuestL = new ArrayList<>();
+ newQuestM.setDisplayName(ChatColor.GREEN.toString() + ChatColor.BOLD + "New Quest");
+ newQuestL.add(ChatColor.GRAY + "Click to make a new quest.");
+ newQuestM.setLore(newQuestL);
+ newQuest.setItemMeta(newQuestM);
+
+ ItemStack editQuest = new ItemStack(Material.STAINED_GLASS_PANE, 1, (short) 1);
+ ItemMeta editQuestM = editQuest.getItemMeta();
+ List<String> editQuestL = new ArrayList<>();
+ editQuestM.setDisplayName(ChatColor.GREEN.toString() + ChatColor.BOLD + "Edit Quest");
+ editQuestL.add(ChatColor.GRAY + "Click to edit an existing quest.");
+ editQuestM.setLore(editQuestL);
+ editQuest.setItemMeta(editQuestM);
+
+ ItemStack removeQuest = new ItemStack(Material.STAINED_GLASS_PANE, 1, (short) 14);
+ ItemMeta removeQuestM = removeQuest.getItemMeta();
+ List<String> removeQuestL = new ArrayList<>();
+ removeQuestM.setDisplayName(ChatColor.GREEN.toString() + ChatColor.BOLD + "Delete Quest");
+ removeQuestL.add(ChatColor.GRAY + "Click to delete an existing quest.");
+ removeQuestM.setLore(removeQuestL);
+ removeQuest.setItemMeta(removeQuestM);
+
+ inventory.setItem(2, newQuest);
+ inventory.setItem(4, editQuest);
+ inventory.setItem(6, removeQuest);
+
+ return inventory;
+ }
+
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/player/QPlayer.java b/src/main/java/me/fatpigsarefat/quests/player/QPlayer.java
new file mode 100644
index 00000000..e797d7bb
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/player/QPlayer.java
@@ -0,0 +1,123 @@
+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;
+ private boolean onlyDataLoaded;
+
+ public QPlayer(UUID uuid, QuestProgressFile questProgressFile) {
+ this(uuid, questProgressFile, false);
+ }
+
+ public QPlayer(UUID uuid, QuestProgressFile questProgressFile, boolean onlyDataLoaded) {
+ this.uuid = uuid;
+ this.questProgressFile = questProgressFile;
+ this.onlyDataLoaded = onlyDataLoaded;
+ }
+
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ public void openCategory(Category category) {
+ if (onlyDataLoaded) {
+ return;
+ }
+
+ 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() {
+ if (onlyDataLoaded) {
+ return;
+ }
+
+ 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 boolean isOnlyDataLoaded() {
+ return onlyDataLoaded;
+ }
+
+ public void setOnlyDataLoaded(boolean onlyDataLoaded) {
+ this.onlyDataLoaded = onlyDataLoaded;
+ }
+
+ public QuestProgressFile getQuestProgressFile() {
+ return questProgressFile;
+ }
+
+ public QuestProgressFile setQuestProgressFile() {
+ return questProgressFile;
+ }
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/player/QPlayerManager.java b/src/main/java/me/fatpigsarefat/quests/player/QPlayerManager.java
new file mode 100644
index 00000000..ef5e54b4
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/player/QPlayerManager.java
@@ -0,0 +1,78 @@
+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.*;
+
+public class QPlayerManager {
+
+ private Map<UUID, QPlayer> qPlayers = new HashMap<>();
+
+ public void addPlayer(QPlayer qPlayer) {
+ qPlayers.put(qPlayer.getUuid(), qPlayer);
+ }
+
+ public QPlayer getPlayer(UUID uuid) {
+ return qPlayers.get(uuid);
+ }
+
+ public void removePlayer(UUID uuid) {
+ qPlayers.remove(uuid);
+ }
+
+ public Collection<QPlayer> getQPlayers() {
+ return qPlayers.values();
+ }
+
+ public void loadPlayer(UUID uuid) {
+ loadPlayer(uuid, false);
+ }
+
+ public void loadPlayer(UUID uuid, boolean onlyData) {
+ if (getPlayer(uuid) == null || getPlayer(uuid).isOnlyDataLoaded()) {
+ QuestProgressFile questProgressFile = new QuestProgressFile(uuid);
+
+ try {
+ 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);
+ }
+ }
+ }
+ }
+ } catch (Exception ignored) {
+ // fuck
+ }
+
+ QPlayer qPlayer = new QPlayer(uuid, questProgressFile, onlyData);
+
+ addPlayer(qPlayer);
+ }
+ }
+
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/player/questprogressfile/QuestProgress.java b/src/main/java/me/fatpigsarefat/quests/player/questprogressfile/QuestProgress.java
new file mode 100644
index 00000000..97e0b517
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/player/questprogressfile/QuestProgress.java
@@ -0,0 +1,106 @@
+package me.fatpigsarefat.quests.player.questprogressfile;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class QuestProgress {
+
+ private Map<String, TaskProgress> taskProgress = new HashMap<>();
+ 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 setCompleted(boolean completed) {
+ this.completed = completed;
+ this.modified = true;
+ }
+
+ public boolean isStarted() {
+ return started;
+ }
+
+ public void setStarted(boolean started) {
+ this.started = started;
+ 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.put(taskProgress.getTaskId(), taskProgress);
+ }
+
+ public Collection<TaskProgress> getTaskProgress() {
+ return taskProgress.values();
+ }
+
+ public TaskProgress getTaskProgress(String taskId) {
+ TaskProgress tP = taskProgress.getOrDefault(taskId, null);
+ if (tP == null) {
+ repairTaskProgress(taskId);
+ tP = taskProgress.getOrDefault(taskId, null);
+ }
+ return tP;
+ }
+
+ public void repairTaskProgress(String taskid) {
+ TaskProgress taskProgress = new TaskProgress(taskid, null, player, false);
+ this.addTaskProgress(taskProgress);
+ }
+
+ public boolean isWorthSaving() {
+ return modified;
+ }
+
+ public void setWorthSaving(boolean modified) {
+ this.modified = modified;
+ }
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/player/questprogressfile/QuestProgressFile.java b/src/main/java/me/fatpigsarefat/quests/player/questprogressfile/QuestProgressFile.java
new file mode 100644
index 00000000..144093e6
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/player/questprogressfile/QuestProgressFile.java
@@ -0,0 +1,254 @@
+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.*;
+import java.util.concurrent.TimeUnit;
+
+public class QuestProgressFile {
+
+ private Map<String, QuestProgress> questProgress = new HashMap<>();
+ 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);
+ Bukkit.getServer().getScheduler().runTask(Quests.getInstance(), () -> {
+ 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;
+ }
+
+ /**
+ * Start a quest for the player.
+ *
+ * @param quest the quest to check
+ * @return 0 if successful, 1 if limit reached, 2 if quest is already completed, 3 if quest has cooldown, 4 if still locked
+ */
+ public int 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 1;
+ }
+ 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 2;
+ }
+ 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 3;
+ }
+ if (!hasMetRequirements(quest)) {
+ if (Bukkit.getPlayer(player) != null) {
+ Player player = Bukkit.getPlayer(getPlayer());
+ player.sendMessage(Messages.QUEST_START_LOCKED.getMessage());
+ }
+ return 4;
+ }
+ 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 0;
+ }
+
+ public boolean cancelQuest(Quest quest) {
+ QuestProgress questProgress = getQuestProgress(quest);
+ if (!questProgress.isStarted()) {
+ if (Bukkit.getPlayer(player) != null) {
+ Bukkit.getPlayer(getPlayer()).sendMessage(Messages.QUEST_CANCEL_NOTSTARTED.getMessage());
+ }
+ return false;
+ }
+ questProgress.setStarted(false);
+ for (TaskProgress taskProgress : questProgress.getTaskProgress()) {
+ taskProgress.setProgress(null);
+ }
+ if (Bukkit.getPlayer(player) != null) {
+ Bukkit.getPlayer(getPlayer()).sendMessage(Messages.QUEST_CANCEL.getMessage().replace("{quest}", quest.getDisplayNameStripped()));
+ }
+ return true;
+ }
+
+ public void addQuestProgress(QuestProgress questProgress) {
+ this.questProgress.put(questProgress.getQuestId(), questProgress);
+ }
+
+ public List<Quest> getStartedQuests() {
+ List<Quest> startedQuests = new ArrayList<>();
+ for (QuestProgress questProgress : questProgress.values()) {
+ if (questProgress.isStarted()) {
+ startedQuests.add(Quests.getQuestManager().getQuestById(questProgress.getQuestId()));
+ }
+ }
+ return startedQuests;
+ }
+
+ public boolean hasQuestProgress(Quest quest) {
+ return questProgress.containsKey(quest.getId());
+ }
+
+ 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) {
+ if (questProgress.containsKey(quest.getId())) {
+ return questProgress.get(quest.getId());
+ } else 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);
+ }
+
+ addQuestProgress(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 : questProgress.values()) {
+ if (!questProgress.isWorthSaving()) {
+ continue;
+ }
+ data.set("quest-progress." + questProgress.getQuestId() + ".started", questProgress.isStarted());
+ data.set("quest-progress." + questProgress.getQuestId() + ".completed", questProgress.isCompleted());
+ data.set("quest-progress." + questProgress.getQuestId() + ".completed-before", questProgress.isCompletedBefore());
+ 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();
+ }
+ }
+
+ public void clear() {
+ questProgress.clear();
+ }
+
+}
+
diff --git a/src/main/java/me/fatpigsarefat/quests/player/questprogressfile/TaskProgress.java b/src/main/java/me/fatpigsarefat/quests/player/questprogressfile/TaskProgress.java
new file mode 100644
index 00000000..3b896334
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/quests/Category.java b/src/main/java/me/fatpigsarefat/quests/quests/Category.java
new file mode 100644
index 00000000..b17f6db7
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/quests/Quest.java b/src/main/java/me/fatpigsarefat/quests/quests/Quest.java
new file mode 100644
index 00000000..0f0a3638
--- /dev/null
+++ b/src/main/java/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.*;
+
+public class Quest {
+
+ private Map<String, Task> tasks = new HashMap<>();
+ //TODO: maybe store by <tasktypename (string), list<task>> since we never get task by id, but always get tasks by type.
+ 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.put(task.getId(), task);
+ }
+
+ public Collection<Task> getTasks() {
+ return tasks.values();
+ }
+
+ public List<Task> getTasksOfType(String type) {
+ List<Task> tasks = new ArrayList<>();
+ for (Task task : getTasks()) {
+ 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/main/java/me/fatpigsarefat/quests/quests/QuestManager.java b/src/main/java/me/fatpigsarefat/quests/quests/QuestManager.java
new file mode 100644
index 00000000..1ec6ea63
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/quests/Task.java b/src/main/java/me/fatpigsarefat/quests/quests/Task.java
new file mode 100644
index 00000000..fb209145
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/quests/tasktypes/ConfigValue.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/ConfigValue.java
new file mode 100644
index 00000000..d886fe16
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/ConfigValue.java
@@ -0,0 +1,29 @@
+package me.fatpigsarefat.quests.quests.tasktypes;
+
+/**
+ * This is for the quest creator and is purely cosmetic.
+ */
+public final class ConfigValue {
+
+ private String key;
+ private boolean required;
+ private String description;
+
+ public ConfigValue(String key, boolean required, String description) {
+ this.key = key;
+ this.required = required;
+ this.description = description;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public boolean isRequired() {
+ return required;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/TaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/TaskType.java
new file mode 100644
index 00000000..bb4ddea5
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/TaskType.java
@@ -0,0 +1,56 @@
+package me.fatpigsarefat.quests.quests.tasktypes;
+
+import me.fatpigsarefat.quests.quests.Quest;
+import org.bukkit.event.Listener;
+
+import java.util.ArrayList;
+import java.util.Collections;
+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;
+ }
+
+ public List<ConfigValue> getCreatorConfigValues() {
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/TaskTypeManager.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/TaskTypeManager.java
new file mode 100644
index 00000000..163e128c
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/ASkyBlockLevelType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/ASkyBlockLevelType.java
new file mode 100644
index 00000000..5fcdda15
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/ASkyBlockLevelType.java
@@ -0,0 +1,64 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class ASkyBlockLevelType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public ASkyBlockLevelType() {
+ super("askyblock_level", "fatpigsarefat", "Reach a certain island level for ASkyBlock.");
+ this.creatorConfigValues.add(new ConfigValue("level", true, "Minimum island level needed."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/BuildingCertainTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/BuildingCertainTaskType.java
new file mode 100644
index 00000000..5bda96c3
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/BuildingCertainTaskType.java
@@ -0,0 +1,103 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+import me.fatpigsarefat.quests.Quests;
+import me.fatpigsarefat.quests.blocktype.Block;
+import me.fatpigsarefat.quests.blocktype.SimilarBlocks;
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.apache.commons.lang.StringUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.BlockPlaceEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class BuildingCertainTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public BuildingCertainTaskType() {
+ super("blockplacecertain", "fatpigsarefat", "Place a set amount of a specific block.");
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of blocks to be placed."));
+ this.creatorConfigValues.add(new ConfigValue("block", true, "Name or ID of block."));
+ this.creatorConfigValues.add(new ConfigValue("data", false, "Data code for block."));
+ this.creatorConfigValues.add(new ConfigValue("use-similar-blocks", false, "If true, this will ignore orientation of doors, logs etc."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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");
+ Object configSimilarBlocks = task.getConfigValue("use-similar-blocks");
+
+ if (StringUtils.isNumeric(String.valueOf(configBlock))) {
+ material = Material.getMaterial((int) configBlock);
+ } else {
+ material = Material.getMaterial(String.valueOf(configBlock));
+ }
+
+ Material blockType = event.getBlock().getType();
+ short blockData = event.getBlock().getData();
+
+ if (configSimilarBlocks != null && ((Boolean) configSimilarBlocks)) {
+ Block block;
+ if ((block = SimilarBlocks.getSimilarBlock(new Block(blockType, blockData))) != null) {
+ blockType = block.getMaterial();
+ blockData = block.getData();
+ }
+ }
+
+ if (blockType.equals(material)) {
+ if (configData != null && (((int) blockData) != ((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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/BuildingTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/BuildingTaskType.java
new file mode 100644
index 00000000..0943ddf9
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/BuildingTaskType.java
@@ -0,0 +1,68 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.BlockPlaceEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class BuildingTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public BuildingTaskType() {
+ super("blockplace", "fatpigsarefat", "Place a set amount of blocks.");
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of blocks to be placed."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/FarmingTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/FarmingTaskType.java
new file mode 100644
index 00000000..1fff9703
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/FarmingTaskType.java
@@ -0,0 +1,94 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+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;
+import org.bukkit.material.Crops;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class FarmingTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public FarmingTaskType() {
+ super("farming", "fatpigsarefat", "Break a set amount of a crop.");
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of crops to be broken."));
+ this.creatorConfigValues.add(new ConfigValue("crop", true, "Name or ID of crop."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockBreak(BlockBreakEvent event) {
+ //TODO: finish this
+ if (!(event.getBlock().getState() instanceof Crops)) {
+ return;
+ }
+ Crops crop = (Crops) event.getBlock().getState();
+
+ QPlayer qPlayer = 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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/FishingTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/FishingTaskType.java
new file mode 100644
index 00000000..87ce8147
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/FishingTaskType.java
@@ -0,0 +1,74 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.player.PlayerFishEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class FishingTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public FishingTaskType() {
+ super("fishing", "fatpigsarefat", "Catch a set amount of items from the sea.");
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of fish to be caught."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/InventoryTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/InventoryTaskType.java
new file mode 100644
index 00000000..ab3c2af5
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/InventoryTaskType.java
@@ -0,0 +1,116 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.apache.commons.lang.StringUtils;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.inventory.InventoryInteractEvent;
+import org.bukkit.event.player.PlayerPickupItemEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class InventoryTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public InventoryTaskType() {
+ super("inventory", "fatpigsarefat", "Obtain a set of items.");
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of item to retrieve."));
+ this.creatorConfigValues.add(new ConfigValue("item", true, "Name or ID of item."));
+ this.creatorConfigValues.add(new ConfigValue("remove-items-when-complete", false, "Take the items away from the player on completion (true/false, " +
+ "default = false)."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onItemPickup(PlayerPickupItemEvent event) {
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ checkInventory(event.getPlayer());
+ }
+ }.runTaskLater(Quests.getInstance(), 1L);
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onInventoryClick(InventoryInteractEvent event) {
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ checkInventory((Player) event.getWhoClicked());
+ }
+ }.runTaskLater(Quests.getInstance(), 1L);
+ }
+
+ private void checkInventory(Player player) {
+ QPlayer qPlayer = Quests.getPlayerManager().getPlayer(player.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;
+ }
+
+ Material material;
+ int amount = (int) task.getConfigValue("amount");
+ Object configBlock = task.getConfigValue("item");
+ Object configData = task.getConfigValue("data");
+ Object remove = task.getConfigValue("remove-items-when-complete");
+
+ if (StringUtils.isNumeric(String.valueOf(configBlock))) {
+ material = Material.getMaterial((int) configBlock);
+ } else {
+ material = Material.getMaterial(String.valueOf(configBlock));
+ }
+
+ if (material == null) {
+ continue;
+ }
+ ItemStack is;
+ if (configData != null) {
+ is = new ItemStack(material, 1, ((Integer) configData).shortValue());
+ } else {
+ is = new ItemStack(material, 1);
+ }
+
+ if (player.getInventory().containsAtLeast(is, amount)) {
+ is.setAmount(amount);
+ taskProgress.setCompleted(true);
+
+ if (remove != null && ((Boolean) remove)) {
+ player.getInventory().removeItem(is);
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MilkingTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MilkingTaskType.java
new file mode 100644
index 00000000..7de92d59
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MilkingTaskType.java
@@ -0,0 +1,77 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.Material;
+import org.bukkit.entity.Cow;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.player.PlayerInteractEntityEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class MilkingTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public MilkingTaskType() {
+ super("milking", "fatpigsarefat", "Milk a set amount of cows.");
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of cows to be milked."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MiningCertainTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MiningCertainTaskType.java
new file mode 100644
index 00000000..0199150e
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MiningCertainTaskType.java
@@ -0,0 +1,102 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+import me.fatpigsarefat.quests.Quests;
+import me.fatpigsarefat.quests.blocktype.Block;
+import me.fatpigsarefat.quests.blocktype.SimilarBlocks;
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class MiningCertainTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public MiningCertainTaskType() {
+ super("blockbreakcertain", "fatpigsarefat", "Break a set amount of a specific block.");
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of blocks to be broken."));
+ this.creatorConfigValues.add(new ConfigValue("block", true, "Name or ID of block."));
+ this.creatorConfigValues.add(new ConfigValue("data", false, "Data code for block."));
+ this.creatorConfigValues.add(new ConfigValue("use-similar-blocks", false, "If true, this will ignore orientation of doors, logs etc."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockBreak(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");
+ Object configSimilarBlocks = task.getConfigValue("use-similar-blocks");
+
+ if (StringUtils.isNumeric(String.valueOf(configBlock))) {
+ material = Material.getMaterial((int) configBlock);
+ } else {
+ material = Material.getMaterial(String.valueOf(configBlock));
+ }
+
+ Material blockType = event.getBlock().getType();
+ short blockData = event.getBlock().getData();
+
+ if (configSimilarBlocks != null && ((Boolean) configSimilarBlocks)) {
+ Block block;
+ if ((block = SimilarBlocks.getSimilarBlock(new Block(blockType, blockData))) != null) {
+ blockType = block.getMaterial();
+ blockData = block.getData();
+ }
+ }
+
+ if (blockType.equals(material)) {
+ if (configData != null && (((int) blockData) != ((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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MiningTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MiningTaskType.java
new file mode 100644
index 00000000..f0ba95ca
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MiningTaskType.java
@@ -0,0 +1,72 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.BlockBreakEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class MiningTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public MiningTaskType() {
+ // type, author, description
+ super("blockbreak", "fatpigsarefat", "Break a set amount of blocks.");
+
+ // config values for the quest creator to use, if unspecified then the quest creator will not know what to put here (and will require users to
+ // go into the config and manually configure there)
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of blocks to be broken."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MobkillingCertainTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MobkillingCertainTaskType.java
new file mode 100644
index 00000000..1a026d5f
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MobkillingCertainTaskType.java
@@ -0,0 +1,108 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.entity.EntityDeathEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class MobkillingCertainTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public MobkillingCertainTaskType() {
+ super("mobkillingcertain", "fatpigsarefat", "Kill a set amount of a specific entity type.");
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of mobs to be killed."));
+ this.creatorConfigValues.add(new ConfigValue("mob", true, "Name of mob."));
+ this.creatorConfigValues.add(new ConfigValue("name", false, "Only allow a specific name for mob (unspecified = any name allowed)."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onMobKill(EntityDeathEvent event) {
+ Entity killer = event.getEntity().getKiller();
+ Entity mob = event.getEntity();
+
+ if (mob == null || 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;
+ try {
+ entity = EntityType.valueOf(configEntity);
+ } catch (IllegalArgumentException ex) {
+ continue;
+ }
+
+ if (configName != null) {
+ configName = ChatColor.translateAlternateColorCodes('&', configName);
+ if (mob.getCustomName() != null && !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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MobkillingTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MobkillingTaskType.java
new file mode 100644
index 00000000..8e0e5550
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/MobkillingTaskType.java
@@ -0,0 +1,101 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.entity.Animals;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Monster;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.entity.EntityDeathEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class MobkillingTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public MobkillingTaskType() {
+ super("mobkilling", "fatpigsarefat", "Kill a set amount of entities.");
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of mobs to be killed."));
+ this.creatorConfigValues.add(new ConfigValue("hostile", false, "Only allow hostile or non-hostile mobs (unspecified = any type allowed)."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/PlayerkillingTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/PlayerkillingTaskType.java
new file mode 100644
index 00000000..6a9e7481
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/PlayerkillingTaskType.java
@@ -0,0 +1,84 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.entity.EntityDeathEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class PlayerkillingTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public PlayerkillingTaskType() {
+ super("playerkilling", "fatpigsarefat", "Kill a set amount of players.");
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of mobs to be killed."));
+ this.creatorConfigValues.add(new ConfigValue("hostile", false, "Only allow hostile or non-hostile mobs (unspecified = any type allowed)."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/PlaytimeTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/PlaytimeTaskType.java
new file mode 100644
index 00000000..6268b9de
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/PlaytimeTaskType.java
@@ -0,0 +1,54 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+
+public final class PlaytimeTaskType extends TaskType {
+
+ public PlaytimeTaskType() {
+ super("playtime", "Reinatix", "Track the amount of playing time a user has been on");
+ playTime();
+ }
+
+ public void playTime() {
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ QPlayer qPlayer = Quests.getPlayerManager().getPlayer(player.getUniqueId());
+ QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile();
+ for (Quest quest : PlaytimeTaskType.super.getRegisteredQuests()) {
+ if (questProgressFile.hasStartedQuest(quest)) {
+ QuestProgress questProgress = questProgressFile.getQuestProgress(quest);
+ for (Task task : quest.getTasksOfType(PlaytimeTaskType.super.getType())) {
+ TaskProgress taskProgress = questProgress.getTaskProgress(task.getId());
+ if (taskProgress.isCompleted()) {
+ continue;
+ }
+ int minutes = (int) task.getConfigValue("minutes");
+ if (taskProgress.getProgress() == null) {
+ taskProgress.setProgress(1);
+ } else {
+ taskProgress.setProgress((int) taskProgress.getProgress() + 1);
+ }
+ if (((int) taskProgress.getProgress()) >= minutes) {
+ taskProgress.setCompleted(true);
+ }
+ }
+ }
+ }
+ }
+ }
+ }.runTaskTimer(Quests.getInstance(), 1200L, 1200L);
+ }
+
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/PositionTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/PositionTaskType.java
new file mode 100644
index 00000000..6702f732
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/PositionTaskType.java
@@ -0,0 +1,87 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.player.PlayerMoveEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class PositionTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public PositionTaskType() {
+ super("position", "fatpigsarefat", "Reach a set of co-ordinates.");
+ this.creatorConfigValues.add(new ConfigValue("x", true, "X position."));
+ this.creatorConfigValues.add(new ConfigValue("y", true, "Y position."));
+ this.creatorConfigValues.add(new ConfigValue("z", true, "Z position."));
+ this.creatorConfigValues.add(new ConfigValue("world", true, "Name of world."));
+ this.creatorConfigValues.add(new ConfigValue("distance-padding", false, "Padding zone in meters/blocks (default/unspecified = 0)."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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 x = (int) task.getConfigValue("x");
+ int y = (int) task.getConfigValue("y");
+ int z = (int) task.getConfigValue("z");
+ String worldString = (String) task.getConfigValue("world");
+ int padding = 0;
+ if (task.getConfigValue("distance-padding") != null) {
+ padding = (int) task.getConfigValue("distance-padding");
+ }
+ World world = Bukkit.getWorld(worldString);
+ if (world == null) {
+ return;
+ }
+
+ Location location = new Location(world, x, y, z);
+ if (player.getWorld().equals(world) && player.getLocation().getBlockX() == location.getBlockX() && player.getLocation().getBlockY() == location.getBlockY() && player.getLocation().getBlockZ() == location.getBlockZ()) {
+ taskProgress.setCompleted(true);
+ } else if (player.getWorld().equals(world) && player.getLocation().distance(location) < padding) {
+ taskProgress.setCompleted(true);
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/ShearingTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/ShearingTaskType.java
new file mode 100644
index 00000000..316c3e28
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/ShearingTaskType.java
@@ -0,0 +1,76 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Sheep;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.player.PlayerShearEntityEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class ShearingTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public ShearingTaskType() {
+ super("shearing", "fatpigsarefat", "Shear a set amount of sheep.");
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of cows to be milked."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/TamingTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/TamingTaskType.java
new file mode 100644
index 00000000..beca3b4e
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/TamingTaskType.java
@@ -0,0 +1,75 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.entity.EntityTameEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class TamingTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public TamingTaskType() {
+ super("taming", "fatpigsarefat", "Tame a set amount of animals.");
+ this.creatorConfigValues.add(new ConfigValue("amount", true, "Amount of animals to be tamed."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/WalkingTaskType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/WalkingTaskType.java
new file mode 100644
index 00000000..5ddc2241
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/WalkingTaskType.java
@@ -0,0 +1,75 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.player.PlayerMoveEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class WalkingTaskType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public WalkingTaskType() {
+ super("walking", "fatpigsarefat", "Walk a set distance.");
+ this.creatorConfigValues.add(new ConfigValue("distance", true, "Amount of meters (blocks) to be travelled."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/uSkyBlockLevelType.java b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/uSkyBlockLevelType.java
new file mode 100644
index 00000000..d140ab8f
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/quests/tasktypes/types/uSkyBlockLevelType.java
@@ -0,0 +1,65 @@
+package me.fatpigsarefat.quests.quests.tasktypes.types;
+
+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 me.fatpigsarefat.quests.quests.tasktypes.ConfigValue;
+import me.fatpigsarefat.quests.quests.tasktypes.TaskType;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import us.talabrek.ultimateskyblock.api.event.uSkyBlockScoreChangedEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class uSkyBlockLevelType extends TaskType {
+
+ private List<ConfigValue> creatorConfigValues = new ArrayList<>();
+
+ public uSkyBlockLevelType() {
+ super("uskyblock_level", "fatpigsarefat", "Reach a certain island level for uSkyBlock.");
+ this.creatorConfigValues.add(new ConfigValue("level", true, "Minimum island level needed."));
+ }
+
+ @Override
+ public List<ConfigValue> getCreatorConfigValues() {
+ return creatorConfigValues;
+ }
+
+ @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/main/java/me/fatpigsarefat/quests/title/Title.java b/src/main/java/me/fatpigsarefat/quests/title/Title.java
new file mode 100644
index 00000000..4851440b
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/title/Title_Bukkit.java b/src/main/java/me/fatpigsarefat/quests/title/Title_Bukkit.java
new file mode 100644
index 00000000..0a39b2eb
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/title/Title_Bukkit.java
@@ -0,0 +1,11 @@
+package me.fatpigsarefat.quests.title;
+
+import org.bukkit.entity.Player;
+
+public class Title_Bukkit implements Title {
+
+ @Override
+ public void sendTitle(Player player, String message, String submessage) {
+ player.sendTitle(message, submessage, 10, 100, 10);
+ }
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/title/Title_BukkitNoTimings.java b/src/main/java/me/fatpigsarefat/quests/title/Title_BukkitNoTimings.java
new file mode 100644
index 00000000..97fe6e02
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/title/Title_BukkitNoTimings.java
@@ -0,0 +1,13 @@
+package me.fatpigsarefat.quests.title;
+
+import org.bukkit.entity.Player;
+
+public class Title_BukkitNoTimings implements Title {
+
+ // this one is for 1.8, 1.9 and 1.10 where there was no timings method
+ @Override
+ public void sendTitle(Player player, String message, String submessage) {
+ player.sendTitle(message, submessage);
+ }
+
+}
diff --git a/src/main/java/me/fatpigsarefat/quests/title/Title_Other.java b/src/main/java/me/fatpigsarefat/quests/title/Title_Other.java
new file mode 100644
index 00000000..eef4bc07
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/title/Title_v1_10_R1.java b/src/main/java/me/fatpigsarefat/quests/title/Title_v1_10_R1.java
new file mode 100644
index 00000000..0343ccbd
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/title/Title_v1_11_R1.java b/src/main/java/me/fatpigsarefat/quests/title/Title_v1_11_R1.java
new file mode 100644
index 00000000..edb7e9e7
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/title/Title_v1_12_R1.java b/src/main/java/me/fatpigsarefat/quests/title/Title_v1_12_R1.java
new file mode 100644
index 00000000..daebefa3
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/title/Title_v1_8_R1.java b/src/main/java/me/fatpigsarefat/quests/title/Title_v1_8_R1.java
new file mode 100644
index 00000000..4de97c98
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/title/Title_v1_8_R2.java b/src/main/java/me/fatpigsarefat/quests/title/Title_v1_8_R2.java
new file mode 100644
index 00000000..acda3c70
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/title/Title_v1_8_R3.java b/src/main/java/me/fatpigsarefat/quests/title/Title_v1_8_R3.java
new file mode 100644
index 00000000..0bc56b5f
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/title/Title_v1_9_R1.java b/src/main/java/me/fatpigsarefat/quests/title/Title_v1_9_R1.java
new file mode 100644
index 00000000..80e25392
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/title/Title_v1_9_R2.java b/src/main/java/me/fatpigsarefat/quests/title/Title_v1_9_R2.java
new file mode 100644
index 00000000..29b52bbd
--- /dev/null
+++ b/src/main/java/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/main/java/me/fatpigsarefat/quests/updater/Updater.java b/src/main/java/me/fatpigsarefat/quests/updater/Updater.java
new file mode 100644
index 00000000..28cfde26
--- /dev/null
+++ b/src/main/java/me/fatpigsarefat/quests/updater/Updater.java
@@ -0,0 +1,65 @@
+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.concurrent.TimeUnit;
+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;
+ private long lastCheck;
+
+ 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() {
+ if (lastCheck != 0 && TimeUnit.MINUTES.convert(System.currentTimeMillis() - lastCheck, TimeUnit.MILLISECONDS) < 10) {
+ return updateReady;
+ }
+ try {
+ lastCheck = System.currentTimeMillis();
+ 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