From 0d39c4c93c702724fa194755c4e50459364e58e4 Mon Sep 17 00:00:00 2001 From: LMBishop <13875753+LMBishop@users.noreply.github.com> Date: Tue, 2 Feb 2021 17:30:35 +0000 Subject: 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 --- .../java/com/leonardobishop/quests/Quests.java | 3 +- .../quests/commands/CommandQuests.java | 60 +++++++++++++++++++--- .../quests/events/EventPlayerJoin.java | 9 +++- .../com/leonardobishop/quests/obj/Messages.java | 2 + .../quests/player/QPlayerManager.java | 24 +++++---- .../player/questprogressfile/QuestProgress.java | 4 ++ .../questprogressfile/QuestProgressFile.java | 42 ++++++++++++++- .../com/leonardobishop/quests/quests/Quest.java | 6 ++- .../quests/quests/tasktypes/TaskTypeManager.java | 4 ++ 9 files changed, 133 insertions(+), 21 deletions(-) (limited to 'src/main/java/com') 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 fileVisitor = new SimpleFileVisitor() { + @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 " + ChatColor.DARK_GRAY + ": clear a " + "players quest data file"); - sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata reset " + ChatColor.DARK_GRAY + ": clear a " + + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata reset " + ChatColor.DARK_GRAY + ": clear a " + "players data for specifc quest"); - sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata start " + ChatColor.DARK_GRAY + ": start a " + + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata start " + ChatColor.DARK_GRAY + ": start a " + "quest for a player"); - sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata complete " + ChatColor.DARK_GRAY + ": " + + sender.sendMessage(ChatColor.DARK_GRAY + " * " + ChatColor.RED + "/quests a moddata complete " + 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 options = Arrays.asList("quests", "category"); return matchTabComplete(args[2], options); } else if (args[1].equalsIgnoreCase("moddata")) { - List options = Arrays.asList("fullreset", "reset", "start", "complete"); + List 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 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 invalidQuests = new ArrayList<>(); + for (String questId : this.questProgress.keySet()) { + Quest q; + if ((q = plugin.getQuestManager().getQuestById(questId)) == null) { + invalidQuests.add(questId); + } else { + ArrayList invalidTasks = new ArrayList<>(); + for (String taskId : this.questProgress.get(questId).getTaskProgressMap().keySet()) { + if (q.getTaskById(taskId) == null) { + invalidTasks.add(taskId); + } + } + for (String taskId : invalidTasks) { + this.questProgress.get(questId).getTaskProgressMap().remove(taskId); + } + } + } + for (String questId : invalidQuests) { + this.questProgress.remove(questId); + } + } + } + } 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 { private Map tasks = new HashMap<>(); - //TODO: maybe store by > since we never get task by id, but always get tasks by type. + //TODO: maybe ALSO store by > private final String id; private final QItemStack displayItem; private final List rewards; @@ -50,6 +50,10 @@ public class Quest implements Comparable { return tasks.values(); } + public Task getTaskById(String id) { + return tasks.get(id); + } + public List getTasksOfType(String type) { List tasks = new ArrayList<>(); for (Task task : getTasks()) { 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 taskTypes = new ArrayList<>(); public ArrayList getTaskTypes() { -- cgit v1.2.3-70-g09d2