diff options
| author | Krakenied <krakenied1@gmail.com> | 2025-05-13 19:30:31 +0200 |
|---|---|---|
| committer | Krakenied <46192742+Krakenied@users.noreply.github.com> | 2025-05-13 20:34:15 +0200 |
| commit | a4857f7a4e457ff4c7c7e8da8410129efd4aabcf (patch) | |
| tree | fec0c9c512346eea9ea6c7b0a05ce42ecb11f04a | |
| parent | 258d425ae0147e2b2a4e8d658d4aaba159005f8d (diff) | |
API cleanup & ensure compatibility
36 files changed, 824 insertions, 643 deletions
diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 01272846..2b4c719f 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -94,7 +94,7 @@ dependencies { // ItemsAdder compileOnlyPlugin("com.github.LoneDev6:API-ItemsAdder:3.5.0b") // JetBrains Annotations - compileOnlyPlugin("org.jetbrains:annotations:24.1.0") + compileOnlyPlugin("org.jetbrains:annotations:26.0.2") // MMOItems compileOnlyPlugin("net.Indyuce:MMOItems-API:6.9.2-SNAPSHOT") // MythicLib diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java index 88ccfb2a..74f31be1 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java @@ -280,7 +280,7 @@ public class BukkitQuestsPlugin extends JavaPlugin implements Quests { this.logHistory = new LogHistory(true); this.generateConfigurations(); this.questsConfig = new BukkitQuestsConfig(new File(super.getDataFolder() + File.separator + "config.yml")); - this.questManager = new QuestManager(this); + this.questManager = new QuestManager(); this.serverScheduler = FoliaServerScheduler.FOLIA ? new FoliaServerScheduler(this) : new BukkitServerSchedulerAdapter(this); questsLogger.info("Running server scheduler: " + serverScheduler.getServerSchedulerName()); diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/AdminDebugReportCommandHandler.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/AdminDebugReportCommandHandler.java index ae1e53fb..838ca946 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/AdminDebugReportCommandHandler.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/AdminDebugReportCommandHandler.java @@ -98,12 +98,12 @@ public class AdminDebugReportCommandHandler implements CommandHandler { lines.add(""); printList(lines, 0, "Task types available", plugin.getTaskTypeManager().getTaskTypes(), TaskType::getType); lines.add(""); - printList(lines, 0, "Quests", plugin.getQuestManager().getQuests().values(), Quest::getId); + printList(lines, 0, "Quests", plugin.getQuestManager().getQuestMap().values(), Quest::getId); lines.add(""); printList(lines, 0, "Categories", plugin.getQuestManager().getCategories(), Category::getId); lines.add(""); BukkitQuestCompleter completer = (BukkitQuestCompleter) plugin.getQuestCompleter(); - printList(lines, 0, "Completion queue", completer.getCompletionQueue(), questProgress -> questProgress.getPlayer().toString()); + printList(lines, 0, "Completion queue", completer.getCompletionQueue(), questProgress -> questProgress.getPlayerUUID().toString()); lines.add(""); printList(lines, 0, "Full check queue", completer.getFullCheckQueue(), questProgressFile -> questProgressFile.getPlayerUUID().toString()); lines.add(""); @@ -181,9 +181,9 @@ public class AdminDebugReportCommandHandler implements CommandHandler { lines.add("# Quests #"); lines.add("################################"); lines.add(""); - lines.add("Number of quests: " + plugin.getQuestManager().getQuests().size()); + lines.add("Number of quests: " + plugin.getQuestManager().getQuestMap().size()); lines.add(""); - for (Quest quest : plugin.getQuestManager().getQuests().values()) { + for (Quest quest : plugin.getQuestManager().getQuestMap().values()) { Map<String, Object> questValues = getFieldValues(quest.getClass(), quest, "tasks", "tasksByType"); try { Field tasksField = quest.getClass().getDeclaredField("tasks"); diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/AdminInfoCommandHandler.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/AdminInfoCommandHandler.java index 9392b7f2..72e39137 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/AdminInfoCommandHandler.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/AdminInfoCommandHandler.java @@ -25,16 +25,16 @@ public class AdminInfoCommandHandler implements CommandHandler { if (args.length == 2) { sender.sendMessage(ChatColor.GRAY + "Loaded quests:"); int i = 0; - for (Quest quest : plugin.getQuestManager().getQuests().values()) { + for (Quest quest : plugin.getQuestManager().getQuestMap().values()) { sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + quest.getId() + ChatColor.GRAY + " [" + quest.getTasks().size() + " tasks]"); i++; - if (i == 25 && plugin.getQuestManager().getQuests().size() > 25) { - sender.sendMessage(ChatColor.DARK_GRAY + " ... and " + (plugin.getQuestManager().getQuests().size() - 25) + " more ..."); + if (i == 25 && plugin.getQuestManager().getQuestMap().size() > 25) { + sender.sendMessage(ChatColor.DARK_GRAY + " ... and " + (plugin.getQuestManager().getQuestMap().size() - 25) + " more ..."); break; } } sender.sendMessage(ChatColor.GRAY + "Quest controller: " + ChatColor.RED + plugin.getQuestController().getName()); - sender.sendMessage(ChatColor.GRAY.toString() + plugin.getQuestManager().getQuests().size() + " registered."); + sender.sendMessage(ChatColor.GRAY.toString() + plugin.getQuestManager().getQuestMap().size() + " registered."); sender.sendMessage(ChatColor.DARK_GRAY + "View info using /q a info [quest]."); } else { Quest quest = plugin.getQuestManager().getQuestById(args[2]); diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/AdminModdataRandomCommandHandler.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/AdminModdataRandomCommandHandler.java index 81a5759a..b4b6b850 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/AdminModdataRandomCommandHandler.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/AdminModdataRandomCommandHandler.java @@ -33,7 +33,7 @@ public class AdminModdataRandomCommandHandler implements CommandHandler { List<Quest> validQuests = new ArrayList<>(); boolean fromCategory = args.length != 4; if (!fromCategory) { - for (Quest quest : plugin.getQuestManager().getQuests().values()) { + for (Quest quest : plugin.getQuestManager().getQuestMap().values()) { if (qPlayer.canStartQuest(quest) == QuestStartResult.QUEST_SUCCESS) { validQuests.add(quest); } diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/RandomCommandHandler.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/RandomCommandHandler.java index 34fd70c8..69b88707 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/RandomCommandHandler.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/RandomCommandHandler.java @@ -33,7 +33,7 @@ public class RandomCommandHandler implements CommandHandler { } List<Quest> validQuests = new ArrayList<>(); if (args.length == 1) { - for (Quest quest : plugin.getQuestManager().getQuests().values()) { + for (Quest quest : plugin.getQuestManager().getQuestMap().values()) { if (qPlayer.canStartQuest(quest) == QuestStartResult.QUEST_SUCCESS) { validQuests.add(quest); } diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/TabHelper.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/TabHelper.java index ff92c82f..6177b81b 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/TabHelper.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/command/TabHelper.java @@ -32,12 +32,12 @@ public class TabHelper { } public static List<String> tabCompleteQuests(String arg) { - List<String> options = new ArrayList<>(plugin.getQuestManager().getQuests().keySet()); + List<String> options = new ArrayList<>(plugin.getQuestManager().getQuestMap().keySet()); return matchTabComplete(arg, options); } public static List<String> tabCompleteQuestsOrWildcard(String arg) { - List<String> options = new ArrayList<>(plugin.getQuestManager().getQuests().keySet()); + List<String> options = new ArrayList<>(plugin.getQuestManager().getQuestMap().keySet()); options.add("*"); return matchTabComplete(arg, options); } diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/config/BukkitQuestsLoader.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/config/BukkitQuestsLoader.java index 7b005fa1..215d4b8b 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/config/BukkitQuestsLoader.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/config/BukkitQuestsLoader.java @@ -227,7 +227,7 @@ public class BukkitQuestsLoader implements QuestsLoader { configValues.put(key, config.get(taskRoot + "." + key)); } - Set<ConfigProblem> taskProblems = new HashSet<>(); + List<ConfigProblem> taskProblems = new ArrayList<>(); for (TaskType.ConfigValidator validator : t.getConfigValidators()) { validator.validateConfig(configValues, taskProblems); } @@ -426,7 +426,7 @@ public class BukkitQuestsLoader implements QuestsLoader { e.printStackTrace(); } - questsLogger.info(questManager.getQuests().size() + " quests have been registered."); + questsLogger.info(questManager.getQuestMap().size() + " quests have been registered."); // post-load checks for (Map.Entry<String, Quest> loadedQuest : pathToQuest.entrySet()) { diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/QuestsPlaceholders.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/QuestsPlaceholders.java index 1a533aab..39c53b6a 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/QuestsPlaceholders.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/QuestsPlaceholders.java @@ -82,7 +82,7 @@ public class QuestsPlaceholders extends PlaceholderExpansion implements Cacheabl switch (args[0].toLowerCase()) { case "all": case "a": - final List<Quest> listAll = new ArrayList<>(plugin.getQuestManager().getQuests().values()); + final List<Quest> listAll = new ArrayList<>(plugin.getQuestManager().getQuestMap().values()); result = (args.length == 1 ? String.valueOf(listAll.size()) : parseList((List<Quest>) listAll, args[1], split)); break; case "completed": diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/data/CommonPlaceholderType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/data/CommonPlaceholderType.java deleted file mode 100644 index 47361f51..00000000 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/papi/data/CommonPlaceholderType.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.leonardobishop.quests.bukkit.hook.papi.data; - -import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin; -import com.leonardobishop.quests.common.player.QPlayer; -import com.leonardobishop.quests.common.player.questprogressfile.filters.QuestProgressFilter; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; - -public enum CommonPlaceholderType { - ALL("all", "a") { - @Override - public int getCount(final @NotNull BukkitQuestsPlugin plugin, final @NotNull QPlayer player) { - return plugin.getQuestManager().getQuests().size(); - } - }, - COMPLETED("completed", "c") { - @Override - public int getCount(final @NotNull BukkitQuestsPlugin plugin, final @NotNull QPlayer player) { - return player.getQuestProgressFile().getAllQuestsFromProgressCount(QuestProgressFilter.COMPLETED); - } - }, - COMPLETED_BEFORE("completedbefore", "cb") { - @Override - public int getCount(final @NotNull BukkitQuestsPlugin plugin, final @NotNull QPlayer player) { - return player.getQuestProgressFile().getAllQuestsFromProgressCount(QuestProgressFilter.COMPLETED_BEFORE); - } - }, - STARTED("started", "s") { - @Override - public int getCount(final @NotNull BukkitQuestsPlugin plugin, final @NotNull QPlayer player) { - return player.getQuestProgressFile().getAllQuestsFromProgressCount(QuestProgressFilter.STARTED); - } - }, - CATEGORIES("categories") { - @Override - public int getCount(final @NotNull BukkitQuestsPlugin plugin, final @NotNull QPlayer player) { - return plugin.getQuestManager().getCategories().size(); - } - }; - - private final String[] names; - - CommonPlaceholderType(final @NotNull String @NotNull ... names) { - this.names = names; - } - - public abstract int getCount(final @NotNull BukkitQuestsPlugin plugin, final @NotNull QPlayer player); - - public @NotNull String @NotNull [] getNames() { - return this.names; - } - - private static final CommonPlaceholderType[] VALUES = CommonPlaceholderType.values(); - - private static final Map<String, CommonPlaceholderType> byName = new HashMap<>(CommonPlaceholderType.VALUES.length) {{ - for (final CommonPlaceholderType placeholderType : CommonPlaceholderType.VALUES) { - for (final String name : placeholderType.getNames()) { - this.put(name, placeholderType); - } - } - }}; - - public static @Nullable CommonPlaceholderType getByName(final @NotNull String name) { - return CommonPlaceholderType.byName.get(name); - } -} diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/listener/PlayerJoinListener.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/listener/PlayerJoinListener.java index 13f2566a..2bceaa21 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/listener/PlayerJoinListener.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/listener/PlayerJoinListener.java @@ -42,7 +42,7 @@ public class PlayerJoinListener implements Listener { // track first quest if (plugin.getConfig().getBoolean("options.allow-quest-track") && plugin.getConfig().getBoolean("options.quest-autotrack")) { - for (Quest quest : plugin.getQuestManager().getQuests().values()) { + for (Quest quest : plugin.getQuestManager().getQuestMap().values()) { if (qPlayer.hasStartedQuest(quest)) { qPlayer.trackQuest(quest); break; diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/MenuController.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/MenuController.java index 33f086b5..47d97adc 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/MenuController.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/menu/MenuController.java @@ -88,7 +88,7 @@ public class MenuController implements Listener { // // StartedQMenu startedQMenu = new StartedQMenu(plugin, qPlayer); // List<QuestSortWrapper> quests = new ArrayList<>(); -// for (Map.Entry<String, Quest> entry : plugin.getQuestManager().getQuests().entrySet()) { +// for (Map.Entry<String, Quest> entry : plugin.getQuestManager().getQuestMap().entrySet()) { // quests.add(new QuestSortWrapper(plugin, entry.getValue())); // } // startedQMenu.populate(quests); diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcompleter/BukkitQuestCompleter.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcompleter/BukkitQuestCompleter.java index 04e03f70..0f09c877 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcompleter/BukkitQuestCompleter.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcompleter/BukkitQuestCompleter.java @@ -78,7 +78,7 @@ public class BukkitQuestCompleter implements QuestCompleter, Runnable { QuestProgress questProgress = completionQueue.poll(); if (questProgress == null) return; - Player player = Bukkit.getPlayer(questProgress.getPlayer()); + Player player = Bukkit.getPlayer(questProgress.getPlayerUUID()); if (player != null && player.isOnline()) { QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId()); if (qPlayer == null) return; diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/DailyQuestController.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/DailyQuestController.java index c6e103bc..95be073a 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/DailyQuestController.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/DailyQuestController.java @@ -63,7 +63,7 @@ // random = new Random(refreshTime); // quests = new ArrayList<>(); // -// List<String> questIds = new ArrayList<>(plugin.getQuestManager().getQuests().keySet()); +// List<String> questIds = new ArrayList<>(plugin.getQuestManager().getQuestMap().keySet()); // for (int i = 0; i < 5; i++) { // int randInt = random.nextInt(questIds.size()); // quests.add(questIds.get(randInt)); diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java index 2a0972ab..6bd319cb 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java @@ -18,7 +18,9 @@ import com.leonardobishop.quests.bukkit.util.chat.Chat; import com.leonardobishop.quests.common.enums.QuestStartResult; import com.leonardobishop.quests.common.player.QPlayer; import com.leonardobishop.quests.common.player.questprogressfile.QuestProgress; +import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress; +import com.leonardobishop.quests.common.quest.Category; import com.leonardobishop.quests.common.quest.Quest; import com.leonardobishop.quests.common.quest.Task; import com.leonardobishop.quests.common.questcontroller.QuestController; @@ -49,7 +51,7 @@ public class NormalQuestController implements QuestController { this.config = (BukkitQuestsConfig) plugin.getQuestsConfig(); List<Quest> autoStartQuestCache = new ArrayList<>(); - for (Quest quest : plugin.getQuestManager().getQuests().values()) { + for (Quest quest : plugin.getQuestManager().getQuestMap().values()) { if (quest.isAutoStartEnabled()) autoStartQuestCache.add(quest); } this.autoStartQuestCache = autoStartQuestCache; @@ -112,7 +114,7 @@ public class NormalQuestController implements QuestController { QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); questProgress.setStarted(true); questProgress.setStartedDate(System.currentTimeMillis()); - for (TaskProgress taskProgress : questProgress.getTaskProgress()) { + for (TaskProgress taskProgress : questProgress.getTaskProgresses()) { taskProgress.setCompleted(false); taskProgress.setProgress(null); } @@ -156,60 +158,76 @@ public class NormalQuestController implements QuestController { } @Override - public QuestStartResult canPlayerStartQuest(QPlayer qPlayer, Quest quest) { - Player p = Bukkit.getPlayer(qPlayer.getPlayerUUID()); - QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); - if (!quest.isRepeatable() && questProgress.isCompletedBefore()) { - //if (playerUUID != null) { - // ??? - //} - return QuestStartResult.QUEST_ALREADY_COMPLETED; - } - long cooldown = qPlayer.getQuestProgressFile().getCooldownFor(quest); - if (cooldown > 0) { - return QuestStartResult.QUEST_COOLDOWN; + public @NotNull QuestStartResult canPlayerStartQuest(final @NotNull QPlayer qPlayer, final @NotNull Quest quest) { + final QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); + final QuestProgress questProgress = questProgressFile.getQuestProgressOrNull(quest); + + if (questProgress != null) { + if (!quest.isRepeatable() && questProgress.isCompleted()) { + // if (playerUUID != null) { + // ??? + // } + + return QuestStartResult.QUEST_ALREADY_COMPLETED; + } + + final long cooldown = questProgressFile.getCooldownFor(quest); + + if (cooldown > 0) { + return QuestStartResult.QUEST_COOLDOWN; + } } - if (!qPlayer.getQuestProgressFile().hasMetRequirements(quest)) { + + if (!questProgressFile.hasMetRequirements(quest)) { return QuestStartResult.QUEST_LOCKED; } - if (quest.isPermissionRequired()) { - if (p != null) { - if (!p.hasPermission("quests.quest." + quest.getId())) { - return QuestStartResult.QUEST_NO_PERMISSION; - } - } else { - return QuestStartResult.QUEST_NO_PERMISSION; - } + + final Player player = Bukkit.getPlayer(qPlayer.getPlayerUUID()); + final String questPermission = quest.getPermission(); + + if (questPermission != null && (player == null || !player.hasPermission(questPermission))) { + return QuestStartResult.QUEST_NO_PERMISSION; } - if (quest.getCategoryId() != null && plugin.getQuestManager().getCategoryById(quest.getCategoryId()) != null && plugin.getQuestManager() - .getCategoryById(quest.getCategoryId()).isPermissionRequired()) { - if (p != null) { - if (!p.hasPermission("quests.category." + quest.getCategoryId())) { + + final String categoryId = quest.getCategoryId(); + + if (categoryId != null) { + final Category category = this.plugin.getQuestManager().getCategoryById(categoryId); + + if (category != null) { + final String categoryPermission = category.getPermission(); + + if (categoryPermission != null && (player == null || !player.hasPermission(categoryPermission))) { return QuestStartResult.NO_PERMISSION_FOR_CATEGORY; } - } else { - return QuestStartResult.NO_PERMISSION_FOR_CATEGORY; } } - boolean autostart = this.config.getBoolean("options.quest-autostart"); - if (questProgress.isStarted() || quest.isAutoStartEnabled() || autostart) { + final boolean autostart = this.config.getBoolean("options.quest-autostart"); + + if (autostart) { return QuestStartResult.QUEST_ALREADY_STARTED; } if (quest.doesCountTowardsLimit()) { - Set<Quest> startedQuests = getStartedQuestsForPlayer(qPlayer); + final Set<Quest> startedQuests = this.getStartedQuestsForPlayer(qPlayer); int questLimitCount = 0; - for (Quest q : startedQuests) { - if (q.doesCountTowardsLimit()) { + + for (final Quest startedQuest : startedQuests) { + if (startedQuest.doesCountTowardsLimit()) { questLimitCount++; } } - if (questLimitCount >= config.getQuestLimit(p)) { + + if (questLimitCount >= this.config.getQuestLimit(player)) { return QuestStartResult.QUEST_LIMIT_REACHED; } } + if (questProgress != null && questProgress.isStarted() || quest.isAutoStartEnabled()) { + return QuestStartResult.QUEST_ALREADY_STARTED; + } + return QuestStartResult.QUEST_SUCCESS; } @@ -218,7 +236,7 @@ public class NormalQuestController implements QuestController { QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest); questProgress.setStarted(false); questProgress.setStartedDate(System.currentTimeMillis()); - for (TaskProgress taskProgress : questProgress.getTaskProgress()) { + for (TaskProgress taskProgress : questProgress.getTaskProgresses()) { taskProgress.setCompleted(false); taskProgress.setProgress(null); } @@ -275,7 +293,7 @@ public class NormalQuestController implements QuestController { private void resetQuest(QuestProgress questProgress) { questProgress.setStarted(false); questProgress.setStartedDate(System.currentTimeMillis()); - for (TaskProgress taskProgress : questProgress.getTaskProgress()) { + for (TaskProgress taskProgress : questProgress.getTaskProgresses()) { taskProgress.setCompleted(false); taskProgress.setProgress(null); } @@ -405,7 +423,7 @@ public class NormalQuestController implements QuestController { private Set<Quest> getStartedQuestsForPlayer(QPlayer qPlayer) { Set<Quest> startedQuests = new HashSet<>(); if (config.getBoolean("options.quest-autostart")) { - for (Quest quest : plugin.getQuestManager().getQuests().values()) { + for (Quest quest : plugin.getQuestManager().getQuestMap().values()) { QuestStartResult response = canPlayerStartQuest(qPlayer, quest); if (response == QuestStartResult.QUEST_SUCCESS || response == QuestStartResult.QUEST_ALREADY_STARTED) { startedQuests.add(quest); diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/ModernMySQLStorageProvider.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/ModernMySQLStorageProvider.java index 72cda628..a1d9187f 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/ModernMySQLStorageProvider.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/ModernMySQLStorageProvider.java @@ -372,7 +372,7 @@ public final class ModernMySQLStorageProvider implements StorageProvider { questStmt.setLong(12, questProgress.getCompletionDate()); questStmt.addBatch(); - for (final TaskProgress taskProgress : questProgress.getAllTaskProgress()) { + for (final TaskProgress taskProgress : questProgress.getTaskProgresses()) { final String taskId = taskProgress.getTaskId(); final Object progress = taskProgress.getProgress(); diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/ModernYAMLStorageProvider.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/ModernYAMLStorageProvider.java index 2b6b1cf9..c08477ae 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/ModernYAMLStorageProvider.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/ModernYAMLStorageProvider.java @@ -193,7 +193,7 @@ public final class ModernYAMLStorageProvider implements StorageProvider { data.set("quest-progress." + questId + ".completed-before", questProgress.isCompletedBefore()); data.set("quest-progress." + questId + ".completion-date", questProgress.getCompletionDate()); - for (final TaskProgress taskProgress : questProgress.getAllTaskProgress()) { + for (final TaskProgress taskProgress : questProgress.getTaskProgresses()) { final String taskId = taskProgress.getTaskId(); data.set("quest-progress." + questId + ".task-progress." + taskId + ".completed", taskProgress.isCompleted()); diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/MenuUtils.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/MenuUtils.java index c8b3b7cc..00a10ef0 100644 --- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/MenuUtils.java +++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/MenuUtils.java @@ -75,7 +75,7 @@ public class MenuUtils { plugin.getMenuController().openMenu(player, categoryQMenu); } else { List<Quest> quests = new ArrayList<>(); - for (Map.Entry<String, Quest> entry : plugin.getQuestManager().getQuests().entrySet()) { + for (Map.Entry<String, Quest> entry : plugin.getQuestManager().getQuestMap().entrySet()) { quests.add(entry.getValue()); } Collections.sort(quests); @@ -119,7 +119,7 @@ public class MenuUtils { } List<QuestSortWrapper> quests = new ArrayList<>(); - for (Map.Entry<String, Quest> entry : plugin.getQuestManager().getQuests().entrySet()) { + for (Map.Entry<String, Quest> entry : plugin.getQuestManager().getQuestMap().entrySet()) { quests.add(new QuestSortWrapper(plugin, entry.getValue())); } Collections.sort(quests); diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 223a9a0c..d8e3b2cd 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,7 +1,15 @@ +plugins { + `java-library` +} + repositories { mavenCentral() } dependencies { - compileOnly("org.jetbrains:annotations:26.0.1") + // Use it for nullability annotations + api("org.jspecify:jspecify:1.0.0") + + // Use it for contracts and unmodifiability annotations + api("org.jetbrains:annotations:26.0.2") } 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 index f9e9de33..88c6d274 100644 --- a/common/src/main/java/com/leonardobishop/quests/common/config/ConfigProblem.java +++ b/common/src/main/java/com/leonardobishop/quests/common/config/ConfigProblem.java @@ -1,41 +1,53 @@ package com.leonardobishop.quests.common.config; +import com.leonardobishop.quests.common.util.Modern; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +import java.util.Objects; + +@Modern(type = Modern.Type.FULL) +@NullMarked public final class ConfigProblem { private final ConfigProblemType type; private final String description; - private final String extendedDescription; + private final @Nullable String extendedDescription; private final String location; - public ConfigProblem(ConfigProblemType type, String description, String extendedDescription, String location) { - this.type = type; - this.description = description == null ? "?" : description; + public ConfigProblem(final ConfigProblemType type, final @Nullable String description, final @Nullable String extendedDescription, final @Nullable String location) { + this.type = Objects.requireNonNull(type, "type cannot be null"); + this.description = Objects.requireNonNullElse(description, "?"); this.extendedDescription = extendedDescription; - this.location = location == null ? "?" : location; + this.location = Objects.requireNonNullElse(location, "?"); } - public ConfigProblem(ConfigProblemType type, String description, String extendedDescription) { + public ConfigProblem(final ConfigProblemType type, final @Nullable String description, final @Nullable String extendedDescription) { this(type, description, extendedDescription, null); } + @Contract(pure = true) public ConfigProblemType getType() { - return type; + return this.type; } + @Contract(pure = true) public String getDescription() { - return description; + return this.description; } - public String getExtendedDescription() { - return extendedDescription; + @Contract(pure = true) + public @Nullable String getExtendedDescription() { + return this.extendedDescription; } + @Contract(pure = true) public String getLocation() { - return location; + return this.location; } public enum ConfigProblemType { - ERROR("Error", "E", 1, "An error prevents a quest from being loaded"), WARNING("Warning", "W", 2, "A warning indicates a quest may not work as expected"); @@ -44,27 +56,31 @@ public final class ConfigProblem { private final int priority; private final String description; - ConfigProblemType(String title, String shortened, int priority, String description) { + ConfigProblemType(final String title, final String shortened, final int priority, final String description) { this.title = title; this.shortened = shortened; this.priority = priority; this.description = description; } + @Contract(pure = true) public String getTitle() { - return title; + return this.title; } + @Contract(pure = true) public String getShortened() { - return shortened; + return this.shortened; } + @Contract(pure = true) public int getPriority() { - return priority; + return this.priority; } + @Contract(pure = true) public String getDescription() { - return description; + return this.description; } } -}
\ No newline at end of file +} 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 index bcfafdd0..e7d45981 100644 --- a/common/src/main/java/com/leonardobishop/quests/common/player/QPlayer.java +++ b/common/src/main/java/com/leonardobishop/quests/common/player/QPlayer.java @@ -5,8 +5,9 @@ import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFi import com.leonardobishop.quests.common.plugin.Quests; import com.leonardobishop.quests.common.quest.Quest; import com.leonardobishop.quests.common.questcontroller.QuestController; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -18,13 +19,14 @@ import java.util.UUID; /** * Represents a player. */ +@NullMarked public final class QPlayer { private final Quests plugin; private final QPlayerData playerData; private QuestController questController; - public QPlayer(final @NotNull Quests plugin, final @NotNull QPlayerData playerData, final @NotNull QuestController questController) { + public QPlayer(final Quests plugin, final QPlayerData playerData, final QuestController questController) { this.plugin = plugin; this.playerData = playerData; this.questController = questController; @@ -35,7 +37,8 @@ public final class QPlayer { * * @return the players data */ - public @NotNull QPlayerData getPlayerData() { + @Contract(pure = true) + public QPlayerData getPlayerData() { return this.playerData; } @@ -44,7 +47,8 @@ public final class QPlayer { * * @return uuid */ - public @NotNull UUID getPlayerUUID() { + @Contract(pure = true) + public UUID getPlayerUUID() { return this.playerData.playerUUID(); } @@ -53,7 +57,8 @@ public final class QPlayer { * * @return the players preferences */ - public @NotNull QPlayerPreferences getPlayerPreferences() { + @Contract(pure = true) + public QPlayerPreferences getPlayerPreferences() { return this.playerData.playerPreferences(); } @@ -62,43 +67,96 @@ public final class QPlayer { * * @return the quest progress file */ - public @NotNull QuestProgressFile getQuestProgressFile() { + @Contract(pure = true) + public QuestProgressFile getQuestProgressFile() { return this.playerData.questProgressFile(); } /** + * 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 + */ + @Contract(pure = true) + public QuestStartResult canStartQuest(final Quest quest) { + Objects.requireNonNull(quest, "quest cannot be null"); + + return this.questController.canPlayerStartQuest(this, quest); + } + + /** + * Gets whether 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 + */ + @Contract(pure = true) + public boolean hasStartedQuest(final Quest quest) { + Objects.requireNonNull(quest, "quest cannot be null"); + + return this.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(final Quest quest) { + Objects.requireNonNull(quest, "quest cannot be null"); + + return this.questController.startQuestForPlayer(this, quest); + } + + /** * 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) */ - @SuppressWarnings("UnusedReturnValue") - public boolean completeQuest(final @NotNull Quest quest) { + public boolean completeQuest(final Quest quest) { Objects.requireNonNull(quest, "quest cannot be null"); return this.questController.completeQuestForPlayer(this, quest); } /** - * Attempt to track a quest for the player. This will also play all effects (such as titles, messages etc.) + * Attempt to cancel a quest for the player. This will also play all effects (such as titles, messages etc.) * - * @param quest the quest to track + * @param quest the quest to start + * @return true if the quest was cancelled, false otherwise */ - public void trackQuest(final @Nullable Quest quest) { - this.questController.trackQuestForPlayer(this, quest); + public boolean cancelQuest(final Quest quest) { + Objects.requireNonNull(quest, "quest cannot be null"); + + return this.questController.cancelQuestForPlayer(this, quest); } /** - * Gets whether the player has started a specific quest. + * Attempt to expire a quest for the player. This will also play all effects (such as titles, messages etc.) * - * @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 + * @param quest the quest to start + * @return true if the quest was expired, false otherwise */ - public boolean hasStartedQuest(final @NotNull Quest quest) { + public boolean expireQuest(final Quest quest) { Objects.requireNonNull(quest, "quest cannot be null"); - return this.questController.hasPlayerStartedQuest(this, quest); + return this.questController.expireQuestForPlayer(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(final @Nullable Quest quest) { + this.questController.trackQuestForPlayer(this, quest); } /** @@ -106,7 +164,8 @@ public final class QPlayer { * * @return list of effectively started quests */ - public @NotNull List<Quest> getEffectiveStartedQuests() { + @Contract(pure = true) + public List<Quest> getEffectiveStartedQuests() { return this.getEffectiveStartedQuests(-1); } @@ -117,9 +176,10 @@ public final class QPlayer { * @param limit the maximum number of quests to return. A value of -1 indicates no limit. * @return list of effectively started quests, up to the specified limit */ - public @NotNull List<Quest> getEffectiveStartedQuests(final int limit) { + @Contract(pure = true) + public List<Quest> getEffectiveStartedQuests(final int limit) { final Collection<Quest> quests = this.plugin.getQuestManager() - .getQuests() + .getQuestMap() .values(); final List<Quest> ret; @@ -152,64 +212,35 @@ public final class QPlayer { } /** - * 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 @NotNull QuestStartResult startQuest(final @NotNull Quest quest) { - Objects.requireNonNull(quest, "quest cannot be null"); - - return this.questController.startQuestForPlayer(this, quest); - } - - /** - * Attempt to cancel a quest for the player. This will also play all effects (such as titles, messages etc.) + * Gets count of quests which the player has effectively started. This includes quests started automatically. * - * @param quest the quest to start - * @return true if the quest was cancelled, false otherwise + * @return count of effectively started quests */ - public boolean cancelQuest(final @NotNull Quest quest) { - Objects.requireNonNull(quest, "quest cannot be null"); - - return this.questController.cancelQuestForPlayer(this, quest); - } + @Contract(pure = true) + public int getEffectiveStartedQuestsCount() { + int count = 0; - /** - * Attempt to expire 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 expired, false otherwise - */ - @SuppressWarnings("UnusedReturnValue") - public boolean expireQuest(final @NotNull Quest quest) { - Objects.requireNonNull(quest, "quest cannot be null"); - - return this.questController.expireQuestForPlayer(this, quest); - } + final Collection<Quest> quests = this.plugin.getQuestManager() + .getQuestMap() + .values(); - /** - * 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 @NotNull QuestStartResult canStartQuest(final @NotNull Quest quest) { - Objects.requireNonNull(quest, "quest cannot be null"); + for (final Quest quest : quests) { + if (this.questController.hasPlayerStartedQuest(this, quest)) { + count++; + } + } - return this.questController.canPlayerStartQuest(this, quest); + return count; } /** * Get player's associated {@link QuestController}. It's usually the server's active quest controller. * - * @see QPlayerManager#getActiveQuestController() * @return the quest controller for this player + * @see QPlayerManager#getActiveQuestController() */ - public @NotNull QuestController getQuestController() { + @Contract(pure = true) + public QuestController getQuestController() { return this.questController; } @@ -218,7 +249,7 @@ public final class QPlayer { * * @param questController new quest controller */ - public void setQuestController(final @NotNull QuestController questController) { + public void setQuestController(final QuestController questController) { Objects.requireNonNull(questController, "questController cannot be null"); this.questController = questController; diff --git a/common/src/main/java/com/leonardobishop/quests/common/player/QPlayerData.java b/common/src/main/java/com/leonardobishop/quests/common/player/QPlayerData.java index cdabd385..2209bcba 100644 --- a/common/src/main/java/com/leonardobishop/quests/common/player/QPlayerData.java +++ b/common/src/main/java/com/leonardobishop/quests/common/player/QPlayerData.java @@ -1,24 +1,27 @@ package com.leonardobishop.quests.common.player; import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFile; -import org.jetbrains.annotations.NotNull; +import com.leonardobishop.quests.common.util.Modern; +import org.jspecify.annotations.NullMarked; import java.util.Objects; import java.util.UUID; +@Modern(type = Modern.Type.FULL) +@NullMarked public final class QPlayerData { private final UUID playerUUID; private final QPlayerPreferences playerPreferences; private final QuestProgressFile questProgressFile; - public QPlayerData(final @NotNull UUID playerUUID, final @NotNull QPlayerPreferences playerPreferences, final @NotNull QuestProgressFile questProgressFile) { + public QPlayerData(final UUID playerUUID, final QPlayerPreferences playerPreferences, final QuestProgressFile questProgressFile) { this.playerUUID = Objects.requireNonNull(playerUUID, "playerUUID cannot be null"); this.playerPreferences = Objects.requireNonNull(playerPreferences, "playerPreferences cannot be null"); this.questProgressFile = Objects.requireNonNull(questProgressFile, "questProgressFile cannot be null"); } - public QPlayerData(final @NotNull QPlayerData playerData) { + public QPlayerData(final QPlayerData playerData) { Objects.requireNonNull(playerData, "playerData cannot be null"); this.playerUUID = playerData.playerUUID; @@ -26,15 +29,15 @@ public final class QPlayerData { this.questProgressFile = new QuestProgressFile(playerData.questProgressFile); } - public @NotNull UUID playerUUID() { + public UUID playerUUID() { return this.playerUUID; } - public @NotNull QPlayerPreferences playerPreferences() { + public QPlayerPreferences playerPreferences() { return this.playerPreferences; } - public @NotNull QuestProgressFile questProgressFile() { + public QuestProgressFile questProgressFile() { return this.questProgressFile; } 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 index 4c3704de..52c1985d 100644 --- a/common/src/main/java/com/leonardobishop/quests/common/player/QPlayerManager.java +++ b/common/src/main/java/com/leonardobishop/quests/common/player/QPlayerManager.java @@ -4,9 +4,10 @@ import com.leonardobishop.quests.common.player.questprogressfile.QuestProgressFi import com.leonardobishop.quests.common.plugin.Quests; import com.leonardobishop.quests.common.questcontroller.QuestController; import com.leonardobishop.quests.common.storage.StorageProvider; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.leonardobishop.quests.common.util.Modern; import org.jetbrains.annotations.UnmodifiableView; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Collection; import java.util.Collections; @@ -20,6 +21,8 @@ import java.util.concurrent.ConcurrentHashMap; * The QPlayerManager is responsible for keeping a reference to all players on the server and is used to * obtain an instance of a player, load new players and save current players. */ +@Modern(type = Modern.Type.FULL) +@NullMarked public final class QPlayerManager { private final Quests plugin; @@ -27,7 +30,7 @@ public final class QPlayerManager { private final Map<UUID, QPlayer> qPlayerMap; private QuestController activeQuestController; - public QPlayerManager(final @NotNull Quests plugin, final @NotNull StorageProvider storageProvider, final @NotNull QuestController questController) { + public QPlayerManager(final Quests plugin, final StorageProvider storageProvider, final QuestController questController) { this.plugin = Objects.requireNonNull(plugin, "plugin cannot be null"); this.storageProvider = Objects.requireNonNull(storageProvider, "storageProvider cannot be null"); this.activeQuestController = Objects.requireNonNull(questController, "questController cannot be null"); @@ -40,7 +43,7 @@ public final class QPlayerManager { * @param uuid the uuid * @return {@link QPlayer} if they are loaded, otherwise null */ - public @Nullable QPlayer getPlayer(final @NotNull UUID uuid) { + public @Nullable QPlayer getPlayer(final UUID uuid) { Objects.requireNonNull(uuid, "uuid cannot be null"); // QPlayer qPlayer = qPlayers.get(uuid); @@ -58,7 +61,7 @@ public final class QPlayerManager { * * @param uuid the uuid of the player */ - public void removePlayer(final @NotNull UUID uuid) { + public void removePlayer(final UUID uuid) { Objects.requireNonNull(uuid, "uuid cannot be null"); this.plugin.getQuestsLogger().debug("Unloading and saving player " + uuid + "..."); @@ -73,7 +76,7 @@ public final class QPlayerManager { * @param uuid the uuid of the player * @return completable future */ - public @NotNull CompletableFuture<Void> savePlayer(final @NotNull UUID uuid) { + public CompletableFuture<@Nullable Void> savePlayer(final UUID uuid) { Objects.requireNonNull(uuid, "uuid cannot be null"); final QPlayer qPlayer = this.getPlayer(uuid); @@ -88,10 +91,10 @@ public final class QPlayerManager { * Schedules a save for the player with a specified {@link QuestProgressFile}. The modified status of the * specified progress file will be reset. */ - public @NotNull CompletableFuture<Void> savePlayer(final @NotNull QPlayerData playerData) { + public CompletableFuture<@Nullable Void> savePlayer(final QPlayerData playerData) { Objects.requireNonNull(playerData, "playerData cannot be null"); - final CompletableFuture<Void> future = new CompletableFuture<>(); + final CompletableFuture<@Nullable Void> future = new CompletableFuture<>(); final QPlayerData clonedPlayerData = new QPlayerData(playerData); playerData.setModified(false); @@ -109,7 +112,7 @@ public final class QPlayerManager { * * @param uuid the uuid of the player */ - public void savePlayerSync(final @NotNull UUID uuid) { + public void savePlayerSync(final UUID uuid) { Objects.requireNonNull(uuid, "uuid cannot be null"); final QPlayer qPlayer = this.getPlayer(uuid); @@ -124,11 +127,11 @@ public final class QPlayerManager { * Immediately saves the player with a specified {@link QuestProgressFile}, on the same thread. The modified status * of the specified progress file is not changed. */ - public void savePlayerSync(final @NotNull QPlayerData playerData) { + public void savePlayerSync(final QPlayerData playerData) { this.save(playerData); } - private void save(@NotNull QPlayerData playerData) { + private void save(final QPlayerData playerData) { Objects.requireNonNull(playerData, "playerData cannot be null"); final String uuidString = playerData.playerUUID().toString(); @@ -146,7 +149,7 @@ public final class QPlayerManager { * * @param uuid the uuid of the player */ - public void dropPlayer(final @NotNull UUID uuid) { + public void dropPlayer(final UUID uuid) { Objects.requireNonNull(uuid, "uuid cannot be null"); this.plugin.getQuestsLogger().debug("Dropping player " + uuid + "."); @@ -158,8 +161,7 @@ public final class QPlayerManager { * * @return immutable collection of quest players */ - @UnmodifiableView - public @NotNull Collection<QPlayer> getQPlayers() { + public @UnmodifiableView Collection<QPlayer> getQPlayers() { return Collections.unmodifiableCollection(this.qPlayerMap.values()); } @@ -170,12 +172,12 @@ public final class QPlayerManager { * @param uuid the uuid of the player * @return completable future with the loaded player, or null if there was an error */ - public @NotNull CompletableFuture<QPlayer> loadPlayer(final @NotNull UUID uuid) { + public CompletableFuture<@Nullable QPlayer> loadPlayer(final UUID uuid) { Objects.requireNonNull(uuid, "uuid cannot be null"); final String uuidString = uuid.toString(); this.plugin.getQuestsLogger().debug("Loading player " + uuidString + "..."); - final CompletableFuture<QPlayer> future = new CompletableFuture<>(); + final CompletableFuture<@Nullable QPlayer> future = new CompletableFuture<>(); this.plugin.getScheduler().doAsync(() -> { final QPlayerData playerData = this.storageProvider.loadPlayerData(uuid); @@ -201,15 +203,15 @@ public final class QPlayerManager { * * @return {@link StorageProvider} */ - public @NotNull StorageProvider getStorageProvider() { + public StorageProvider getStorageProvider() { return this.storageProvider; } - public @NotNull QuestController getActiveQuestController() { + public QuestController getActiveQuestController() { return this.activeQuestController; } - public void setActiveQuestController(final @NotNull QuestController activeQuestController) { + public void setActiveQuestController(final QuestController activeQuestController) { this.activeQuestController = Objects.requireNonNull(activeQuestController, "activeQuestController cannot be null"); for (final QPlayer qPlayer : this.qPlayerMap.values()) { 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 index addc8a76..a6adf4cb 100644 --- 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 @@ -1,10 +1,9 @@ package com.leonardobishop.quests.common.player.questprogressfile; import com.leonardobishop.quests.common.plugin.Quests; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Collection; import java.util.HashMap; @@ -12,6 +11,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +@NullMarked public final class QuestProgress { private final Quests plugin; @@ -39,7 +39,7 @@ public final class QuestProgress { * @param completionDate the date of the last quest completion * @param modified whether the object has been modified and needs to be saved */ - public QuestProgress(final @NotNull Quests plugin, final @NotNull String questId, final @NotNull UUID playerUUID, final boolean started, final long startedDate, final boolean completed, final boolean completedBefore, final long completionDate, final boolean modified) { + public QuestProgress(final Quests plugin, final String questId, final UUID playerUUID, final boolean started, final long startedDate, final boolean completed, final boolean completedBefore, final long completionDate, final boolean modified) { this.plugin = plugin; this.questId = questId; this.playerUUID = playerUUID; @@ -64,7 +64,7 @@ public final class QuestProgress { * @param completedBefore whether the quest has been completed before * @param completionDate the date of the last quest completion */ - public QuestProgress(final @NotNull Quests plugin, final @NotNull String questId, final @NotNull UUID playerUUID, final boolean started, final long startedDate, final boolean completed, final boolean completedBefore, final long completionDate) { + public QuestProgress(final Quests plugin, final String questId, final UUID playerUUID, final boolean started, final long startedDate, final boolean completed, final boolean completedBefore, final long completionDate) { this(plugin, questId, playerUUID, started, startedDate, completed, completedBefore, completionDate, false); } @@ -73,14 +73,13 @@ public final class QuestProgress { * * @param questProgress the quest progress instance */ - @ApiStatus.Internal - public QuestProgress(final @NotNull QuestProgress questProgress) { + public QuestProgress(final QuestProgress questProgress) { final Set<Map.Entry<String, TaskProgress>> progressEntries = questProgress.taskProgressMap.entrySet(); this.plugin = questProgress.plugin; this.questId = questProgress.questId; this.playerUUID = questProgress.playerUUID; - this.taskProgressMap = new HashMap<>(progressEntries.size()); + this.taskProgressMap = HashMap.newHashMap(progressEntries.size()); for (final Map.Entry<String, TaskProgress> progressEntry : progressEntries) { this.taskProgressMap.put(progressEntry.getKey(), new TaskProgress(progressEntry.getValue())); @@ -98,25 +97,15 @@ public final class QuestProgress { * @return the associated quest ID */ @Contract(pure = true) - public @NotNull String getQuestId() { + public String getQuestId() { return this.questId; } /** * @return the associated player ID - * @see QuestProgress#getPlayerUUID() - */ - @Deprecated(forRemoval = true) - @Contract(pure = true) - public @NotNull UUID getPlayer() { - return this.playerUUID; - } - - /** - * @return the associated player ID */ @Contract(pure = true) - public @NotNull UUID getPlayerUUID() { + public UUID getPlayerUUID() { return this.playerUUID; } @@ -124,26 +113,15 @@ public final class QuestProgress { * @return mutable task progress map */ @Contract(pure = true) - public @NotNull Map<String, TaskProgress> getTaskProgressMap() { + public Map<String, TaskProgress> getTaskProgressMap() { return this.taskProgressMap; } /** * @return mutable task progress map values collection - * @see QuestProgress#getAllTaskProgress() - */ - @Deprecated(forRemoval = true) - @Contract(pure = true) - public @NotNull Collection<TaskProgress> getTaskProgress() { - return this.taskProgressMap.values(); - } - - /** - * @return mutable task progress map values collection */ - @SuppressWarnings("unused") @Contract(pure = true) - public @NotNull Collection<TaskProgress> getAllTaskProgress() { + public Collection<TaskProgress> getTaskProgresses() { return this.taskProgressMap.values(); } @@ -153,7 +131,7 @@ public final class QuestProgress { * @param taskId the task ID to get the progress for * @return {@link TaskProgress} or a blank generated one if the task does not exist */ - public @NotNull TaskProgress getTaskProgress(final @NotNull String taskId) { + public TaskProgress getTaskProgress(final String taskId) { final TaskProgress taskProgress = this.taskProgressMap.get(taskId); if (taskProgress != null) { return taskProgress; @@ -170,26 +148,15 @@ public final class QuestProgress { * @param taskId the task ID to get the progress for * @return {@link TaskProgress} or null if the task does not exist */ - @SuppressWarnings("unused") @Contract(pure = true) - public @Nullable TaskProgress getTaskProgressOrNull(final @NotNull String taskId) { + public @Nullable TaskProgress getTaskProgressOrNull(final String taskId) { return this.taskProgressMap.get(taskId); } /** - * @param taskId the task ID to repair the progress for - */ - @Deprecated(forRemoval = true) - @ApiStatus.Internal - public void repairTaskProgress(final @NotNull String taskId) { - final TaskProgress taskProgress = new TaskProgress(this, taskId, this.playerUUID, null, false, false); - this.addTaskProgress(taskProgress); - } - - /** * @param taskProgress the task progress to put into the task progress map */ - public void addTaskProgress(final @NotNull TaskProgress taskProgress) { + public void addTaskProgress(final TaskProgress taskProgress) { this.taskProgressMap.put(taskProgress.getTaskId(), taskProgress); } @@ -210,7 +177,7 @@ public final class QuestProgress { } /** - * @return the date of the last quest start + * @return {@code 0} if the quest hasn't been started yet, the date of the last quest start */ @Contract(pure = true) public long getStartedDate() { @@ -258,7 +225,7 @@ public final class QuestProgress { } /** - * @return the date of the last quest completion + * @return {@code 0} if the quest hasn't been completed yet, otherwise the date of the last quest completion */ @Contract(pure = true) public long getCompletionDate() { @@ -276,7 +243,6 @@ public final class QuestProgress { /** * @return whether the object has been modified and needs to be saved */ - @SuppressWarnings("unused") @Contract(pure = true) public boolean isModified() { if (this.modified) { @@ -293,16 +259,6 @@ public final class QuestProgress { } /** - * It's equivalent to {@code QuestProgress#setModified(false)}. - * - * @see QuestProgress#setModified(boolean) - */ - @Deprecated(forRemoval = true) - public void resetModified() { - this.setModified(false); - } - - /** * @param modified whether the object has been modified and needs to be saved */ public void setModified(final boolean modified) { @@ -322,7 +278,8 @@ public final class QuestProgress { * - {@link QuestProgress#startedDate}<br> * - {@link QuestProgress#completed}<br> * - {@link QuestProgress#completedBefore}<br> - * - {@link QuestProgress#completionDate} + * - {@link QuestProgress#completionDate}<br> + * - {@link QuestProgress#taskProgressMap} * </p> * * @return whether the object has non default values @@ -345,8 +302,58 @@ public final class QuestProgress { /** * Queues the {@link QuestProgress} instance for a completion test. */ - @SuppressWarnings("unused") public void queueForCompletionTest() { this.plugin.getQuestCompleter().queueSingular(this); } + + // DEPRECATED AND FOR REMOVAL + + /** + * @return the associated player ID + * @see QuestProgress#getPlayerUUID() + */ + @Deprecated(forRemoval = true) + @Contract(pure = true) + public UUID getPlayer() { + return this.playerUUID; + } + + /** + * @return mutable task progress map values collection + * @see QuestProgress#getTaskProgresses() + */ + @Deprecated(forRemoval = true) + @Contract(pure = true) + public Collection<TaskProgress> getTaskProgress() { + return this.getTaskProgresses(); + } + + /** + * @return mutable task progress map values collection + * @see QuestProgress#getTaskProgresses() + */ + @Deprecated(forRemoval = true) + @Contract(pure = true) + public Collection<TaskProgress> getAllTaskProgress() { + return this.getTaskProgresses(); + } + + /** + * @param taskId the task ID to repair the progress for + */ + @Deprecated(forRemoval = true) + public void repairTaskProgress(final String taskId) { + final TaskProgress taskProgress = new TaskProgress(this, taskId, this.playerUUID, null, false, false); + this.addTaskProgress(taskProgress); + } + + /** + * It's equivalent to {@code QuestProgress#setModified(false)}. + * + * @see QuestProgress#setModified(boolean) + */ + @Deprecated(forRemoval = true) + public void resetModified() { + this.setModified(false); + } } 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 index 2ebefe93..c4b1eea2 100644 --- 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 @@ -5,10 +5,10 @@ import com.leonardobishop.quests.common.player.questprogressfile.filters.QuestPr import com.leonardobishop.quests.common.plugin.Quests; import com.leonardobishop.quests.common.quest.Quest; import com.leonardobishop.quests.common.quest.Task; -import org.jetbrains.annotations.ApiStatus; +import com.leonardobishop.quests.common.util.Modern; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -22,6 +22,8 @@ import java.util.concurrent.TimeUnit; /** * Represents underlying quest progress for a player. */ +@Modern(type = Modern.Type.FULL) +@NullMarked public final class QuestProgressFile { // https://github.com/LMBishop/Quests/issues/760 @@ -37,7 +39,7 @@ public final class QuestProgressFile { * @param plugin the plugin instance * @param playerUUID the associated player UUID */ - public QuestProgressFile(final @NotNull Quests plugin, final @NotNull UUID playerUUID) { + public QuestProgressFile(final Quests plugin, final UUID playerUUID) { this.plugin = plugin; this.playerUUID = playerUUID; this.questProgressMap = new HashMap<>(); @@ -48,13 +50,12 @@ public final class QuestProgressFile { * * @param questProgressFile the quest progress file instance */ - @ApiStatus.Internal - public QuestProgressFile(final @NotNull QuestProgressFile questProgressFile) { + public QuestProgressFile(final QuestProgressFile questProgressFile) { final Set<Map.Entry<String, QuestProgress>> progressEntries = questProgressFile.questProgressMap.entrySet(); this.plugin = questProgressFile.plugin; this.playerUUID = questProgressFile.playerUUID; - this.questProgressMap = new HashMap<>(progressEntries.size()); + this.questProgressMap = HashMap.newHashMap(progressEntries.size()); for (final Map.Entry<String, QuestProgress> progressEntry : progressEntries) { this.questProgressMap.put(progressEntry.getKey(), new QuestProgress(progressEntry.getValue())); @@ -64,7 +65,7 @@ public final class QuestProgressFile { /** * @param questProgress the quest progress to put into the quest progress map */ - public void addQuestProgress(final @NotNull QuestProgress questProgress) { + public void addQuestProgress(final QuestProgress questProgress) { // TODO don't do that here //if (Options.VERIFY_QUEST_EXISTS_ON_LOAD.getBooleanValue(true) && plugin.getQuestManager().getQuestById(questProgress.getQuestId()) == null) { // return; @@ -80,7 +81,7 @@ public final class QuestProgressFile { * @return list of started quests */ @Contract(pure = true) - public @NotNull List<Quest> getStartedQuests() { + public List<Quest> getStartedQuests() { return this.getAllQuestsFromProgress(QuestProgressFilter.STARTED); } @@ -90,7 +91,7 @@ public final class QuestProgressFile { * @return list of matching quests */ @Contract(pure = true) - public @NotNull List<Quest> getAllQuestsFromProgress(final @NotNull QuestProgressFilter filter) { + public List<Quest> getAllQuestsFromProgress(final QuestProgressFilter filter) { final List<Quest> quests = new ArrayList<>(); for (final QuestProgress questProgress : this.questProgressMap.values()) { @@ -112,7 +113,7 @@ public final class QuestProgressFile { * @return count of matching quests */ @Contract(pure = true) - public int getAllQuestsFromProgressCount(final @NotNull QuestProgressFilter filter) { + public int getAllQuestsFromProgressCount(final QuestProgressFilter filter) { int count = 0; for (final QuestProgress questProgress : this.questProgressMap.values()) { @@ -126,7 +127,8 @@ public final class QuestProgressFile { return count; } - private @Nullable Quest getQuestFromProgress(final @NotNull QuestProgressFilter filter, final QuestProgress questProgress) { + @Contract(pure = true) + private @Nullable Quest getQuestFromProgress(final QuestProgressFilter filter, final QuestProgress questProgress) { final boolean matchesProgress = filter.matchesProgress(questProgress); if (!matchesProgress) { return null; @@ -151,7 +153,7 @@ public final class QuestProgressFile { * @return {@code Collection<QuestProgress>} all quest progresses */ @Contract(pure = true) - public @NotNull Collection<QuestProgress> getAllQuestProgress() { + public Collection<QuestProgress> getAllQuestProgress() { return this.questProgressMap.values(); } @@ -162,7 +164,7 @@ public final class QuestProgressFile { * @return true if they have quest progress */ @Contract(pure = true) - public boolean hasQuestProgress(final @NotNull Quest quest) { + public boolean hasQuestProgress(final Quest quest) { return this.questProgressMap.containsKey(quest.getId()); } @@ -170,11 +172,11 @@ public final class QuestProgressFile { * 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, -1 if the cooldown is disabled or the quest is not completed, + * @return {@code 0} if no cooldown remaining, {@code -1} if the cooldown is disabled or the quest is not completed, * otherwise the cooldown in milliseconds */ @Contract(pure = true) - public long getCooldownFor(final @NotNull Quest quest) { + public long getCooldownFor(final Quest quest) { if (!quest.isCooldownEnabled()) { return -1; } @@ -185,7 +187,7 @@ public final class QuestProgressFile { } final long completionDate = questProgress.getCompletionDate(); - if (completionDate == 0) { + if (completionDate == 0L) { return -1; } @@ -200,11 +202,11 @@ public final class QuestProgressFile { * Gets the time remaining before a quest will have expired. * * @param quest the quest to test for - * @return 0 if no time remaining, -1 if the time limit is disabled or the quest is not started, + * @return {@code 0} if no time remaining, {@code -1} if the time limit is disabled or the quest is not started, * otherwise the time left in milliseconds */ @Contract(pure = true) - public long getTimeRemainingFor(final @NotNull Quest quest) { + public long getTimeRemainingFor(final Quest quest) { if (!quest.isTimeLimitEnabled()) { return -1; } @@ -215,7 +217,7 @@ public final class QuestProgressFile { } final long startedDate = questProgress.getStartedDate(); - if (startedDate == 0) { + if (startedDate == 0L) { return -1; } @@ -234,7 +236,7 @@ public final class QuestProgressFile { */ // TODO possibly move this @Contract(pure = true) - public boolean hasMetRequirements(final @NotNull Quest quest) { + public boolean hasMetRequirements(final Quest quest) { for (final String requiredQuestId : quest.getRequirements()) { final QuestProgress requiredQuestProgress = this.questProgressMap.get(requiredQuestId); if (requiredQuestProgress == null || !requiredQuestProgress.isCompletedBefore()) { @@ -259,7 +261,7 @@ public final class QuestProgressFile { * @return the associated player UUID */ @Contract(pure = true) - public @NotNull UUID getPlayerUUID() { + public UUID getPlayerUUID() { return this.playerUUID; } @@ -269,7 +271,7 @@ public final class QuestProgressFile { * @param quest the quest to get the progress for * @return {@link QuestProgress} or a blank generated one if the quest does not exist */ - public @NotNull QuestProgress getQuestProgress(final @NotNull Quest quest) { + public QuestProgress getQuestProgress(final Quest quest) { if (DEBUG_ISSUE_760 && !this.plugin.isPrimaryThread()) { //noinspection CallToPrintStackTrace new IllegalStateException("async getQuestProgress call").printStackTrace(); @@ -286,7 +288,7 @@ public final class QuestProgressFile { * @return {@link QuestProgress} or null if the quest does not exist */ @Contract(pure = true) - public @Nullable QuestProgress getQuestProgressOrNull(final @NotNull Quest quest) { + public @Nullable QuestProgress getQuestProgressOrNull(final Quest quest) { return this.questProgressMap.get(quest.getId()); } @@ -297,7 +299,7 @@ public final class QuestProgressFile { * @return true if player has the quest started */ @Contract(pure = true) - public boolean hasQuestStarted(final @NotNull Quest quest) { + public boolean hasQuestStarted(final Quest quest) { final QuestProgress questProgress = this.getQuestProgressOrNull(quest); return questProgress != null && questProgress.isStarted(); } @@ -308,7 +310,7 @@ public final class QuestProgressFile { * @param quest the quest to generate the progress for * @return the generated blank {@link QuestProgress} */ - public @NotNull QuestProgress generateBlankQuestProgress(final @NotNull Quest quest) { + public QuestProgress generateBlankQuestProgress(final Quest quest) { return this.generateBlankQuestProgress(quest, false); } @@ -319,7 +321,7 @@ public final class QuestProgressFile { * @param modified the modified state of the quest * @return the generated blank {@link QuestProgress} */ - public @NotNull QuestProgress generateBlankQuestProgress(final @NotNull Quest quest, final boolean modified) { + public QuestProgress generateBlankQuestProgress(final Quest quest, final boolean modified) { final QuestProgress questProgress = new QuestProgress(this.plugin, quest.getId(), this.playerUUID, false, 0L, false, false, 0L, modified); for (final Task task : quest.getTasks()) { @@ -420,7 +422,7 @@ public final class QuestProgressFile { */ @Deprecated(forRemoval = true) @Contract(pure = true) - public @NotNull List<Quest> getAllQuestsFromProgress(final @NotNull QuestsProgressFilter filter) { + public List<Quest> getAllQuestsFromProgress(final QuestsProgressFilter filter) { final List<Quest> quests = new ArrayList<>(); for (final QuestProgress questProgress : this.questProgressMap.values()) { @@ -445,46 +447,46 @@ public final class QuestProgressFile { ALL("all") { @Override @Contract(pure = true) - public boolean matches(final @NotNull QuestProgress questProgress) { + public boolean matches(final QuestProgress questProgress) { return QuestProgressFilter.ALL.matchesProgress(questProgress); } }, COMPLETED("completed") { @Override @Contract(pure = true) - public boolean matches(final @NotNull QuestProgress questProgress) { + public boolean matches(final QuestProgress questProgress) { return QuestProgressFilter.COMPLETED.matchesProgress(questProgress); } }, COMPLETED_BEFORE("completedBefore") { @Override @Contract(pure = true) - public boolean matches(final @NotNull QuestProgress questProgress) { + public boolean matches(final QuestProgress questProgress) { return QuestProgressFilter.COMPLETED_BEFORE.matchesProgress(questProgress); } }, STARTED("started") { @Override @Contract(pure = true) - public boolean matches(final @NotNull QuestProgress questProgress) { + public boolean matches(final QuestProgress questProgress) { return QuestProgressFilter.STARTED.matchesProgress(questProgress); } }; private final String legacy; - QuestsProgressFilter(final @NotNull String legacy) { + QuestsProgressFilter(final String legacy) { this.legacy = legacy; } @SuppressWarnings("unused") @Contract(pure = true) - public @NotNull String getLegacy() { + public String getLegacy() { return this.legacy; } @Contract(pure = true) - public abstract boolean matches(final @NotNull QuestProgress questProgress); + public abstract boolean matches(final QuestProgress questProgress); // And some static things to improve legacy performance (is it even used?) @@ -498,7 +500,7 @@ public final class QuestProgressFile { @SuppressWarnings("unused") @Contract(pure = true) - public static @NotNull QuestsProgressFilter fromLegacy(final @NotNull String legacy) { + public static QuestsProgressFilter fromLegacy(final String legacy) { return QuestsProgressFilter.legacyToFilterMap.getOrDefault(legacy, QuestsProgressFilter.ALL); } } 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 index 9395634e..531a524f 100644 --- 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 @@ -1,20 +1,22 @@ package com.leonardobishop.quests.common.player.questprogressfile; -import org.jetbrains.annotations.ApiStatus; +import com.leonardobishop.quests.common.util.Modern; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Objects; import java.util.UUID; +@Modern(type = Modern.Type.FULL) +@NullMarked public final class TaskProgress { - private final QuestProgress questProgress; + private final @Nullable QuestProgress questProgress; private final String taskId; private final UUID playerUUID; - private Object progress; + private @Nullable Object progress; private boolean completed; private boolean modified; @@ -28,7 +30,7 @@ public final class TaskProgress { * @param completed whether the task is completed * @param modified whether the object has been modified and needs to be saved */ - public TaskProgress(final @Nullable QuestProgress questProgress, final @NotNull String taskId, final @NotNull UUID playerUUID, final @Nullable Object progress, final boolean completed, final boolean modified) { + public TaskProgress(final @Nullable QuestProgress questProgress, final String taskId, final UUID playerUUID, final @Nullable Object progress, final boolean completed, final boolean modified) { this.questProgress = questProgress; this.taskId = taskId; this.playerUUID = playerUUID; @@ -46,7 +48,7 @@ public final class TaskProgress { * @param progress the progress object * @param completed whether the task is completed */ - public TaskProgress(final @NotNull QuestProgress questProgress, final @NotNull String taskId, final @NotNull UUID playerUUID, final @Nullable Object progress, final boolean completed) { + public TaskProgress(final QuestProgress questProgress, final String taskId, final UUID playerUUID, final @Nullable Object progress, final boolean completed) { this(questProgress, taskId, playerUUID, progress, completed, false); } @@ -55,8 +57,7 @@ public final class TaskProgress { * * @param taskProgress the task progress instance */ - @ApiStatus.Internal - public TaskProgress(final @NotNull TaskProgress taskProgress) { + public TaskProgress(final TaskProgress taskProgress) { this(null, taskProgress.taskId, taskProgress.playerUUID, taskProgress.progress, taskProgress.completed, taskProgress.modified); } @@ -64,25 +65,15 @@ public final class TaskProgress { * @return the associated task ID */ @Contract(pure = true) - public @NotNull String getTaskId() { + public String getTaskId() { return this.taskId; } /** * @return the associated player ID - * @see QuestProgress#getPlayerUUID() - */ - @Deprecated(forRemoval = true) - @Contract(pure = true) - public @NotNull UUID getPlayer() { - return this.playerUUID; - } - - /** - * @return the associated player ID */ @Contract(pure = true) - public @NotNull UUID getPlayerUUID() { + public UUID getPlayerUUID() { return this.playerUUID; } @@ -145,6 +136,25 @@ public final class TaskProgress { } /** + * @param modified whether the object has been modified and needs to be saved + */ + public void setModified(final boolean modified) { + this.modified = modified; + } + + // DEPRECATED AND FOR REMOVAL + + /** + * @return the associated player ID + * @see QuestProgress#getPlayerUUID() + */ + @Deprecated(forRemoval = true) + @Contract(pure = true) + public UUID getPlayer() { + return this.playerUUID; + } + + /** * It's equivalent to {@code TaskProgress#setModified(false)}. * * @see TaskProgress#setModified(boolean) @@ -153,11 +163,4 @@ public final class TaskProgress { public void resetModified() { this.setModified(false); } - - /** - * @param modified whether the object has been modified and needs to be saved - */ - public void setModified(final boolean modified) { - this.modified = modified; - } } 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 index 23533210..ddfad1b2 100644 --- a/common/src/main/java/com/leonardobishop/quests/common/plugin/Quests.java +++ b/common/src/main/java/com/leonardobishop/quests/common/plugin/Quests.java @@ -10,8 +10,9 @@ 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 org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NullMarked; +@NullMarked public interface Quests { /** @@ -20,7 +21,7 @@ public interface Quests { * @see QuestsLogger * @return quests logger */ - @NotNull QuestsLogger getQuestsLogger(); + QuestsLogger getQuestsLogger(); /** * Obtain an instance of the QuestManager. @@ -28,7 +29,15 @@ public interface Quests { * @see QuestManager * @return quest manager */ - @NotNull QuestManager getQuestManager(); + QuestManager getQuestManager(); + + /** + * Obtain an instance of the TaskTypeManager. + * + * @see TaskTypeManager + * @return task type manager + */ + TaskTypeManager getTaskTypeManager(); /** * Obtain an instance of the QPlayerManager. @@ -36,7 +45,7 @@ public interface Quests { * @see QPlayerManager * @return quest player manager */ - @NotNull QPlayerManager getPlayerManager(); + QPlayerManager getPlayerManager(); /** * Obtain an instance of the QuestController. @@ -44,15 +53,7 @@ public interface Quests { * @see QuestController * @return quest controller */ - @NotNull QuestController getQuestController(); - - /** - * Obtain an instance of the TaskTypeManager. - * - * @see TaskTypeManager - * @return task type manager - */ - @NotNull TaskTypeManager getTaskTypeManager(); + QuestController getQuestController(); /** * Obtain an instance of the QuestCompleter. @@ -60,7 +61,7 @@ public interface Quests { * @see QuestCompleter * @return quest completer */ - @NotNull QuestCompleter getQuestCompleter(); + QuestCompleter getQuestCompleter(); /** * Obtain an instance of the QuestConfig. @@ -68,7 +69,7 @@ public interface Quests { * @see QuestsConfig * @return quest config */ - @NotNull QuestsConfig getQuestsConfig(); + QuestsConfig getQuestsConfig(); /** * Obtain an instance of the Updater. @@ -76,7 +77,7 @@ public interface Quests { * @see Updater * @return updater */ - @NotNull Updater getUpdater(); + Updater getUpdater(); /** * Obtain an instance of the ServerScheduler. @@ -84,7 +85,7 @@ public interface Quests { * @see ServerScheduler * @return server scheduler */ - @NotNull ServerScheduler getScheduler(); + ServerScheduler getScheduler(); /** * Obtain an instance of the StorageProvider. @@ -92,7 +93,7 @@ public interface Quests { * @see StorageProvider * @return storage provider */ - @NotNull StorageProvider getStorageProvider(); + StorageProvider getStorageProvider(); /** * Performs a full reload of the plugin, unloading and re-registering quests to their task types. 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 index 0531af5b..285eff1a 100644 --- a/common/src/main/java/com/leonardobishop/quests/common/quest/Category.java +++ b/common/src/main/java/com/leonardobishop/quests/common/quest/Category.java @@ -1,73 +1,116 @@ package com.leonardobishop.quests.common.quest; -import org.jetbrains.annotations.NotNull; +import com.leonardobishop.quests.common.util.Modern; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.UnmodifiableView; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; -public class Category { +/** + * Represents a category for organizing quests within the quest system. Each category can have + * associated quests, and it can specify whether permission is required to access it and whether + * it should be hidden from the plugin menus. + */ +@Modern(type = Modern.Type.FULL) +@NullMarked +public final class Category { + + private static final String PERMISSION_PREFIX = "quests.category."; private final String id; + private final List<String> registeredQuestIds; private final boolean permissionRequired; - private final List<String> registeredQuestIds = new ArrayList<>(); private final boolean hidden; - public Category(String id, boolean permissionRequired) { - this(id, permissionRequired, false); - } - - public Category(String id, boolean permissionRequired, boolean hidden) { - this.id = id; + /** + * Constructs a Category with the specified parameters. + * + * @param id the unique identifier for the category; must not be null + * @param permissionRequired whether a permission is required to access this category + * @param hidden whether the category should be hidden from view + */ + public Category(final String id, final boolean permissionRequired, final boolean hidden) { + this.id = Objects.requireNonNull(id, "id cannot be null"); + this.registeredQuestIds = new ArrayList<>(); this.permissionRequired = permissionRequired; this.hidden = hidden; } /** - * Get the id of this category. + * Constructs a Category with {@link Category#hidden} set to {@code false}. * - * @return id + * @param id the unique identifier for the category; must not be null + * @param permissionRequired whether a permission is required to access this category */ - public @NotNull String getId() { - return id; + public Category(final String id, final boolean permissionRequired) { + this(id, permissionRequired, false); } /** - * Get if a specific permission is required to open this category and start quests within it. - * This permission will be in the form of "quests.category.[category id]". + * Returns the unique identifier of this category. * - * @return boolean + * @return the category ID */ + @Contract(pure = true) + public String getId() { + return this.id; + } + + /** + * Checks if a specific permission is required to access this category and start quests within it. + * The permission will be in the form of "quests.category.[category id]". + * + * @return true if permission is required, false otherwise + * @see Category#getPermission() Permission getter + */ + @Contract(pure = true) public boolean isPermissionRequired() { - return permissionRequired; + return this.permissionRequired; } /** - * Register a new quest ID to this category + * Returns the permission required to start quests in this category. * - * @param questId quest id to register + * @return the permission string if required, or null if no permission is needed */ - public void registerQuestId(@NotNull String questId) { + @Contract(pure = true) + public @Nullable String getPermission() { + return this.permissionRequired ? PERMISSION_PREFIX + this.id : null; + } + + /** + * Registers a new quest ID to this category. + * + * @param questId the quest ID to register; must not be null + */ + public void registerQuestId(final String questId) { Objects.requireNonNull(questId, "questId cannot be null"); - registeredQuestIds.add(questId); + + this.registeredQuestIds.add(questId); } /** - * Get quest IDs which are registered to this category + * Returns an unmodifiable list of quest IDs that are registered to this category. * - * @return immutable list of quest ids + * @return an unmodifiable list of registered quest IDs */ - public @NotNull List<String> getRegisteredQuestIds() { - return Collections.unmodifiableList(registeredQuestIds); + @Contract(pure = true) + public @UnmodifiableView List<String> getRegisteredQuestIds() { + return Collections.unmodifiableList(this.registeredQuestIds); } /** - * Get if this category is hidden + * Checks if this category is hidden from view. * - * @return true if hidden + * @return true if the category is hidden, false otherwise */ + @Contract(pure = true) public boolean isHidden() { - return hidden; + return this.hidden; } } 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 index 1f5d6d0d..b0d73e4e 100644 --- a/common/src/main/java/com/leonardobishop/quests/common/quest/Quest.java +++ b/common/src/main/java/com/leonardobishop/quests/common/quest/Quest.java @@ -109,6 +109,13 @@ public class Quest implements Comparable<Quest> { } /** + * @return permission required to start the quest + */ + public @Nullable String getPermission() { + return isPermissionRequired() ? "quests.quest." + id : null; + } + + /** * Get the reward string of the quest. * The reward string is a series of messages sent to the player upon completing the quest. * 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 index 2a569b2e..562fad8a 100644 --- a/common/src/main/java/com/leonardobishop/quests/common/quest/QuestManager.java +++ b/common/src/main/java/com/leonardobishop/quests/common/quest/QuestManager.java @@ -1,8 +1,10 @@ package com.leonardobishop.quests.common.quest; -import com.leonardobishop.quests.common.plugin.Quests; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.leonardobishop.quests.common.util.Modern; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.UnmodifiableView; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; @@ -14,14 +16,20 @@ import java.util.Objects; /** * The quests manager stores all present Quests and Categories on the server and is used as a registry. */ -public class QuestManager { +@Modern(type = Modern.Type.FULL) +@NullMarked +public final class QuestManager { - private final Quests plugin; - private final Map<String, Quest> quests = new LinkedHashMap<>(); - private final List<Category> categories = new ArrayList<>(); + private final Map<String, Quest> questMap; + private final List<Category> categories; - public QuestManager(Quests plugin) { - this.plugin = plugin; + /** + * Constructs a QuestManager. + */ + public QuestManager() { + // Specify expected size as people tend to add horrendous amounts of quests + this.questMap = LinkedHashMap.newLinkedHashMap(1024); + this.categories = new ArrayList<>(); } /** @@ -29,28 +37,31 @@ public class QuestManager { * * @param quest the category to register */ - public void registerQuest(@NotNull Quest quest) { + public void registerQuest(final Quest quest) { Objects.requireNonNull(quest, "quest cannot be null"); - quests.put(quest.getId(), quest); + this.questMap.put(quest.getId(), quest); } /** * @param id id to match * @return {@link Quest}, or null */ - public @Nullable Quest getQuestById(@NotNull String id) { + @Contract(pure = true) + public @Nullable Quest getQuestById(final String id) { Objects.requireNonNull(id, "id cannot be null"); - return quests.get(id); + return this.questMap.get(id); } /** * Get a map of id-quest of all quests registered + * * @return immutable map of all {@link Quest} */ - public @NotNull Map<String, Quest> getQuests() { - return Collections.unmodifiableMap(quests); + @Contract(pure = true) + public @UnmodifiableView Map<String, Quest> getQuestMap() { + return Collections.unmodifiableMap(this.questMap); } /** @@ -58,17 +69,10 @@ public class QuestManager { * * @param category the category to register */ - public void registerCategory(@NotNull Category category) { + public void registerCategory(final Category category) { Objects.requireNonNull(category, "category cannot be null"); - categories.add(category); - } - - /** - * @return immutable list of all {@link Category} - */ - public @NotNull List<Category> getCategories() { - return Collections.unmodifiableList(categories); + this.categories.add(category); } /** @@ -77,21 +81,48 @@ public class QuestManager { * @param id the id * @return {@link Category}, or null */ - public @Nullable Category getCategoryById(@NotNull String id) { + @Contract(pure = true) + public @Nullable Category getCategoryById(final String id) { Objects.requireNonNull(id, "id cannot be null"); - for (Category category : categories) { - if (category.getId().equals(id)) return category; + for (final Category category : this.categories) { + if (category.getId().equals(id)) { + return category; + } } + return null; } /** + * Get a map of id-category of all categories registered + * + * @return immutable map of all {@link Quest} + */ + @Contract(pure = true) + public @UnmodifiableView List<Category> getCategories() { + return Collections.unmodifiableList(this.categories); + } + + /** * Reset the quest manager and clears all registered quests and categories */ public void clear() { - quests.clear(); - categories.clear(); + this.questMap.clear(); + this.categories.clear(); } + // DEPRECATED AND FOR REMOVAL + + /** + * Get a map of id-quest of all quests registered + * + * @return immutable map of all {@link Quest} + * @see QuestManager#getQuestMap() + */ + @Deprecated(forRemoval = true) + @Contract(pure = true) + public @UnmodifiableView Map<String, Quest> getQuests() { + return this.getQuestMap(); + } } 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 index b92ed59e..c11b508e 100644 --- a/common/src/main/java/com/leonardobishop/quests/common/quest/Task.java +++ b/common/src/main/java/com/leonardobishop/quests/common/quest/Task.java @@ -1,60 +1,70 @@ package com.leonardobishop.quests.common.quest; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.leonardobishop.quests.common.util.Modern; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.UnmodifiableView; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; -public class Task { +@Modern(type = Modern.Type.FULL) +@NullMarked +public final class Task { - private final Map<String, Object> configValues = new HashMap<>(); private final String id; private final String type; + private final Map<String, Object> configValues; - public Task(String id, String type) { + public Task(final String id, final String type) { this.id = id; this.type = type; + this.configValues = new HashMap<>(); } /** - * @return the id of this task + * @return the id of the task */ - public @NotNull String getId() { - return id; + @Contract(pure = true) + public String getId() { + return this.id; } /** * @return the configured task type for this task */ - public @NotNull String getType() { - return type; + @Contract(pure = true) + public String getType() { + return this.type; } /** * Check if a config value is set for this task * - * @param key key of config value to check - * @return whether it exists + * @param key key of the config value to check + * @return whether the specified key exists */ - public boolean hasConfigKey(@NotNull String key) { + @Contract(pure = true) + public boolean hasConfigKey(final String key) { Objects.requireNonNull(key, "key cannot be null"); - return configValues.containsKey(key); + return this.configValues.containsKey(key); } /** * Get a specific configuration value for this task * - * @param key key of config value to get + * @param key key of the config value to get * @return config value, or null */ - public @Nullable Object getConfigValue(@NotNull String key) { + @Contract(pure = true) + public @Nullable Object getConfigValue(final String key) { Objects.requireNonNull(key, "key cannot be null"); - return configValues.getOrDefault(key, null); //??? this will return null without the need of `OrDefault(key, null)` + return this.configValues.get(key); } /** @@ -62,32 +72,34 @@ public class Task { * * @param key key of config value to get * @param def default value if null - * @return config value, or null + * @return config value, or default */ - public @Nullable Object getConfigValue(@NotNull String key, @Nullable Object def) { + @Contract(pure = true) + public Object getConfigValue(final String key, final Object def) { Objects.requireNonNull(key, "key cannot be null"); + Objects.requireNonNull(def, "def cannot be null"); - return configValues.getOrDefault(key, def); + return this.configValues.getOrDefault(key, def); } /** - * @return immutable list containing all config values + * @return immutable map of the config values */ - public @NotNull Map<String, Object> getConfigValues() { - return Collections.unmodifiableMap(configValues); + @Contract(pure = true) + public @UnmodifiableView Map<String, Object> getConfigValues() { + return Collections.unmodifiableMap(this.configValues); } /** * Add a key-value pair to this tasks configuration * - * @param key key + * @param key key * @param value value */ - public void addConfigValue(@NotNull String key, @NotNull Object value) { + public void addConfigValue(final String key, final Object value) { Objects.requireNonNull(key, "key cannot be null"); Objects.requireNonNull(value, "value cannot be null"); - configValues.put(key, value); + this.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 index d1e4812c..a178ca5e 100644 --- a/common/src/main/java/com/leonardobishop/quests/common/questcontroller/QuestController.java +++ b/common/src/main/java/com/leonardobishop/quests/common/questcontroller/QuestController.java @@ -3,27 +3,35 @@ 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; +import com.leonardobishop.quests.common.util.Modern; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** * The quests controller dictates how the plugin should act and acts as a bridge between a player * and their progress file, interpreting the progress file and mutating it on certain events. */ +@Modern(type = Modern.Type.FULL) +@NullMarked public interface QuestController { + @Contract(pure = true) String getName(); - QuestStartResult startQuestForPlayer(QPlayer qPlayer, Quest quest); - + @Contract(pure = true) QuestStartResult canPlayerStartQuest(QPlayer qPlayer, Quest quest); - boolean completeQuestForPlayer(QPlayer qPlayer, Quest quest); - + @Contract(pure = true) boolean hasPlayerStartedQuest(QPlayer qPlayer, Quest quest); + QuestStartResult startQuestForPlayer(QPlayer qPlayer, Quest quest); + + boolean completeQuestForPlayer(QPlayer qPlayer, Quest quest); + boolean cancelQuestForPlayer(QPlayer qPlayer, Quest quest); boolean expireQuestForPlayer(QPlayer qPlayer, Quest quest); - void trackQuestForPlayer(QPlayer qPlayer, Quest quest); - + void trackQuestForPlayer(QPlayer qPlayer, @Nullable Quest quest); } 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 index 526b7444..7e294c55 100644 --- a/common/src/main/java/com/leonardobishop/quests/common/tasktype/TaskType.java +++ b/common/src/main/java/com/leonardobishop/quests/common/tasktype/TaskType.java @@ -3,193 +3,208 @@ 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 org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.leonardobishop.quests.common.util.Modern; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Unmodifiable; +import org.jetbrains.annotations.UnmodifiableView; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; 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. + * Represents a type of task that can be used within quests. A {@link Quest} + * will be associated with this task type if it contains at least one task + * of this type, allowing for efficient quest management without the need + * to iterate through every single quest. */ +@Modern(type = Modern.Type.FULL) +@NullMarked public abstract class TaskType { protected final String type; - private final String author; - private final String description; - private final Set<String> aliases; - private final Set<Quest> quests; - private final Set<ConfigValidator> configValidators; + private final @Nullable String author; + private final @Nullable String description; + private final List<String> aliases; + private final List<ConfigValidator> configValidators; + private final List<Quest> quests; /** - * Constructs a TaskType. + * Constructs a new TaskType with the specified parameters. * - * @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 - * @param aliases the aliases of the task type, should not contain spaces + * @param type the name of the task type; must not contain spaces + * @param author the name of the person (or people) who created this task type; can be null + * @param description a short description of the task type; can be null + * @param aliases an array of alternative names for this task type; must not be null */ - public TaskType(final @NotNull String type, final @Nullable String author, final @Nullable String description, final @NotNull String @NotNull ... aliases) { + public TaskType(final String type, final @Nullable String author, final @Nullable String description, final String... aliases) { Objects.requireNonNull(type, "type cannot be null"); Objects.requireNonNull(aliases, "aliases cannot be null"); this.type = type; this.author = author; this.description = description; - this.aliases = Set.of(aliases); - this.quests = new HashSet<>(); - this.configValidators = new HashSet<>(); + this.aliases = List.of(aliases); + this.configValidators = new ArrayList<>(); + this.quests = new ArrayList<>(); } /** - * Constructs a TaskType with the specified type, author, and description. + * Constructs a new TaskType with the specified type, author, and 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 + * @param type the name of the task type; must not contain spaces + * @param author the name of the person (or people) who created this task type; can be null + * @param description a short description of the task type; can be null */ - public TaskType(final @NotNull String type, final @Nullable String author, final @Nullable String description) { + public TaskType(final String type, final @Nullable String author, final @Nullable String description) { this(type, author, description, new String[0]); } /** - * Constructs a TaskType with the specified type. + * Constructs a new TaskType with the specified type. * - * @param type the name of the task type, should not contain spaces + * @param type the name of the task type; must not contain spaces */ - public TaskType(final @NotNull String type) { + public TaskType(final String type) { this(type, null, null); } /** - * Registers a {@link Quest} to this task type. This is usually done when - * all the quests are initially loaded. + * Returns the name of this task type. * - * @param quest the {@link Quest} to register. + * @return the task type name */ - public final void registerQuest(final @NotNull Quest quest) { - Objects.requireNonNull(quest, "quest cannot be null"); - - this.quests.add(quest); + @Contract(pure = true) + public final String getType() { + return this.type; } /** - * Clears the set which contains the registered quests. + * Returns the author of this task type. + * + * @return the author's name, or null if not specified */ - protected final void unregisterAll() { - this.quests.clear(); + @Contract(pure = true) + public final @Nullable String getAuthor() { + return this.author; } /** - * Returns an immutable set of all registered quests. + * Returns the description of this task type. * - * @return immutable {@link Set} of type {@link Quest} of all registered quests. + * @return the description, or null if not specified */ - public final @NotNull Set<Quest> getRegisteredQuests() { - return Collections.unmodifiableSet(this.quests); + @Contract(pure = true) + public final @Nullable String getDescription() { + return this.description; } /** - * Returns the type of this task type. + * Returns an unmodifiable list of aliases for this task type. * - * @return the type of this task type + * @return an unmodifiable list of aliases */ - public final @NotNull String getType() { - return this.type; + @Contract(pure = true) + public final @Unmodifiable List<String> getAliases() { + return this.aliases; } /** - * Returns the author of this task type. + * Returns an unmodifiable view of the list of configuration validators for this task type. * - * @return the author of this task type, or null if not specified + * @return an unmodifiable view of the configuration validators */ - public final @Nullable String getAuthor() { - return this.author; + @Contract(pure = true) + public @UnmodifiableView List<ConfigValidator> getConfigValidators() { + return Collections.unmodifiableList(this.configValidators); } /** - * Returns the description of this task type. + * Adds a configuration validator to this task type. * - * @return the description of this task type, or null if not specified + * @param validator the configuration validator to add; must not be null */ - public final @Nullable String getDescription() { - return this.description; + public void addConfigValidator(final ConfigValidator validator) { + Objects.requireNonNull(validator, "validator cannot be null"); + + this.configValidators.add(validator); } /** - * Returns the aliases of this task type. + * Returns an unmodifiable list of all registered quests for this task type. * - * @return a set of aliases of this task type + * @return an unmodifiable list of registered quests */ - public final @NotNull Set<String> getAliases() { - return this.aliases; + @Contract(pure = true) + public final @UnmodifiableView List<Quest> getRegisteredQuests() { + return Collections.unmodifiableList(this.quests); } /** - * Called when Quests has finished registering all quests to the task type. - * May be called several times if an operator uses /quests admin reload. + * Registers a quest to this task type. This is typically done when + * all quests are initially loaded. + * + * @param quest the quest to register; must not be null */ - public void onReady() { - // not implemented here + public final void registerQuest(final Quest quest) { + Objects.requireNonNull(quest, "quest cannot be null"); + + if (!this.quests.contains(quest)) { + this.quests.add(quest); + } } /** - * Called when a player starts a quest containing a task of this type. - * - * @param quest the quest containing the task - * @param task the task being started - * @param playerUUID the UUID of the player starting the task + * Clears all registered quests from this task type. */ - public void onStart(final @NotNull Quest quest, final @NotNull Task task, final @NotNull UUID playerUUID) { - // not implemented here + public final void unregisterAll() { + this.quests.clear(); } /** - * Called when a task type is disabled. + * Called when all quests have been registered to this task type. + * This method may be called multiple times if an operator uses + * the /quests admin reload command. */ - public void onDisable() { - // not implemented here + public void onReady() { + // Not implemented here } /** - * Adds a config validator to this task type. + * Called when a player starts a quest that contains a task of this type. * - * @param validator the config validator to add + * @param quest the quest being started + * @param task the task being started + * @param playerUUID the UUID of the player starting the quest */ - public void addConfigValidator(final @NotNull ConfigValidator validator) { - Objects.requireNonNull(validator, "validator cannot be null"); - - this.configValidators.add(validator); + public void onStart(final Quest quest, final Task task, final UUID playerUUID) { + // Not implemented here } /** - * Returns an immutable set of config validators. - * - * @return an immutable set of config validators + * Called when this task type is disabled. */ - public @NotNull Set<ConfigValidator> getConfigValidators() { - return Collections.unmodifiableSet(this.configValidators); + public void onDisable() { + // Not implemented here } /** - * A functional interface for config validation. + * A functional interface for validating task configuration. */ @FunctionalInterface public interface ConfigValidator { /** - * Validates the configuration of a task. + * Validates the configuration for a task. * - * @param taskConfig the configuration of the task - * @param problems the set of problems to report validation issues + * @param taskConfig the configuration map for the task + * @param problems a list to collect any configuration problems found */ - void validateConfig(final @NotNull Map<String, Object> taskConfig, final @NotNull Set<ConfigProblem> problems); + void validateConfig(Map<String, Object> taskConfig, List<ConfigProblem> problems); } } 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 index c8aee763..f3f5ddd6 100644 --- a/common/src/main/java/com/leonardobishop/quests/common/tasktype/TaskTypeManager.java +++ b/common/src/main/java/com/leonardobishop/quests/common/tasktype/TaskTypeManager.java @@ -2,12 +2,17 @@ package com.leonardobishop.quests.common.tasktype; import com.leonardobishop.quests.common.quest.Quest; import com.leonardobishop.quests.common.quest.Task; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.leonardobishop.quests.common.util.Modern; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Unmodifiable; +import org.jetbrains.annotations.UnmodifiableView; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -16,11 +21,13 @@ import java.util.function.BooleanSupplier; import java.util.function.Supplier; /** - * The task type manager stores all registered task types and registers individual quests to each task type. - * Task types can only be registered if registrations are enabled, which is typically only during start-up. - * This is to ensure quests are only registered to task types when all task types have been registered first. + * Manages the registration and handling of task types within the quest system. + * The TaskTypeManager stores all registered task types and associates individual quests with each task type. + * Task types can only be registered when registrations are enabled, typically during the startup phase. + * This ensures that quests are only registered to task types after all task types have been registered. */ -@SuppressWarnings("UnusedReturnValue") +@Modern(type = Modern.Type.FULL) +@NullMarked public abstract class TaskTypeManager { private final Set<String> exclusions; @@ -34,12 +41,12 @@ public abstract class TaskTypeManager { /** * Constructs a TaskTypeManager with a specified set of exclusions. * - * @param exclusions a set of task type names to exclude from registration + * @param exclusions a collection of task type names to exclude from registration; must not be null */ - public TaskTypeManager(final @NotNull Set<String> exclusions) { + public TaskTypeManager(final Collection<String> exclusions) { Objects.requireNonNull(exclusions, "exclusions cannot be null"); - this.exclusions = exclusions; + this.exclusions = Set.copyOf(exclusions); this.taskTypes = new HashMap<>(); this.aliases = new HashMap<>(); this.registrationsOpen = true; @@ -50,38 +57,39 @@ public abstract class TaskTypeManager { /** * Constructs a TaskTypeManager with an empty set of exclusions. - * Use this constructor when no exclusions are needed. */ public TaskTypeManager() { this(Set.of()); } /** - * Returns an immutable set containing all task type exclusions. + * Returns an unmodifiable set containing task type exclusions. * - * @return immutable {@link Set} containing all task type exclusions + * @return an unmodifiable set of task type exclusions */ - @SuppressWarnings("unused") - public @NotNull Set<String> getExclusions() { - return Collections.unmodifiableSet(this.exclusions); + @Contract(pure = true) + public @Unmodifiable Set<String> getExclusions() { + return this.exclusions; } /** - * Returns an immutable collection containing all registered task types. + * Returns an unmodifiable collection of registered {@link TaskType} instances. * - * @return immutable {@link Set} containing all registered {@link TaskType} + * @return an unmodifiable collection of registered task types */ - public @NotNull Collection<TaskType> getTaskTypes() { + @Contract(pure = true) + public @UnmodifiableView Collection<TaskType> getTaskTypes() { return Collections.unmodifiableCollection(this.taskTypes.values()); } /** - * Gets a registered task type by type. + * Retrieves a registered {@link TaskType} by its type name. * - * @param type the type to check - * @return the {@link TaskType} if found, null otherwise + * @param type the type name of the task type to retrieve; must not be null + * @return the registered task type, or null if not found */ - public @Nullable TaskType getTaskType(final @NotNull String type) { + @Contract(pure = true) + public @Nullable TaskType getTaskType(final String type) { Objects.requireNonNull(type, "type cannot be null"); final TaskType taskType = this.taskTypes.get(type); @@ -98,12 +106,13 @@ public abstract class TaskTypeManager { } /** - * Gets the actual name of a task type, following aliases. + * Resolves the actual name of a registered {@link TaskType}, considering aliases. * - * @param type name of task type - * @return the actual name of the task type, or null if not found + * @param type the type name or alias of the task type to resolve; must not be null + * @return the actual name of the registered task type, or null if not found */ - public @Nullable String resolveTaskTypeName(final @NotNull String type) { + @Contract(pure = true) + public @Nullable String resolveTaskTypeName(final String type) { Objects.requireNonNull(type, "type cannot be null"); return this.taskTypes.containsKey(type) @@ -112,12 +121,12 @@ public abstract class TaskTypeManager { } /** - * Registers a task type with the task type manager. + * Registers a {@link TaskType} with the task type manager. * - * @param taskType the task type to register - * @return true if the task type was successfully registered, false otherwise + * @param taskType the task type to be registered; must not be null + * @return whether the task type was successfully registered */ - public boolean registerTaskType(final @NotNull TaskType taskType) { + public boolean registerTaskType(final TaskType taskType) { Objects.requireNonNull(taskType, "taskType cannot be null"); if (!this.registrationsOpen) { @@ -125,7 +134,7 @@ public abstract class TaskTypeManager { } final String type = taskType.getType(); - final Set<String> aliases = taskType.getAliases(); + final List<String> aliases = taskType.getAliases(); if (this.exclusions.contains(type) || this.taskTypes.containsKey(type) || !Collections.disjoint(this.exclusions, aliases) @@ -145,13 +154,13 @@ public abstract class TaskTypeManager { } /** - * Registers a task type with the task type manager using suppliers. + * Registers a {@link TaskType} using a supplier and compatibility checks. * - * @param taskTypeSupplier supplier of the task type to register - * @param compatibilitySuppliers suppliers to check for task type compatibility - * @return true if the task type was successfully registered, false otherwise + * @param taskTypeSupplier a supplier that provides the task type to register; must not be null + * @param compatibilitySuppliers suppliers that check for task type compatibility; must not be null + * @return whether the task type was successfully registered */ - public boolean registerTaskType(final @NotNull Supplier<TaskType> taskTypeSupplier, final @NotNull BooleanSupplier @NotNull ... compatibilitySuppliers) { + public boolean registerTaskType(final Supplier<TaskType> taskTypeSupplier, final BooleanSupplier... compatibilitySuppliers) { Objects.requireNonNull(taskTypeSupplier, "taskTypeSupplier cannot be null"); Objects.requireNonNull(compatibilitySuppliers, "compatibilitySuppliers cannot be null"); @@ -170,77 +179,90 @@ public abstract class TaskTypeManager { } /** - * Closes the task type registrations. This is typically done after start-up. + * Registers a quest with its associated task types. This will register the quest to each task type it contains. + * + * @param quest the quest to register; must not be null */ - public void closeRegistrations() { - this.registrationsOpen = false; + public void registerQuestTasksWithTaskTypes(final Quest quest) { + Objects.requireNonNull(quest, "quest cannot be null"); + + if (this.registrationsOpen) { + throw new IllegalStateException("Still accepting new task types (type registrations must be closed before registering quests)"); + } + + for (final Task task : quest.getTasks()) { + final TaskType taskType = this.getTaskType(task.getType()); + + if (taskType != null) { + taskType.registerQuest(quest); + } + } } /** - * Checks if registrations are still open. + * Resets all quest-to-task type registrations. This does not clear the task types registered with the task type manager. + */ + public void resetTaskTypes() { + for (final TaskType taskType : this.taskTypes.values()) { + taskType.unregisterAll(); + } + } + + /** + * Checks if task type registrations are still open. * * @return true if registrations are open, false otherwise */ + @Contract(pure = true) public boolean areRegistrationsOpen() { return this.registrationsOpen; } /** - * Returns the number of task types registered. + * Closes the task type registrations. This is typically done after the startup phase. + */ + public void closeRegistrations() { + this.registrationsOpen = false; + } + + /** + * Returns the number of task types that have been registered. * - * @return number of task types registered + * @return the count of registered task types */ + @Contract(pure = true) public int getRegistered() { return this.registered; } /** - * Returns the number of task types skipped due to exclusions or name conflicts. + * Returns the number of task types that were skipped due to exclusions or name conflicts. * - * @return number of task types skipped + * @return the count of skipped task types */ + @Contract(pure = true) public int getSkipped() { return this.skipped; } /** - * Returns the number of task types skipped due to failing to meet specified requirements. + * Returns the number of task types that were skipped due to failing to meet specified requirements. * - * @return number of task types skipped due to failing to meet specified requirements + * @return the count of unsupported task types */ + @Contract(pure = true) public int getUnsupported() { return this.unsupported; } /** - * Registers a quest with its task types. This will register the quest to each task type it contains. + * Sends a debug message. * - * @param quest the quest to register - */ - public void registerQuestTasksWithTaskTypes(final @NotNull Quest quest) { - Objects.requireNonNull(quest, "quest cannot be null"); - - if (this.registrationsOpen) { - throw new IllegalStateException("Still accepting new task types (type registrations must be closed before registering quests)"); - } - - for (final Task task : quest.getTasks()) { - final TaskType taskType = this.getTaskType(task.getType()); - - if (taskType != null) { - taskType.registerQuest(quest); - } - } - } - - /** - * Resets all quest to task type registrations. This does not clear the task types registered to the task type manager. + * @param message the debug message to send + * @param taskType the name of the task type associated with the message + * @param questId the ID of the quest associated with the message + * @param taskId the ID of the task associated with the message + * @param associatedPlayer the UUID of the player associated with the message */ - public void resetTaskTypes() { - for (final TaskType taskType : this.taskTypes.values()) { - taskType.unregisterAll(); - } - } - - public abstract void sendDebug(final @NotNull String message, final @NotNull String taskType, final @NotNull String questId, final @NotNull String taskId, final @NotNull UUID associatedPlayer); + public abstract void sendDebug(final String message, final String taskType, final String questId, final String taskId, final UUID associatedPlayer); } diff --git a/common/src/main/java/com/leonardobishop/quests/common/util/Modern.java b/common/src/main/java/com/leonardobishop/quests/common/util/Modern.java new file mode 100644 index 00000000..a607e575 --- /dev/null +++ b/common/src/main/java/com/leonardobishop/quests/common/util/Modern.java @@ -0,0 +1,21 @@ +package com.leonardobishop.quests.common.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to mark classes which have been rewritten to meet project revamp requirements. + */ +@Retention(value = RetentionPolicy.SOURCE) +@Target(value = ElementType.TYPE) +public @interface Modern { + + Type type(); + + enum Type { + FULL, + PARTIAL + } +} diff --git a/docs/task-types/farming-(task-type).md b/docs/task-types/farming-(task-type).md index f47c28dc..4bc09076 100644 --- a/docs/task-types/farming-(task-type).md +++ b/docs/task-types/farming-(task-type).md @@ -63,7 +63,7 @@ farmingmultiple: amount: 10 # amount of blocks to be placed blocks: # name of blocks which will count towards progress - WHEAT - - BEETROOT + - BEETROOTS worlds: # (OPTIONAL) restrict to certain worlds - "world" ``` |
