diff options
| author | LMBishop <13875753+LMBishop@users.noreply.github.com> | 2021-02-02 17:30:35 +0000 |
|---|---|---|
| committer | LMBishop <13875753+LMBishop@users.noreply.github.com> | 2021-02-02 17:30:35 +0000 |
| commit | 0d39c4c93c702724fa194755c4e50459364e58e4 (patch) | |
| tree | 973314568eb47d72b165021b57eb7c030af4fdbf /src | |
| parent | fe0f5605d8aec1448ae55ac61522598a19a0e6e2 (diff) | |
Add command to clean quest progress files & option to do it on join
- 'Clean' as in remove any references to quests which have been deleted in the config.
- Closes #126
Diffstat (limited to 'src')
10 files changed, 141 insertions, 21 deletions
diff --git a/src/main/java/com/leonardobishop/quests/Quests.java b/src/main/java/com/leonardobishop/quests/Quests.java index 9a6120c0..8b201b77 100644 --- a/src/main/java/com/leonardobishop/quests/Quests.java +++ b/src/main/java/com/leonardobishop/quests/Quests.java @@ -31,7 +31,6 @@ import org.bukkit.scheduler.BukkitTask; import java.io.*; import java.util.ArrayList; -import java.util.Map; public class Quests extends JavaPlugin { @@ -181,7 +180,7 @@ public class Quests extends JavaPlugin { // } for (Player player : Bukkit.getOnlinePlayers()) { - qPlayerManager.loadPlayer(player.getUniqueId(), false); + qPlayerManager.loadPlayer(player.getUniqueId()); } }); diff --git a/src/main/java/com/leonardobishop/quests/commands/CommandQuests.java b/src/main/java/com/leonardobishop/quests/commands/CommandQuests.java index b37e14ec..4393d785 100644 --- a/src/main/java/com/leonardobishop/quests/commands/CommandQuests.java +++ b/src/main/java/com/leonardobishop/quests/commands/CommandQuests.java @@ -21,6 +21,11 @@ import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; import java.util.*; public class CommandQuests implements TabExecutor { @@ -99,6 +104,41 @@ public class CommandQuests implements TabExecutor { showAdminHelp(sender, "opengui"); return true; } else if (args[1].equalsIgnoreCase("moddata")) { + if (args[2].equalsIgnoreCase("clean")) { + FileVisitor<Path> fileVisitor = new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attributes) { + File playerDataFile = new File(path.toUri()); + if (!playerDataFile.getName().toLowerCase().endsWith(".yml")) return FileVisitResult.CONTINUE; + String uuidStr = playerDataFile.getName().replace(".yml", ""); + UUID uuid; + try { + uuid = UUID.fromString(uuidStr); + } catch (IllegalArgumentException ex) { + return FileVisitResult.CONTINUE; + } + + plugin.getPlayerManager().loadPlayer(uuid); + QPlayer qPlayer = plugin.getPlayerManager().getPlayer(uuid); + qPlayer.getQuestProgressFile().clean(); + qPlayer.getQuestProgressFile().saveToDisk(false, true); + if (Bukkit.getPlayer(uuid) == null) { + plugin.getPlayerManager().dropPlayer(uuid); + } + return FileVisitResult.CONTINUE; + } + }; + //TODO command to clean specific player + try { + Files.walkFileTree(Paths.get(plugin.getDataFolder() + File.separator + "playerdata"), fileVisitor); + } catch (IOException e) { + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_CLEAN_FAIL.getMessage()); + e.printStackTrace(); + return true; + } + sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_CLEAN_SUCCESS.getMessage()); + return true; + } showAdminHelp(sender, "moddata"); return true; } else if (args[1].equalsIgnoreCase("types")) { @@ -151,7 +191,7 @@ public class CommandQuests implements TabExecutor { QPlayer qPlayer = plugin.getPlayerManager().getPlayer(uuid); if (qPlayer == null) { sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_LOADDATA.getMessage().replace("{player}", name)); - plugin.getPlayerManager().loadPlayer(uuid, false); + plugin.getPlayerManager().loadPlayer(uuid); qPlayer = plugin.getPlayerManager().getPlayer(uuid); //get again } if (qPlayer == null) { @@ -161,6 +201,9 @@ public class CommandQuests implements TabExecutor { QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile(); questProgressFile.clear(); questProgressFile.saveToDisk(false); + if (Bukkit.getPlayer(uuid) == null) { + plugin.getPlayerManager().dropPlayer(uuid); + } sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_FULLRESET.getMessage().replace("{player}", name)); return true; } @@ -211,7 +254,7 @@ public class CommandQuests implements TabExecutor { QPlayer qPlayer = plugin.getPlayerManager().getPlayer(uuid); if (qPlayer == null) { sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_LOADDATA.getMessage().replace("{player}", name)); - plugin.getPlayerManager().loadPlayer(uuid, false); + plugin.getPlayerManager().loadPlayer(uuid); } if (qPlayer == null) { sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_NODATA.getMessage().replace("{player}", name)); @@ -266,6 +309,9 @@ public class CommandQuests implements TabExecutor { if (!success) { showAdminHelp(sender, "moddata"); } + if (Bukkit.getPlayer(uuid) == null) { + plugin.getPlayerManager().dropPlayer(uuid); + } return true; } } @@ -406,12 +452,14 @@ public class CommandQuests implements TabExecutor { sender.sendMessage(ChatColor.GRAY + "The following commands are available: "); sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata fullreset <player> " + ChatColor.DARK_GRAY + ": clear a " + "players quest data file"); - sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata reset <player> <questid>" + ChatColor.DARK_GRAY + ": clear a " + + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata reset <player> <questid> " + ChatColor.DARK_GRAY + ": clear a " + "players data for specifc quest"); - sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata start <player> <questid>" + ChatColor.DARK_GRAY + ": start a " + + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata start <player> <questid> " + ChatColor.DARK_GRAY + ": start a " + "quest for a player"); - sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata complete <player> <questid>" + ChatColor.DARK_GRAY + ": " + + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata complete <player> <questid> " + ChatColor.DARK_GRAY + ": " + "complete a quest for a player"); + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata clean " + ChatColor.DARK_GRAY + ": " + + "clean quest data files for quests which are no longer defined"); sender.sendMessage(ChatColor.GRAY + "These commands modify quest progress for players. Use them cautiously. Changes are irreversible."); } else { sender.sendMessage(ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH + "------------=[" + ChatColor.RED + " Quests Admin " + ChatColor.GRAY @@ -491,7 +539,7 @@ public class CommandQuests implements TabExecutor { List<String> options = Arrays.asList("quests", "category"); return matchTabComplete(args[2], options); } else if (args[1].equalsIgnoreCase("moddata")) { - List<String> options = Arrays.asList("fullreset", "reset", "start", "complete"); + List<String> options = Arrays.asList("fullreset", "reset", "start", "complete", "clean"); return matchTabComplete(args[2], options); } } diff --git a/src/main/java/com/leonardobishop/quests/events/EventPlayerJoin.java b/src/main/java/com/leonardobishop/quests/events/EventPlayerJoin.java index 322316b1..e193c5b2 100644 --- a/src/main/java/com/leonardobishop/quests/events/EventPlayerJoin.java +++ b/src/main/java/com/leonardobishop/quests/events/EventPlayerJoin.java @@ -2,6 +2,7 @@ package com.leonardobishop.quests.events; import com.leonardobishop.quests.Quests; import com.leonardobishop.quests.obj.Messages; +import com.leonardobishop.quests.obj.Options; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -20,7 +21,13 @@ public class EventPlayerJoin implements Listener { @EventHandler public void onEvent(PlayerJoinEvent event) { UUID playerUuid = event.getPlayer().getUniqueId(); - plugin.getPlayerManager().loadPlayer(playerUuid, false); + plugin.getPlayerManager().loadPlayer(playerUuid); + if (Options.SOFT_CLEAN_QUESTSPROGRESSFILE_ON_JOIN.getBooleanValue()) { + plugin.getPlayerManager().getPlayer(playerUuid).getQuestProgressFile().clean(); + if (Options.PUSH_SOFT_CLEAN_TO_DISK.getBooleanValue()) { + plugin.getPlayerManager().getPlayer(playerUuid).getQuestProgressFile().saveToDisk(false, true); + } + } if (plugin.getDescription().getVersion().contains("beta") && event.getPlayer().hasPermission("quests.admin")) { event.getPlayer().sendMessage(Messages.BETA_REMINDER.getMessage()); } diff --git a/src/main/java/com/leonardobishop/quests/obj/Messages.java b/src/main/java/com/leonardobishop/quests/obj/Messages.java index b3c9ceab..92a0dca9 100644 --- a/src/main/java/com/leonardobishop/quests/obj/Messages.java +++ b/src/main/java/com/leonardobishop/quests/obj/Messages.java @@ -36,6 +36,8 @@ public enum Messages { BETA_REMINDER("messages.beta-reminder"), COMMAND_QUEST_ADMIN_LOADDATA("messages.command-quest-admin-loaddata"), COMMAND_QUEST_ADMIN_NODATA("messages.command-quest-admin-nodata"), + COMMAND_QUEST_ADMIN_CLEAN_SUCCESS("messages.command-quest-admin-clean-success"), + COMMAND_QUEST_ADMIN_CLEAN_FAIL("messages.command-quest-admin-clean-fail"), COMMAND_QUEST_ADMIN_FULLRESET("messages.command-quest-admin-fullreset"), COMMAND_QUEST_ADMIN_START_FAILLOCKED("messages.command-quest-admin-start-faillocked"), COMMAND_QUEST_ADMIN_START_FAILCOOLDOWN("messages.command-quest-admin-start-failcooldown"), diff --git a/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java b/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java index 364868f4..d6bf631d 100644 --- a/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java +++ b/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java @@ -44,7 +44,7 @@ public class QPlayerManager { QPlayer qPlayer = qPlayers.get(uuid); if (qPlayer == null && loadIfNull) { plugin.getQuestsLogger().debug("QPlayer of " + uuid + " is null, but was requested! Attempting to load it."); - loadPlayer(uuid, false); + loadPlayer(uuid); return getPlayer(uuid, false); } return qPlayers.get(uuid); @@ -52,7 +52,12 @@ public class QPlayerManager { public void removePlayer(UUID uuid) { this.getPlayer(uuid).getQuestProgressFile().saveToDisk(false); - plugin.getQuestsLogger().debug("Unloading player " + uuid + "."); + plugin.getQuestsLogger().debug("Unloading and saving player " + uuid + "."); + qPlayers.remove(uuid); + } + + public void dropPlayer(UUID uuid) { + plugin.getQuestsLogger().debug("Dropping player " + uuid + "."); qPlayers.remove(uuid); } @@ -65,8 +70,7 @@ public class QPlayerManager { // loadPlayer(uuid, false); //} - // TODO redo "onlyData" and use a less confusing way - public void loadPlayer(UUID uuid, boolean onlyData) { + public void loadPlayer(UUID uuid) { plugin.getQuestsLogger().debug("Loading player " + uuid + " from disk."); if (getPlayer(uuid) == null) { QuestProgressFile questProgressFile = new QuestProgressFile(uuid, plugin); @@ -86,12 +90,14 @@ public class QPlayerManager { QuestProgress questProgress = new QuestProgress(id, completed, completedBefore, completionDate, uuid, started, true); - for (String taskid : data.getConfigurationSection("quest-progress." + id + ".task-progress").getKeys(false)) { - boolean taskCompleted = data.getBoolean("quest-progress." + id + ".task-progress." + taskid + ".completed"); - Object taskProgression = data.get("quest-progress." + id + ".task-progress." + taskid + ".progress"); + if (data.isConfigurationSection("quest.progress." + id + ".task-progress")) { + for (String taskid : data.getConfigurationSection("quest-progress." + id + ".task-progress").getKeys(false)) { + boolean taskCompleted = data.getBoolean("quest-progress." + id + ".task-progress." + taskid + ".completed"); + Object taskProgression = data.get("quest-progress." + id + ".task-progress." + taskid + ".progress"); - TaskProgress taskProgress = new TaskProgress(taskid, taskProgression, uuid, taskCompleted, false); - questProgress.addTaskProgress(taskProgress); + TaskProgress taskProgress = new TaskProgress(taskid, taskProgression, uuid, taskCompleted, false); + questProgress.addTaskProgress(taskProgress); + } } questProgressFile.addQuestProgress(questProgress); diff --git a/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgress.java b/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgress.java index fe9108ce..ab9096a6 100644 --- a/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgress.java +++ b/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgress.java @@ -82,6 +82,10 @@ public class QuestProgress { return taskProgress.values(); } + public Map<String, TaskProgress> getTaskProgressMap() { + return taskProgress; + } + public TaskProgress getTaskProgress(String taskId) { TaskProgress tP = taskProgress.getOrDefault(taskId, null); if (tP == null) { diff --git a/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgressFile.java b/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgressFile.java index d3689185..242c454b 100644 --- a/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgressFile.java +++ b/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgressFile.java @@ -379,7 +379,15 @@ public class QuestProgressFile { return false; } + public void saveToDisk() { + saveToDisk(false, false); + } + public void saveToDisk(boolean disable) { + saveToDisk(disable, false); + } + + public void saveToDisk(boolean disable, boolean fullWrite) { plugin.getQuestsLogger().debug("Saving player " + playerUUID + " to disk."); File directory = new File(plugin.getDataFolder() + File.separator + "playerdata"); if (!directory.exists() && !directory.isDirectory()) { @@ -395,9 +403,11 @@ public class QuestProgressFile { } YamlConfiguration data = YamlConfiguration.loadConfiguration(file); - //data.set("quest-progress", null); + if (fullWrite) { + data.set("quest-progress", null); + } for (QuestProgress questProgress : questProgress.values()) { - if (!questProgress.isWorthSaving()) { + if (!questProgress.isWorthSaving() && !fullWrite) { continue; } data.set("quest-progress." + questProgress.getQuestId() + ".started", questProgress.isStarted()); @@ -433,4 +443,32 @@ public class QuestProgressFile { questProgress.clear(); } + /** + * Removes any references to quests or tasks which are no longer defined in the config + */ + public void clean() { + if (!plugin.getTaskTypeManager().areRegistrationsAccepted()) { + ArrayList<String> invalidQuests = new ArrayList<>(); + for (String questId : this.questProgress.keySet()) { + Quest q; + if ((q = plugin.getQuestManager().getQuestById(questId)) == null) { + invalidQuests.add(questId); + } else { + ArrayList<String> invalidTasks = new ArrayList<>(); + for (String taskId : this.questProgress.get(questId).getTaskProgressMap().keySet()) { + if (q.getTaskById(taskId) == null) { + invalidTasks.add(taskId); + } + } + for (String taskId : invalidTasks) { + this.questProgress.get(questId).getTaskProgressMap().remove(taskId); + } + } + } + for (String questId : invalidQuests) { + this.questProgress.remove(questId); + } + } + } + } diff --git a/src/main/java/com/leonardobishop/quests/quests/Quest.java b/src/main/java/com/leonardobishop/quests/quests/Quest.java index ab02bd19..36429637 100644 --- a/src/main/java/com/leonardobishop/quests/quests/Quest.java +++ b/src/main/java/com/leonardobishop/quests/quests/Quest.java @@ -8,7 +8,7 @@ import java.util.*; public class Quest implements Comparable<Quest> { private Map<String, Task> tasks = new HashMap<>(); - //TODO: maybe store by <tasktypename (string), list<task>> since we never get task by id, but always get tasks by type. + //TODO: maybe ALSO store by <tasktypename (string), list<task>> private final String id; private final QItemStack displayItem; private final List<String> rewards; @@ -50,6 +50,10 @@ public class Quest implements Comparable<Quest> { return tasks.values(); } + public Task getTaskById(String id) { + return tasks.get(id); + } + public List<Task> getTasksOfType(String type) { List<Task> tasks = new ArrayList<>(); for (Task task : getTasks()) { diff --git a/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskTypeManager.java b/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskTypeManager.java index 7b01d463..465ee527 100644 --- a/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskTypeManager.java +++ b/src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskTypeManager.java @@ -21,6 +21,10 @@ public class TaskTypeManager { allowRegistrations = false; } + public boolean areRegistrationsAccepted() { + return allowRegistrations; + } + private ArrayList<TaskType> taskTypes = new ArrayList<>(); public ArrayList<TaskType> getTaskTypes() { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b5ed99ef..21a7ec83 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -155,6 +155,12 @@ options: quest-autostart: false # How much quests should log, 0 = errors only, 1 = warnings, 2 = info, 3 = debug verbose-logging-level: 2 + # Automatically clean player's quest progress files when they join. + # These changes will not be reflected to disk. + # Useful if you frequently add and remove quests on a production server. Equivalent of executing /q a moddata clean, without overwriting the file. + soft-clean-questsprogressfile-on-join: false + # The above, but overwriting the file on disk with the cleaned version, so it does not soft clean on every join. + push-soft-clean-to-disk: false performance-tweaking: # The following are measured in server ticks, multiply SECONDS by 20 to get the number of ticks. quest-completer-poll-interval: 100 # how frequently Quests should check if quests have been completed (def=100 - 5 seconds) - increase this value if you are struggling with performance quest-autosave-interval: 12000 # how frequently online players data will be autosaved (def=12000 - 10 minutes) @@ -215,6 +221,8 @@ messages: command-quest-admin-loaddata: "&7Quest data for '&c{player}&7' is being loaded." command-quest-admin-nodata: "&7No data could be found for player &c{player}&7." command-quest-admin-fullreset: "&7Data for player &c{player}&7 has been fully reset." + command-quest-admin-clean-success: "&7All quest progress files have been cleaned." + command-quest-admin-clean-fail: "&cFailed to clean quest progress files. Please report the error in the console." command-quest-admin-start-faillocked: "&7Quest '&c{quest}&7' could not be started for player &c{player}&7. They have not yet unlocked it." command-quest-admin-start-failcooldown: "&7Quest '&c{quest}&7' could not be started for player &c{player}&7. It is still on cooldown for them." command-quest-admin-start-failcomplete: "&7Quest '&c{quest}&7' could not be started for player &c{player}&7. They have already completed it." |
