summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/leonardobishop/quests/Quests.java3
-rw-r--r--src/main/java/com/leonardobishop/quests/commands/CommandQuests.java60
-rw-r--r--src/main/java/com/leonardobishop/quests/events/EventPlayerJoin.java9
-rw-r--r--src/main/java/com/leonardobishop/quests/obj/Messages.java2
-rw-r--r--src/main/java/com/leonardobishop/quests/player/QPlayerManager.java24
-rw-r--r--src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgress.java4
-rw-r--r--src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgressFile.java42
-rw-r--r--src/main/java/com/leonardobishop/quests/quests/Quest.java6
-rw-r--r--src/main/java/com/leonardobishop/quests/quests/tasktypes/TaskTypeManager.java4
-rw-r--r--src/main/resources/config.yml8
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."