From af7e1e435f577bbf9742bb526ac00a71a21c219c Mon Sep 17 00:00:00 2001 From: LMBishop <13875753+LMBishop@users.noreply.github.com> Date: Thu, 17 Jun 2021 13:32:02 +0100 Subject: Convert to multi module project - Common module to provide an abstract Quests plugin - Api is still todo --- .../quests/common/config/ConfigProblem.java | 63 +++++ .../common/config/ConfigProblemDescriptions.java | 35 +++ .../quests/common/config/QuestsConfig.java | 25 ++ .../quests/common/config/QuestsLoader.java | 11 + .../quests/common/enums/QuestStartResult.java | 13 ++ .../quests/common/logger/QuestsLogger.java | 44 ++++ .../quests/common/player/QPlayer.java | 127 +++++++++++ .../quests/common/player/QPlayerManager.java | 158 +++++++++++++ .../quests/common/player/QPlayerPreferences.java | 18 ++ .../player/questprogressfile/QuestProgress.java | 143 ++++++++++++ .../questprogressfile/QuestProgressFile.java | 253 +++++++++++++++++++++ .../player/questprogressfile/TaskProgress.java | 73 ++++++ .../quests/common/plugin/Quests.java | 38 ++++ .../quests/common/quest/Category.java | 33 +++ .../leonardobishop/quests/common/quest/Quest.java | 120 ++++++++++ .../quests/common/quest/QuestCompleter.java | 11 + .../quests/common/quest/QuestManager.java | 49 ++++ .../leonardobishop/quests/common/quest/Task.java | 41 ++++ .../common/questcontroller/QuestController.java | 23 ++ .../quests/common/scheduler/ServerScheduler.java | 8 + .../quests/common/storage/StorageProvider.java | 17 ++ .../quests/common/tasktype/TaskType.java | 108 +++++++++ .../quests/common/tasktype/TaskTypeManager.java | 67 ++++++ .../quests/common/updater/Updater.java | 78 +++++++ .../leonardobishop/quests/common/util/Format.java | 21 ++ 25 files changed, 1577 insertions(+) create mode 100644 common/src/main/java/com/leonardobishop/quests/common/config/ConfigProblem.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/config/ConfigProblemDescriptions.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/config/QuestsConfig.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/config/QuestsLoader.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/enums/QuestStartResult.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/logger/QuestsLogger.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/player/QPlayer.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/player/QPlayerManager.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/player/QPlayerPreferences.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/player/questprogressfile/QuestProgress.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/player/questprogressfile/QuestProgressFile.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/player/questprogressfile/TaskProgress.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/plugin/Quests.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/quest/Category.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/quest/Quest.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/quest/QuestCompleter.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/quest/QuestManager.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/quest/Task.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/questcontroller/QuestController.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/scheduler/ServerScheduler.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/storage/StorageProvider.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/tasktype/TaskType.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/tasktype/TaskTypeManager.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/updater/Updater.java create mode 100644 common/src/main/java/com/leonardobishop/quests/common/util/Format.java (limited to 'common/src') diff --git a/common/src/main/java/com/leonardobishop/quests/common/config/ConfigProblem.java b/common/src/main/java/com/leonardobishop/quests/common/config/ConfigProblem.java new file mode 100644 index 00000000..d9f30c09 --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/config/ConfigProblem.java @@ -0,0 +1,63 @@ +package com.leonardobishop.quests.common.config; + +public final class ConfigProblem { + + private final ConfigProblemType type; + private final String description; + private final String location; + + public ConfigProblem(ConfigProblemType type, String description, String location) { + this.type = type; + this.description = description == null ? "?" : description; + ; + this.location = location == null ? "?" : location; + } + + public ConfigProblem(ConfigProblemType type, String description) { + this.type = type; + this.description = description == null ? "?" : description; + ; + this.location = "?"; + } + + public ConfigProblemType getType() { + return type; + } + + public String getDescription() { + return description; + } + + public String getLocation() { + return location; + } + + public enum ConfigProblemType { + + ERROR("Error", "E", 1), + WARNING("Warning", "W", 2); + + private final String title; + private final String shortened; + private final int priority; + + ConfigProblemType(String title, String shortened, int priority) { + this.title = title; + this.shortened = shortened; + this.priority = priority; + } + + public String getTitle() { + return title; + } + + public String getShortened() { + return shortened; + } + + public int getPriority() { + return priority; + } + + } +} \ No newline at end of file diff --git a/common/src/main/java/com/leonardobishop/quests/common/config/ConfigProblemDescriptions.java b/common/src/main/java/com/leonardobishop/quests/common/config/ConfigProblemDescriptions.java new file mode 100644 index 00000000..868bdfbb --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/config/ConfigProblemDescriptions.java @@ -0,0 +1,35 @@ +package com.leonardobishop.quests.common.config; + +public enum ConfigProblemDescriptions { + + MALFORMED_YAML("Malformed YAML file, cannot read config"), + INVALID_QUEST_ID("ID '%s' is invalid, must be alphanumeric, unique and with no spaces"), + NO_TASKS("Quest contains no valid tasks"), + NO_TASK_TYPE("Task type not specified"), + UNKNOWN_TASK_TYPE("Task type '%s' does not exist"), + NO_DISPLAY_NAME("No name specified"), + NO_DISPLAY_MATERIAL("No material specified"), + UNKNOWN_MATERIAL("Material '%s' does not exist"), + UNKNOWN_ENTITY_TYPE("Entity type '%s' does not exist"), + TASK_MALFORMED_NOT_SECTION("Task '%s' is not a configuration section (has no fields)"), + TASK_MISSING_FIELD("Required field '%s' is missing for task type '%s'"), + UNKNOWN_TASK_REFERENCE("Attempt to reference unknown task '%s'"), + UNKNOWN_CATEGORY("Category '%s' does not exist"), + UNKNOWN_REQUIREMENT("Quest requirement '%s' does not exist"); + + private final String description; + + ConfigProblemDescriptions(String description) { + this.description = description; + } + + @Override + public String toString() { + return getDescription(); + } + + public String getDescription(String... format) { + return String.format(description, (Object[]) format); + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/leonardobishop/quests/common/config/QuestsConfig.java b/common/src/main/java/com/leonardobishop/quests/common/config/QuestsConfig.java new file mode 100644 index 00000000..be93ed83 --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/config/QuestsConfig.java @@ -0,0 +1,25 @@ +package com.leonardobishop.quests.common.config; + +import java.util.List; + +public interface QuestsConfig { + + boolean loadConfig(); + + String getString(String path); + + String getString(String path, String def); + + boolean getBoolean(String path); + + boolean getBoolean(String path, boolean def); + + int getInt(String path); + + int getInt(String path, int def); + + List getStringList(String path); + + List getStringList(String path, List def); + +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/config/QuestsLoader.java b/common/src/main/java/com/leonardobishop/quests/common/config/QuestsLoader.java new file mode 100644 index 00000000..09db3c52 --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/config/QuestsLoader.java @@ -0,0 +1,11 @@ +package com.leonardobishop.quests.common.config; + +import java.io.File; +import java.util.List; +import java.util.Map; + +public interface QuestsLoader { + + Map> loadQuests(File root); + +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/enums/QuestStartResult.java b/common/src/main/java/com/leonardobishop/quests/common/enums/QuestStartResult.java new file mode 100644 index 00000000..28d8a43c --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/enums/QuestStartResult.java @@ -0,0 +1,13 @@ +package com.leonardobishop.quests.common.enums; + +public enum QuestStartResult { + QUEST_SUCCESS, //0 + QUEST_LIMIT_REACHED, //1 + QUEST_ALREADY_COMPLETED, //2 + QUEST_COOLDOWN, //3 + QUEST_LOCKED, //4 + QUEST_ALREADY_STARTED, //5 + QUEST_NO_PERMISSION, //6 + NO_PERMISSION_FOR_CATEGORY, //7 + OTHER //8 +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/logger/QuestsLogger.java b/common/src/main/java/com/leonardobishop/quests/common/logger/QuestsLogger.java new file mode 100644 index 00000000..b4a192cf --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/logger/QuestsLogger.java @@ -0,0 +1,44 @@ +package com.leonardobishop.quests.common.logger; + +public interface QuestsLogger { + + LoggingLevel getServerLoggingLevel(); + + void setServerLoggingLevel(LoggingLevel serverLoggingLevel); + + void log(String str, LoggingLevel level); + + void debug(String str); + + void info(String str); + + void warning(String str); + + void severe(String str); + + enum LoggingLevel { + ERROR(0), + WARNING(1), + INFO(2), + DEBUG(3); + + private int numericVerbosity; + + LoggingLevel(int number) { + numericVerbosity = number; + } + + public int getNumericVerbosity() { + return numericVerbosity; + } + + public static LoggingLevel fromNumber(int number) { + for (LoggingLevel level : LoggingLevel.values()) { + if (level.getNumericVerbosity() == number) { + return level; + } + } + return LoggingLevel.INFO; + } + } +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/player/QPlayer.java b/common/src/main/java/com/leonardobishop/quests/common/player/QPlayer.java new file mode 100644 index 00000000..0792a0fc --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/player/QPlayer.java @@ -0,0 +1,127 @@ +package com.leonardobishop.quests.common.player; + +import com.leonardobishop.quests.common.questcontroller.QuestController; +import com.leonardobishop.quests.common.enums.QuestStartResult; +import com.leonardobishop.quests.common.plugin.Quests; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; +import com.leonardobishop.quests.common.quest.Quest; + +import java.util.UUID; + +/** + * Represents a player. + */ +public class QPlayer { + + private final Quests plugin; + private final UUID uuid; + private final QPlayerPreferences playerPreferences; + private final QuestProgressFile questProgressFile; + private QuestController questController; + + public QPlayer(Quests plugin, UUID uuid, QPlayerPreferences playerPreferences, QuestProgressFile questProgressFile, QuestController questController) { + this.plugin = plugin; + this.uuid = uuid; + this.playerPreferences = playerPreferences; + this.questProgressFile = questProgressFile; + this.questController = questController; + } + + public UUID getPlayerUUID() { + return this.uuid; + } + + /** + * Attempt to complete a quest for the player. This will also play all effects (such as titles, messages etc.) + * and also dispatches all rewards for the player. + * + * @param quest the quest to complete + * @return true (always) + */ + public boolean completeQuest(Quest quest) { + return questController.completeQuestForPlayer(this, quest); + } + + /** + * Attempt to track a quest for the player. This will also play all effects (such as titles, messages etc.) + ** + * @param quest the quest to track + */ + public void trackQuest(Quest quest) { + questController.trackQuestForPlayer(this, quest); + } + + /** + * Gets whether or not the player has started a specific quest. + * + * @param quest the quest to test for + * @return true if the quest is started or quest autostart is enabled and the quest is ready to start, false otherwise + */ + public boolean hasStartedQuest(Quest quest) { + return questController.hasPlayerStartedQuest(this, quest); + } + + /** + * Attempt to start a quest for the player. This will also play all effects (such as titles, messages etc.) + * + * Warning: will fail if the player is not online. + * + * @param quest the quest to start + * @return the quest start result -- {@code QuestStartResult.QUEST_SUCCESS} indicates success + */ + // TODO PlaceholderAPI support + public QuestStartResult startQuest(Quest quest) { + return questController.startQuestForPlayer(this, quest); + } + + /** + * Attempt to cancel a quest for the player. This will also play all effects (such as titles, messages etc.) + * + * @param quest the quest to start + * @return true if the quest was cancelled, false otherwise + */ + public boolean cancelQuest(Quest quest) { + return questController.cancelQuestForPlayer(this, quest); + } + + /** + * Check if the player can start a quest. + * + * Warning: will fail if the player is not online. + * + * @param quest the quest to check + * @return the quest start result + */ + public QuestStartResult canStartQuest(Quest quest) { + return questController.canPlayerStartQuest(this, quest); + } + + + public QuestProgressFile getQuestProgressFile() { + return questProgressFile; + } + + public QPlayerPreferences getPlayerPreferences() { + return playerPreferences; + } + + public QuestController getQuestController() { + return questController; + } + + public void setQuestController(QuestController questController) { + this.questController = questController; + } + + @Override //Used by java GC + public boolean equals(Object o) { + if (!(o instanceof QPlayer)) return false; + QPlayer qPlayer = (QPlayer) o; + return this.uuid == qPlayer.getPlayerUUID(); + } + + @Override //Used by java GC + public int hashCode() { + return uuid.hashCode() * 73; //uuid hash * prime number + } +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/player/QPlayerManager.java b/common/src/main/java/com/leonardobishop/quests/common/player/QPlayerManager.java new file mode 100644 index 00000000..28a46ae1 --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/player/QPlayerManager.java @@ -0,0 +1,158 @@ +package com.leonardobishop.quests.common.player; + +import com.leonardobishop.quests.common.logger.QuestsLogger; +import com.leonardobishop.quests.common.storage.StorageProvider; +import com.leonardobishop.quests.common.plugin.Quests; +import com.leonardobishop.quests.common.questcontroller.QuestController; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; + +import java.util.Collection; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class QPlayerManager { + + private final Map qPlayers = new ConcurrentHashMap<>(); + private final Quests plugin; + private final StorageProvider storageProvider; + private QuestController activeQuestController; + + public QPlayerManager(Quests plugin, StorageProvider storageProvider, QuestController questController) { + this.plugin = plugin; + this.storageProvider = storageProvider; + this.activeQuestController = questController; + } + + /** + * Gets the QPlayer from a given UUID. + * + * @param uuid the uuid + * @return {@link QPlayer} if they are loaded + */ + public QPlayer getPlayer(UUID uuid) { + QPlayer qPlayer = qPlayers.get(uuid); + if (qPlayer == null) { + plugin.getQuestsLogger().debug("QPlayer of " + uuid + " is null, but was requested:"); + if (plugin.getQuestsLogger().getServerLoggingLevel() == QuestsLogger.LoggingLevel.DEBUG) { + Thread.dumpStack(); + } + } + return qPlayer; + } + + /** + * Unloads and schedules a save for the player. See {@link QPlayerManager#savePlayer(UUID)} + * + * @param uuid the uuid of the player + */ + public void removePlayer(UUID uuid) { + plugin.getQuestsLogger().debug("Unloading and saving player " + uuid + "."); + qPlayers.computeIfPresent(uuid, (mapUUID, qPlayer) -> { + savePlayer(uuid); + return null; + }); + } + + /** + * Schedules a save for the player with the {@link QuestProgressFile} associated by the {@link QPlayerManager}. + * The modified status of the progress file will be reset. + * + * @param uuid the uuid of the player + */ + public void savePlayer(UUID uuid) { + QPlayer qPlayer = getPlayer(uuid); + if (qPlayer == null) return; + savePlayer(uuid, qPlayer.getQuestProgressFile()); + } + + /** + * Schedules a save for the player with a specified {@link QuestProgressFile}. The modified status of the + * specified progress file will be reset. + * + * @param uuid the uuid of the player + * @param originalProgressFile the quest progress file to associate with and save + */ + public void savePlayer(UUID uuid, QuestProgressFile originalProgressFile) { + QuestProgressFile clonedProgressFile = new QuestProgressFile(originalProgressFile); + originalProgressFile.resetModified(); + plugin.getScheduler().doAsync(() -> save(uuid, clonedProgressFile)); + } + + /** + * Immediately saves the player with the {@link QuestProgressFile} associated by the {@link QPlayerManager}, + * on the same thread. The modified status of the specified progress file is not changed. + * + * @param uuid the uuid of the player + */ + public void savePlayerSync(UUID uuid) { + QPlayer qPlayer = getPlayer(uuid); + if (qPlayer == null) return; + savePlayerSync(uuid, qPlayer.getQuestProgressFile()); + } + + /** + * Immediately saves the player with a specified {@link QuestProgressFile}, on the same thread. The modified status + * of the specified progress file is not changed. + * + * @param uuid the uuid of the player + * @param questProgressFile the quest progress file to associate with and save + */ + public void savePlayerSync(UUID uuid, QuestProgressFile questProgressFile) { + save(uuid, questProgressFile); + } + + private void save(UUID uuid, QuestProgressFile questProgressFile) { + plugin.getQuestsLogger().debug("Saving player " + uuid + "."); + storageProvider.saveProgressFile(uuid, questProgressFile); + } + + /** + * Unloads the player without saving to disk. + * + * @param uuid the uuid of the player + */ + public void dropPlayer(UUID uuid) { + plugin.getQuestsLogger().debug("Dropping player " + uuid + "."); + qPlayers.remove(uuid); + } + + public Collection getQPlayers() { + return qPlayers.values(); + } + + /** + * Load the player if they exist, otherwise create a new {@link QuestProgressFile}. + * This will have no effect if player is already loaded. Can be invoked asynchronously. + * + * @param uuid the uuid of the player + */ + public void loadPlayer(UUID uuid) { + plugin.getQuestsLogger().debug("Loading player " + uuid + "."); + qPlayers.computeIfAbsent(uuid, s -> { + QuestProgressFile questProgressFile = storageProvider.loadProgressFile(uuid); + if (questProgressFile == null) return null; + return new QPlayer(plugin, uuid, new QPlayerPreferences(null), questProgressFile, activeQuestController); + }); + } + + /** + * Gets the current storage provider which loads and saves players. + * + * @return {@link StorageProvider} + */ + public StorageProvider getStorageProvider() { + return storageProvider; + } + + public QuestController getActiveQuestController() { + return activeQuestController; + } + + public void setActiveQuestController(QuestController activeQuestController) { + this.activeQuestController = activeQuestController; + for (QPlayer qPlayer : qPlayers.values()) { + qPlayer.setQuestController(activeQuestController); + } + } +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/player/QPlayerPreferences.java b/common/src/main/java/com/leonardobishop/quests/common/player/QPlayerPreferences.java new file mode 100644 index 00000000..5278ae09 --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/player/QPlayerPreferences.java @@ -0,0 +1,18 @@ +package com.leonardobishop.quests.common.player; + +public class QPlayerPreferences { + + private String trackedQuestId; + + public QPlayerPreferences(String trackedQuestId) { + this.trackedQuestId = trackedQuestId; + } + + public String getTrackedQuestId() { + return trackedQuestId; + } + + public void setTrackedQuestId(String trackedQuestId) { + this.trackedQuestId = trackedQuestId; + } +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/player/questprogressfile/QuestProgress.java b/common/src/main/java/com/leonardobishop/quests/common/player/questprogressfile/QuestProgress.java new file mode 100644 index 00000000..d0e0627d --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/player/questprogressfile/QuestProgress.java @@ -0,0 +1,143 @@ +package com.leonardobishop.quests.common.player.questprogressfile; + +import com.leonardobishop.quests.common.plugin.Quests; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class QuestProgress { + + private final Quests plugin; + + private final Map taskProgress = new HashMap<>(); + private final String questid; + private final UUID player; + + private boolean started; + private boolean completed; + private boolean completedBefore; + private long completionDate; + private boolean modified; + + public QuestProgress(Quests plugin, String questid, boolean completed, boolean completedBefore, long completionDate, UUID player, boolean started) { + this.plugin = plugin; + this.questid = questid; + this.completed = completed; + this.completedBefore = completedBefore; + this.completionDate = completionDate; + this.player = player; + this.started = started; + } + + public QuestProgress(Quests plugin, String questid, boolean completed, boolean completedBefore, long completionDate, UUID player, boolean started, boolean modified) { + this(plugin, questid, completed, completedBefore, completionDate, player, started); + this.modified = modified; + } + + public QuestProgress(QuestProgress questProgress) { + this.plugin = questProgress.plugin; + for (Map.Entry progressEntry : questProgress.taskProgress.entrySet()) { + taskProgress.put(progressEntry.getKey(), new TaskProgress(progressEntry.getValue())); + } + this.questid = questProgress.questid; + this.player = questProgress.player; + this.started = questProgress.started; + this.completed = questProgress.completed; + this.completedBefore = questProgress.completedBefore; + this.completionDate = questProgress.completionDate; + this.modified = questProgress.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 getTaskProgress() { + return taskProgress.values(); + } + + public Map getTaskProgressMap() { + return taskProgress; + } + + 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(this, taskid, null, player, false, false); + this.addTaskProgress(taskProgress); + } + + public boolean isModified() { + if (modified) return true; + else { + for (TaskProgress progress : this.taskProgress.values()) { + if (progress.isModified()) return true; + } + return false; + } + } + + public void queueForCompletionTest() { + plugin.getQuestCompleter().queueSingular(this); + } + + public void resetModified() { + this.modified = false; + for (TaskProgress progress : this.taskProgress.values()) { + progress.resetModified(); + } + } +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/player/questprogressfile/QuestProgressFile.java b/common/src/main/java/com/leonardobishop/quests/common/player/questprogressfile/QuestProgressFile.java new file mode 100644 index 00000000..a0c51d9c --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/player/questprogressfile/QuestProgressFile.java @@ -0,0 +1,253 @@ +package com.leonardobishop.quests.common.player.questprogressfile; + +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.plugin.Quests; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * Represents underlying quest progress for a player. + */ +public class QuestProgressFile { + + private final Map questProgress = new HashMap<>(); + private final UUID playerUUID; + private final Quests plugin; + + public QuestProgressFile(UUID playerUUID, Quests plugin) { + this.playerUUID = playerUUID; + this.plugin = plugin; + } + + public QuestProgressFile(QuestProgressFile questProgressFile) { + for (Map.Entry progressEntry : questProgressFile.questProgress.entrySet()) { + questProgress.put(progressEntry.getKey(), new QuestProgress(progressEntry.getValue())); + } + this.playerUUID = questProgressFile.playerUUID; + this.plugin = questProgressFile.plugin; + } + + public void addQuestProgress(QuestProgress questProgress) { + //TODO don't do here +// if (Options.VERIFY_QUEST_EXISTS_ON_LOAD.getBooleanValue(true) && plugin.getQuestManager().getQuestById(questProgress.getQuestId()) == null) { +// return; +// } + this.questProgress.put(questProgress.getQuestId(), questProgress); + } + + /** + * Gets all started quests. + * Note: if quest autostart is enabled then this may produce unexpected results as quests are + * not "started" by the player if autostart is true. Consider {@link QPlayer#hasStartedQuest(Quest)} instead. + * + * @return list of started quests + */ + public List getStartedQuests() { + List startedQuests = new ArrayList<>(); + for (QuestProgress questProgress : questProgress.values()) { + if (questProgress.isStarted()) { + startedQuests.add(plugin.getQuestManager().getQuestById(questProgress.getQuestId())); + } + } + return startedQuests; + } + + /** + * Returns all {@link Quest} a player has encountered + * (not to be confused with a collection of quest progress) + * + * @return {@code List} all quests + */ + public List getAllQuestsFromProgress(QuestsProgressFilter filter) { + List questsProgress = new ArrayList<>(); + for (QuestProgress qProgress : questProgress.values()) { + boolean condition = false; + if (filter == QuestsProgressFilter.STARTED) { + condition = qProgress.isStarted(); + } else if (filter == QuestsProgressFilter.COMPLETED_BEFORE) { + condition = qProgress.isCompletedBefore(); + } else if (filter == QuestsProgressFilter.COMPLETED) { + condition = qProgress.isCompleted(); + } else if (filter == QuestsProgressFilter.ALL) { + condition = true; + } + if (condition) { + Quest quest = plugin.getQuestManager().getQuestById(qProgress.getQuestId()); + if (quest != null) { + questsProgress.add(quest); + } + } + } + return questsProgress; + } + + public enum QuestsProgressFilter { + ALL("all"), + COMPLETED("completed"), + COMPLETED_BEFORE("completedBefore"), + STARTED("started"); + + private String legacy; + + QuestsProgressFilter(String legacy) { + this.legacy = legacy; + } + + public static QuestsProgressFilter fromLegacy(String filter) { + for (QuestsProgressFilter filterEnum : QuestsProgressFilter.values()) { + if (filterEnum.getLegacy().equals(filter)) return filterEnum; + } + return QuestsProgressFilter.ALL; + } + + public String getLegacy() { + return legacy; + } + } + + /** + * Gets all the quest progress that it has ever encountered. + * + * @return {@code Collection} all quest progresses + */ + public Collection getAllQuestProgress() { + return questProgress.values(); + } + + /** + * Checks whether or not the player has {@link QuestProgress} for a specified quest + * + * @param quest the quest to check for + * @return true if they have quest progress + */ + public boolean hasQuestProgress(Quest quest) { + return questProgress.containsKey(quest.getId()); + } + + /** + * Gets the remaining cooldown before being able to start a specific quest. + * + * @param quest the quest to test for + * @return 0 if no cooldown remaining or the cooldown is disabled, otherwise the cooldown in milliseconds + */ + 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; + } + + /** + * Tests whether or not the player meets the requirements to start a specific quest. + * + * @param quest the quest to test for + * @return true if they can start the quest + */ + //TODO possibly move this + public boolean hasMetRequirements(Quest quest) { + for (String id : quest.getRequirements()) { + Quest q = plugin.getQuestManager().getQuestById(id); + if (q == null) { + continue; + } + if (hasQuestProgress(q) && !getQuestProgress(q).isCompletedBefore()) { + return false; + } else if (!hasQuestProgress(q)) { + return false; + } + } + return true; + } + + /** + * Get the {@link UUID} of the player this QuestProgressFile represents + * + * @return UUID + */ + public UUID getPlayerUUID() { + return playerUUID; + } + + /** + * Get the {@link QuestProgress} for a specified {@link Quest}, and generates a new one if it does not exist + * + * @param quest the quest to get progress for + * @return {@link QuestProgress} or null if the quest does not exist + */ + public QuestProgress getQuestProgress(Quest quest) { + if (questProgress.containsKey(quest.getId())) { + return questProgress.get(quest.getId()); + } + generateBlankQuestProgress(quest); + return getQuestProgress(quest); + } + + /** + * Generate a new blank {@link QuestProgress} for a specified {@code quest}. + * Has no effect if there is already an existing {@link QuestProgress} for {@code quest}. + * + * @param quest the quest to generate progress for + */ + public void generateBlankQuestProgress(Quest quest) { + QuestProgress questProgress = new QuestProgress(plugin, quest.getId(), false, false, 0, playerUUID, false, false); + for (Task task : quest.getTasks()) { + TaskProgress taskProgress = new TaskProgress(questProgress, task.getId(), null, playerUUID, false, false); + questProgress.addTaskProgress(taskProgress); + } + + addQuestProgress(questProgress); + } + + public void clear() { + questProgress.clear(); + } + + /** + * Removes any references to quests or tasks which are no longer defined in the config. + */ + @Deprecated + public void clean() { + plugin.getQuestsLogger().debug("Cleaning file " + playerUUID + "."); + if (!plugin.getTaskTypeManager().areRegistrationsAccepted()) { + ArrayList invalidQuests = new ArrayList<>(); + for (String questId : this.questProgress.keySet()) { + Quest q; + if ((q = plugin.getQuestManager().getQuestById(questId)) == null) { + invalidQuests.add(questId); + } else { + ArrayList invalidTasks = new ArrayList<>(); + for (String taskId : this.questProgress.get(questId).getTaskProgressMap().keySet()) { + if (q.getTaskById(taskId) == null) { + invalidTasks.add(taskId); + } + } + for (String taskId : invalidTasks) { + this.questProgress.get(questId).getTaskProgressMap().remove(taskId); + } + } + } + for (String questId : invalidQuests) { + this.questProgress.remove(questId); + } + } + } + + public void resetModified() { + for (QuestProgress questProgress : questProgress.values()) { + questProgress.resetModified(); + } + } + +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/player/questprogressfile/TaskProgress.java b/common/src/main/java/com/leonardobishop/quests/common/player/questprogressfile/TaskProgress.java new file mode 100644 index 00000000..cb7f3fec --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/player/questprogressfile/TaskProgress.java @@ -0,0 +1,73 @@ +package com.leonardobishop.quests.common.player.questprogressfile; + +import java.util.UUID; + +public class TaskProgress { + + private final String taskid; + private final UUID player; + + private QuestProgress linkedQuestProgress; + private boolean modified; + private Object progress; + private boolean completed; + + public TaskProgress(QuestProgress linkedQuestProgress, String taskid, Object progress, UUID player, boolean completed) { + this.linkedQuestProgress = linkedQuestProgress; + this.taskid = taskid; + this.progress = progress; + this.player = player; + this.completed = completed; + } + + public TaskProgress(QuestProgress linkedQuestProgress, String taskid, Object progress, UUID player, boolean completed, boolean modified) { + this(linkedQuestProgress, taskid, progress, player, completed); + this.modified = modified; + } + + public TaskProgress(TaskProgress taskProgress) { + this.taskid = taskProgress.taskid; + this.player = taskProgress.player; + this.modified = taskProgress.modified; + this.progress = taskProgress.progress; + this.completed = taskProgress.completed; + } + + public String getTaskId() { + return taskid; + } + + public Object getProgress() { + return progress; + } + + public void setProgress(Object progress) { + this.progress = progress; + this.modified = true; + } + + public UUID getPlayer() { + return player; + } + + public boolean isCompleted() { + return completed; + } + + public void setCompleted(boolean complete) { + this.completed = complete; + this.modified = true; + + if (complete) { + linkedQuestProgress.queueForCompletionTest(); + } + } + + public boolean isModified() { + return modified; + } + + public void resetModified() { + this.modified = false; + } +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/plugin/Quests.java b/common/src/main/java/com/leonardobishop/quests/common/plugin/Quests.java new file mode 100644 index 00000000..f6eb67c5 --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/plugin/Quests.java @@ -0,0 +1,38 @@ +package com.leonardobishop.quests.common.plugin; + +import com.leonardobishop.quests.common.questcontroller.QuestController; +import com.leonardobishop.quests.common.logger.QuestsLogger; +import com.leonardobishop.quests.common.player.QPlayerManager; +import com.leonardobishop.quests.common.quest.QuestCompleter; +import com.leonardobishop.quests.common.quest.QuestManager; +import com.leonardobishop.quests.common.scheduler.ServerScheduler; +import com.leonardobishop.quests.common.storage.StorageProvider; +import com.leonardobishop.quests.common.tasktype.TaskTypeManager; +import com.leonardobishop.quests.common.updater.Updater; +import com.leonardobishop.quests.common.config.QuestsConfig; + +public interface Quests { + + QuestsLogger getQuestsLogger(); + + QuestManager getQuestManager(); + + QPlayerManager getPlayerManager(); + + QuestController getQuestController(); + + TaskTypeManager getTaskTypeManager(); + + QuestCompleter getQuestCompleter(); + + QuestsConfig getQuestsConfig(); + + Updater getUpdater(); + + ServerScheduler getScheduler(); + + StorageProvider getStorageProvider(); + + void reloadQuests(); + +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/quest/Category.java b/common/src/main/java/com/leonardobishop/quests/common/quest/Category.java new file mode 100644 index 00000000..7bd8f10d --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/quest/Category.java @@ -0,0 +1,33 @@ +package com.leonardobishop.quests.common.quest; + +import java.util.ArrayList; +import java.util.List; + +public class Category { + + private final String id; + private final boolean permissionRequired; + private final List registeredQuestIds = new ArrayList<>(); + + public Category(String id, boolean permissionRequired) { + this.id = id; + this.permissionRequired = permissionRequired; + } + + public String getId() { + return id; + } + + public boolean isPermissionRequired() { + return permissionRequired; + } + + public void registerQuestId(String questid) { + registeredQuestIds.add(questid); + } + + public List getRegisteredQuestIds() { + return registeredQuestIds; + } + +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/quest/Quest.java b/common/src/main/java/com/leonardobishop/quests/common/quest/Quest.java new file mode 100644 index 00000000..510e88d9 --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/quest/Quest.java @@ -0,0 +1,120 @@ +package com.leonardobishop.quests.common.quest; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Quest implements Comparable { + + private Map tasks = new HashMap<>(); + private final String id; + private final List rewards; + private final List requirements; + private final List rewardString; + private final List startString; + private final boolean repeatable; + private final boolean cooldownEnabled; + private final int cooldown; + private final int sortOrder; + private final boolean permissionRequired; + private final Map placeholders; + private String categoryid; + + + public Quest(String id, List rewards, List requirements, boolean repeatable, boolean cooldownEnabled, int cooldown, boolean permissionRequired, List rewardString, List startString, Map placeholders, String categoryid, int sortOrder) { + this(id, rewards, requirements, repeatable, cooldownEnabled, cooldown, permissionRequired, rewardString, startString, placeholders, sortOrder); + this.categoryid = categoryid; + } + + public Quest(String id, List rewards, List requirements, boolean repeatable, boolean cooldownEnabled, int cooldown, boolean permissionRequired, List rewardString, List startString, Map placeholders, int sortOrder) { + this.id = id; + this.rewards = rewards; + this.requirements = requirements; + this.repeatable = repeatable; + this.cooldownEnabled = cooldownEnabled; + this.cooldown = cooldown; + this.permissionRequired = permissionRequired; + this.rewardString = rewardString; + this.startString = startString; + this.placeholders = placeholders; + this.sortOrder = sortOrder; + } + + public void registerTask(Task task) { + tasks.put(task.getId(), task); + } + + public Collection getTasks() { + return tasks.values(); + } + + public Task getTaskById(String id) { + return tasks.get(id); + } + + public List getTasksOfType(String type) { + List tasks = new ArrayList<>(); + for (Task task : getTasks()) { + if (task.getType().equals(type)) { + tasks.add(task); + } + } + return tasks; + } + + + public boolean isPermissionRequired() { + return permissionRequired; + } + + public List getRewardString() { + return rewardString; + } + + public List getStartString() { + return startString; + } + + public String getId() { + return id; + } + + public List getRewards() { + return rewards; + } + + public List getRequirements() { + return requirements; + } + + public boolean isRepeatable() { + return repeatable; + } + + public boolean isCooldownEnabled() { + return cooldownEnabled; + } + + public int getCooldown() { + return cooldown; + } + + public String getCategoryId() { + return categoryid; + } + + public Map getPlaceholders() { + return placeholders; + } + + public int getSortOrder() { + return sortOrder; + } + + @Override + public int compareTo(Quest quest) { + return (sortOrder - quest.sortOrder); + } +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/quest/QuestCompleter.java b/common/src/main/java/com/leonardobishop/quests/common/quest/QuestCompleter.java new file mode 100644 index 00000000..db9cd36c --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/quest/QuestCompleter.java @@ -0,0 +1,11 @@ +package com.leonardobishop.quests.common.quest; + +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; + +public interface QuestCompleter { + + void queueSingular(QuestProgress questProgress); + void queueFullCheck(QuestProgressFile questProgressFile); + +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/quest/QuestManager.java b/common/src/main/java/com/leonardobishop/quests/common/quest/QuestManager.java new file mode 100644 index 00000000..ebace123 --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/quest/QuestManager.java @@ -0,0 +1,49 @@ +package com.leonardobishop.quests.common.quest; + +import com.leonardobishop.quests.common.plugin.Quests; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class QuestManager { + + private final Quests plugin; + + public QuestManager(Quests plugin) { + this.plugin = plugin; + } + + private Map quests = new LinkedHashMap<>(); + private List categories = new ArrayList<>(); + + public void registerQuest(Quest quest) { + quests.put(quest.getId(), quest); + } + + public Quest getQuestById(String id) { + return quests.get(id); + } + + public Map getQuests() { + return quests; + } + + public void registerCategory(Category category) { categories.add(category); } + + public List getCategories() { + return categories; + } + + public Category getCategoryById(String id) { + for (Category category : categories) { + if (category.getId().equals(id)) return category; + } + return null; + } + + public Quests getPlugin() { + return this.plugin; + } +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/quest/Task.java b/common/src/main/java/com/leonardobishop/quests/common/quest/Task.java new file mode 100644 index 00000000..8189e06e --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/quest/Task.java @@ -0,0 +1,41 @@ +package com.leonardobishop.quests.common.quest; + +import java.util.HashMap; +import java.util.Map; + +public class Task { + + private final Map configValues = new HashMap<>(); + private final String id; + private final 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); //??? this will return null without the need of `OrDefault(key, null)` + } + + public Object getConfigValue(String key, Object def) { + return configValues.getOrDefault(key, def); + } + + public Map getConfigValues() { + return configValues; + } + + public void addConfigValue(String key, Object value) { + configValues.put(key, value); + } + +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/questcontroller/QuestController.java b/common/src/main/java/com/leonardobishop/quests/common/questcontroller/QuestController.java new file mode 100644 index 00000000..0f5b6e8f --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/questcontroller/QuestController.java @@ -0,0 +1,23 @@ +package com.leonardobishop.quests.common.questcontroller; + +import com.leonardobishop.quests.common.enums.QuestStartResult; +import com.leonardobishop.quests.common.player.QPlayer; +import com.leonardobishop.quests.common.quest.Quest; + +public interface QuestController { + + String getName(); + + QuestStartResult startQuestForPlayer(QPlayer qPlayer, Quest quest); + + QuestStartResult canPlayerStartQuest(QPlayer qPlayer, Quest quest); + + boolean completeQuestForPlayer(QPlayer qPlayer, Quest quest); + + boolean hasPlayerStartedQuest(QPlayer qPlayer, Quest quest); + + boolean cancelQuestForPlayer(QPlayer qPlayer, Quest quest); + + void trackQuestForPlayer(QPlayer qPlayer, Quest quest); + +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/scheduler/ServerScheduler.java b/common/src/main/java/com/leonardobishop/quests/common/scheduler/ServerScheduler.java new file mode 100644 index 00000000..0de30f51 --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/scheduler/ServerScheduler.java @@ -0,0 +1,8 @@ +package com.leonardobishop.quests.common.scheduler; + +public interface ServerScheduler { + + void doSync(Runnable runnable); + void doAsync(Runnable runnable); + +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/storage/StorageProvider.java b/common/src/main/java/com/leonardobishop/quests/common/storage/StorageProvider.java new file mode 100644 index 00000000..4ea885be --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/storage/StorageProvider.java @@ -0,0 +1,17 @@ +package com.leonardobishop.quests.common.storage; + +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; + +import java.util.UUID; + +public interface StorageProvider { + + void init(); + + void shutdown(); + + QuestProgressFile loadProgressFile(UUID uuid); + + void saveProgressFile(UUID uuid, QuestProgressFile questProgressFile); + +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/tasktype/TaskType.java b/common/src/main/java/com/leonardobishop/quests/common/tasktype/TaskType.java new file mode 100644 index 00000000..79c7a0b0 --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/tasktype/TaskType.java @@ -0,0 +1,108 @@ +package com.leonardobishop.quests.common.tasktype; + +import com.leonardobishop.quests.common.config.ConfigProblem; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +/** + * A task type which can be used within Quests. A {@link Quest} + * will be registered to this if it contains at least 1 task + * which is of this type. This is so you do not have to + * iterate through every single quest. + */ +public abstract class TaskType { + + private final List quests = new ArrayList<>(); + private final String type; + private String author; + private String description; + + /** + * @param type the name of the task type, should not contain spaces + * @param author the name of the person (or people) who wrote it + * @param description a short, simple description of the task type + */ + public TaskType(String type, String author, String description) { + this.type = type; + this.author = author; + this.description = description; + } + + /** + * @param type the name of the task type, should not contain spaces + */ + public TaskType(String type) { + this.type = type; + } + + /** + * Registers a {@link Quest} to this task type. This is usually done when + * all the quests are initially loaded. + * + * @param quest the {@link Quest} to register. + */ + public final void registerQuest(Quest quest) { + if (!quests.contains(quest)) { + quests.add(quest); + } + } + + /** + * Clears the list which contains the registered quests. + */ + public final void unregisterAll() { + quests.clear(); + } + + /** + * @return {@link List} of type {@link Quest} of all registered quests. + */ + public final List getRegisteredQuests() { + return quests; + } + + public final String getType() { + return type; + } + + public String getAuthor() { + return author; + } + + public String getDescription() { + return description; + } + + /** + * Called when Quests has finished registering all quests to the task type + * May be called several times if an operator uses /quests admin reload + */ + public void onReady() { + // not implemented here + } + + /** + * Called when a player starts a quest containing a task of this type + */ + public void onStart(Quest quest, Task task, UUID playerUUID) { + // not implemented here + } + + public void onDisable() { + // not implemented here + } + + /** + * Called when Quests reloads the configuration - used to detect errors in the configuration of your task type + */ + public List validateConfig(String root, HashMap config) { + // not implemented here + return Collections.emptyList(); + } +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/tasktype/TaskTypeManager.java b/common/src/main/java/com/leonardobishop/quests/common/tasktype/TaskTypeManager.java new file mode 100644 index 00000000..dfa5124e --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/tasktype/TaskTypeManager.java @@ -0,0 +1,67 @@ +package com.leonardobishop.quests.common.tasktype; + +import com.leonardobishop.quests.common.plugin.Quests; +import com.leonardobishop.quests.common.quest.Quest; +import com.leonardobishop.quests.common.quest.Task; + +import java.util.ArrayList; + +public abstract class TaskTypeManager { + + private final Quests plugin; + private boolean allowRegistrations; + + public TaskTypeManager(Quests plugin) { + this.plugin = plugin; + allowRegistrations = true; + } + + public void closeRegistrations() { + allowRegistrations = false; + } + + public boolean areRegistrationsAccepted() { + return allowRegistrations; + } + + private ArrayList taskTypes = new ArrayList<>(); + + public ArrayList getTaskTypes() { + return taskTypes; + } + + public void resetTaskTypes() { + for (TaskType taskType : taskTypes) { + taskType.getRegisteredQuests().clear(); + } + } + + public void registerTaskType(TaskType taskType) { + if (!allowRegistrations) { + throw new IllegalStateException("No longer accepting new task types (must be done before quests are loaded)"); + } + plugin.getQuestsLogger().info("Task type " + taskType.getType() + " has been registered."); + taskTypes.add(taskType); + } + + public void registerQuestTasksWithTaskTypes(Quest quest) { + if (allowRegistrations) { + throw new IllegalStateException("Still accepting new task types (type registrations must be closed before registering quests)"); + } + for (Task task : quest.getTasks()) { + TaskType t; + if ((t = getTaskType(task.getType())) != null) { + t.registerQuest(quest); + } + } + } + + public TaskType getTaskType(String string) { + for (TaskType taskType : taskTypes) { + if (taskType.getType().equalsIgnoreCase(string)) { + return taskType; + } + } + return null; + } +} diff --git a/common/src/main/java/com/leonardobishop/quests/common/updater/Updater.java b/common/src/main/java/com/leonardobishop/quests/common/updater/Updater.java new file mode 100644 index 00000000..70660735 --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/updater/Updater.java @@ -0,0 +1,78 @@ +package com.leonardobishop.quests.common.updater; + +import com.leonardobishop.quests.common.plugin.Quests; + +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; + +public class Updater { + + private static final int PROJECT_ID = 23696; + private final String installedVersion; + private final boolean enabled; + private final Quests plugin; + + private String returnedVersion; + private URL api; + private boolean updateReady; + private long lastCheck; + + public Updater(Quests plugin, String installedVersion, boolean enabled) { + this.plugin = plugin; + this.installedVersion = installedVersion; + this.enabled = enabled; + try { + this.api = new URL(getApiUrl()); + } catch (MalformedURLException ignored) { } + } + + public String getUpdateLink() { + return "https://www.spigotmc.org/resources/" + PROJECT_ID; + } + + public String getApiUrl() { + return "https://api.spigotmc.org/legacy/update.php?resource=" + PROJECT_ID; + } + + public String getInstalledVersion() { + return installedVersion; + } + + public String getReturnedVersion() { + return returnedVersion; + } + + public void check() { + if (!enabled) { + return; + } + // stop users from spamming the command and making needless requests + if (lastCheck != 0 && TimeUnit.MINUTES.convert(System.currentTimeMillis() - lastCheck, TimeUnit.MILLISECONDS) < 10) { + return; + } + try { + lastCheck = System.currentTimeMillis(); + URLConnection con = api.openConnection(); + returnedVersion = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine(); + if (!returnedVersion.equals(installedVersion)) { + plugin.getQuestsLogger().info("A new version " + returnedVersion + " was found on Spigot (your version: " + installedVersion + "). Please update me! <3 - Link: " + getUpdateLink()); + updateReady = true; + } else { + updateReady = false; + } + } catch (IOException e) { + plugin.getQuestsLogger().warning("Failed to check for updates. You can check manually at " + getUpdateLink()); + // probably offline + } + } + + public boolean isUpdateReady() { + return updateReady; + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/leonardobishop/quests/common/util/Format.java b/common/src/main/java/com/leonardobishop/quests/common/util/Format.java new file mode 100644 index 00000000..410462ee --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/util/Format.java @@ -0,0 +1,21 @@ +package com.leonardobishop.quests.common.util; + +public class Format { + + //TODO reimplement customisation + public static String formatTime(long sec) { + long hours = sec / 3600; + long minutes = (sec % 3600) / 60; + long seconds = ((sec % 3600) % 60) % 60; + +// return Messages.TIME_FORMAT.getMessage() +// .replace("{hours}", String.format("%02d", hours)) +// .replace("{minutes}", String.format("%02d", minutes)) +// .replace("{seconds}", String.format("%02d", seconds)); + return "{houes}h {minutes}m {seconds}s" + .replace("{hours}", String.format("%02d", hours)) + .replace("{minutes}", String.format("%02d", minutes)) + .replace("{seconds}", String.format("%02d", seconds)); + } + +} -- cgit v1.2.3-70-g09d2