summaryrefslogtreecommitdiffstats
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/leonardobishop/quests/QuestCompleter.java3
-rw-r--r--src/main/java/com/leonardobishop/quests/Quests.java17
-rw-r--r--src/main/java/com/leonardobishop/quests/QuestsAutosaveRunnable.java3
-rw-r--r--src/main/java/com/leonardobishop/quests/api/QuestsPlaceholders.java1
-rw-r--r--src/main/java/com/leonardobishop/quests/command/QuestsCommand.java132
-rw-r--r--src/main/java/com/leonardobishop/quests/listener/PlayerJoinListener.java12
-rw-r--r--src/main/java/com/leonardobishop/quests/listener/PlayerLeaveListener.java3
-rw-r--r--src/main/java/com/leonardobishop/quests/player/QPlayer.java11
-rw-r--r--src/main/java/com/leonardobishop/quests/player/QPlayerManager.java85
-rw-r--r--src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgress.java5
-rw-r--r--src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgressFile.java10
-rw-r--r--src/main/java/com/leonardobishop/quests/player/questprogressfile/TaskProgress.java4
-rw-r--r--src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningCertainTaskType.java3
-rw-r--r--src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsBalanceTaskType.java3
-rw-r--r--src/main/java/com/leonardobishop/quests/storage/MySqlStorageProvider.java278
-rw-r--r--src/main/java/com/leonardobishop/quests/storage/StorageProvider.java2
-rw-r--r--src/main/java/com/leonardobishop/quests/storage/YamlStorageProvider.java13
-rw-r--r--src/main/java/com/leonardobishop/quests/util/Messages.java1
-rw-r--r--src/main/java/com/leonardobishop/quests/util/Options.java3
19 files changed, 473 insertions, 116 deletions
diff --git a/src/main/java/com/leonardobishop/quests/QuestCompleter.java b/src/main/java/com/leonardobishop/quests/QuestCompleter.java
index f31e5daa..d3ff8cf1 100644
--- a/src/main/java/com/leonardobishop/quests/QuestCompleter.java
+++ b/src/main/java/com/leonardobishop/quests/QuestCompleter.java
@@ -35,6 +35,8 @@ public class QuestCompleter implements Runnable {
Player player = Bukkit.getPlayer(questProgress.getPlayer());
if (player != null && player.isOnline()) {
QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId());
+ if (qPlayer == null) return;
+
Quest quest = plugin.getQuestManager().getQuestById(questProgress.getQuestId());
if (!qPlayer.hasStartedQuest(quest)) return;
@@ -52,6 +54,7 @@ public class QuestCompleter implements Runnable {
Player player = Bukkit.getPlayer(questProgressFile.getPlayerUUID());
if (player != null && player.isOnline()) {
QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId());
+ if (qPlayer == null) return;
for (QuestProgress questProgress : questProgressFile.getAllQuestProgress()) {
Quest quest = plugin.getQuestManager().getQuestById(questProgress.getQuestId());
if (quest == null) continue;
diff --git a/src/main/java/com/leonardobishop/quests/Quests.java b/src/main/java/com/leonardobishop/quests/Quests.java
index cab89f6a..6308f9de 100644
--- a/src/main/java/com/leonardobishop/quests/Quests.java
+++ b/src/main/java/com/leonardobishop/quests/Quests.java
@@ -166,14 +166,14 @@ public class Quests extends JavaPlugin {
questsLogger = new QuestsLogger(this, QuestsLogger.LoggingLevel.INFO);
questCompleter = new QuestCompleter(this);
+ this.generateConfigurations();
+ this.setupVersionSpecific();
+
taskTypeManager = new TaskTypeManager(this);
questManager = new QuestManager(this);
qPlayerManager = new QPlayerManager(this);
menuController = new MenuController(this);
- this.generateConfigurations();
- this.setupVersionSpecific();
-
super.getCommand("quests").setExecutor(new QuestsCommand(this));
Bukkit.getPluginManager().registerEvents(new PlayerJoinListener(this), this);
Bukkit.getPluginManager().registerEvents(menuController, this);
@@ -247,12 +247,6 @@ public class Quests extends JavaPlugin {
taskTypeManager.closeRegistrations();
reloadQuests();
-// if (!questsConfigLoader.getBrokenFiles().isEmpty()) {
-// this.getQuestsLogger().severe("Quests has failed to load the following files:");
-// for (Map.Entry<String, QuestsConfigLoader.ConfigLoadError> entry : questsConfigLoader.getBrokenFiles().entrySet()) {
-// this.getQuestsLogger().severe(" - " + entry.getKey() + ": " + entry.getValue().getMessage());
-// }
-// }
for (Player player : Bukkit.getOnlinePlayers()) {
qPlayerManager.loadPlayer(player.getUniqueId());
@@ -302,10 +296,13 @@ public class Quests extends JavaPlugin {
}
for (QPlayer qPlayer : qPlayerManager.getQPlayers()) {
try {
- qPlayerManager.savePlayer(qPlayer.getPlayerUUID());
+ qPlayerManager.savePlayerSync(qPlayer.getPlayerUUID());
} catch (Exception ignored) { }
}
if (placeholderAPIHook != null) placeholderAPIHook.unregisterExpansion();
+ try {
+ qPlayerManager.getStorageProvider().shutdown();
+ } catch (Exception ignored) { }
}
public void reloadQuests() {
diff --git a/src/main/java/com/leonardobishop/quests/QuestsAutosaveRunnable.java b/src/main/java/com/leonardobishop/quests/QuestsAutosaveRunnable.java
index c042fd32..eaa37d87 100644
--- a/src/main/java/com/leonardobishop/quests/QuestsAutosaveRunnable.java
+++ b/src/main/java/com/leonardobishop/quests/QuestsAutosaveRunnable.java
@@ -37,8 +37,7 @@ public class QuestsAutosaveRunnable extends BukkitRunnable {
}
if (Bukkit.getPlayer(player) != null) {
- QuestProgressFile clonedProgressFile = new QuestProgressFile(plugin.getPlayerManager().getPlayer(player).getQuestProgressFile());
- Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> plugin.getPlayerManager().savePlayer(player, clonedProgressFile));
+ plugin.getPlayerManager().savePlayer(player);
}
}
diff --git a/src/main/java/com/leonardobishop/quests/api/QuestsPlaceholders.java b/src/main/java/com/leonardobishop/quests/api/QuestsPlaceholders.java
index 9a402ed5..5c82cf6b 100644
--- a/src/main/java/com/leonardobishop/quests/api/QuestsPlaceholders.java
+++ b/src/main/java/com/leonardobishop/quests/api/QuestsPlaceholders.java
@@ -70,6 +70,7 @@ public class QuestsPlaceholders extends PlaceholderExpansion implements Cacheabl
if (save) args = Arrays.copyOf(args, args.length - 1);
final QPlayer qPlayer = plugin.getPlayerManager().getPlayer(p.getUniqueId());
+ if (qPlayer == null) return "Data not loaded";
String split = args[args.length - 1];
String result = "null";
diff --git a/src/main/java/com/leonardobishop/quests/command/QuestsCommand.java b/src/main/java/com/leonardobishop/quests/command/QuestsCommand.java
index 47aa050e..d18f977c 100644
--- a/src/main/java/com/leonardobishop/quests/command/QuestsCommand.java
+++ b/src/main/java/com/leonardobishop/quests/command/QuestsCommand.java
@@ -78,6 +78,10 @@ public class QuestsCommand implements TabExecutor {
if (args.length == 0 && sender instanceof Player) {
Player player = (Player) sender;
QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId());
+ if (qPlayer == null) {
+ player.sendMessage(Messages.COMMAND_DATA_NOT_LOADED.getMessage());
+ return true;
+ }
qPlayer.openQuests();
return true;
} else if (args.length >= 1) {
@@ -90,10 +94,11 @@ public class QuestsCommand implements TabExecutor {
showAdminHelp(sender, "moddata");
return true;
} else if (args[1].equalsIgnoreCase("reload")) {
+ sender.sendMessage(ChatColor.GRAY + "Please note that some options, such as storage, require a full restart for chances to take effect.");
plugin.reloadConfig();
plugin.reloadQuests();
- showProblems(sender);
- sender.sendMessage(ChatColor.GRAY + "Quests successfully reloaded.");
+ if (!plugin.getQuestsConfigLoader().getFilesWithProblems().isEmpty()) showProblems(sender);
+ sender.sendMessage(ChatColor.GREEN + "Quests successfully reloaded.");
return true;
} else if (args[1].equalsIgnoreCase("config")) {
showProblems(sender);
@@ -156,6 +161,7 @@ public class QuestsCommand implements TabExecutor {
showAdminHelp(sender, "opengui");
return true;
} else if (args[1].equalsIgnoreCase("moddata")) {
+ // TODO remove me
if (args[2].equalsIgnoreCase("clean")) {
FileVisitor<Path> fileVisitor = new SimpleFileVisitor<Path>() {
@Override
@@ -260,36 +266,16 @@ public class QuestsCommand implements TabExecutor {
showAdminHelp(sender, "opengui");
return true;
} else if (args[1].equalsIgnoreCase("moddata")) {
- OfflinePlayer ofp = Bukkit.getOfflinePlayer(args[3]);
- UUID uuid;
- String name;
- // Player.class is a superclass for OfflinePlayer.
- // getofflinePlayer return a player regardless if exists or not
- if (ofp.hasPlayedBefore()) {
- uuid = ofp.getUniqueId();
- name = ofp.getName();
- } else {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_PLAYERNOTFOUND.getMessage().replace("{player}", args[3]));
- return true;
- }
+ QPlayer qPlayer = getOtherPlayer(sender, args[3]);
+ if (qPlayer == null) return true;
if (args[2].equalsIgnoreCase("fullreset")) {
- QPlayer qPlayer = plugin.getPlayerManager().getPlayer(uuid);
- if (qPlayer == null) {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_LOADDATA.getMessage().replace("{player}", name));
- plugin.getPlayerManager().loadPlayer(uuid);
- qPlayer = plugin.getPlayerManager().getPlayer(uuid); //get again
- }
- if (qPlayer == null) {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_NODATA.getMessage().replace("{player}", name));
- return true;
- }
QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile();
questProgressFile.clear();
- plugin.getPlayerManager().savePlayer(uuid, questProgressFile);
- if (Bukkit.getPlayer(uuid) == null) {
- plugin.getPlayerManager().dropPlayer(uuid);
+ plugin.getPlayerManager().savePlayerSync(qPlayer.getPlayerUUID(), questProgressFile);
+ if (Bukkit.getPlayer(qPlayer.getPlayerUUID()) == null) {
+ plugin.getPlayerManager().dropPlayer(qPlayer.getPlayerUUID());
}
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_FULLRESET.getMessage().replace("{player}", name));
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_FULLRESET.getMessage().replace("{player}", args[3]));
return true;
}
showAdminHelp(sender, "moddata");
@@ -326,26 +312,8 @@ public class QuestsCommand implements TabExecutor {
}
} else if (args[1].equalsIgnoreCase("moddata")) {
boolean success = false;
- OfflinePlayer ofp = Bukkit.getOfflinePlayer(args[3]);
- UUID uuid;
- String name;
- if (ofp.hasPlayedBefore()) {
- uuid = ofp.getUniqueId();
- name = ofp.getName();
- } else {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_PLAYERNOTFOUND.getMessage().replace("{player}", args[3]));
- return true;
- }
- QPlayer qPlayer = plugin.getPlayerManager().getPlayer(uuid);
- if (qPlayer == null) {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_LOADDATA.getMessage().replace("{player}", name));
- plugin.getPlayerManager().loadPlayer(uuid);
- }
- if (qPlayer == null) {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_NODATA.getMessage().replace("{player}", name));
- success = true;
- }
- qPlayer = plugin.getPlayerManager().getPlayer(uuid); //get again
+ QPlayer qPlayer = getOtherPlayer(sender, args[3]);
+ if (qPlayer == null) return true;
QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile();
Quest quest = plugin.getQuestManager().getQuestById(args[4]);
if (quest == null) {
@@ -355,47 +323,47 @@ public class QuestsCommand implements TabExecutor {
}
if (args[2].equalsIgnoreCase("reset")) {
questProgressFile.generateBlankQuestProgress(quest);
- plugin.getPlayerManager().savePlayer(uuid, questProgressFile);
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_RESET_SUCCESS.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ plugin.getPlayerManager().savePlayerSync(qPlayer.getPlayerUUID(), questProgressFile);
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_RESET_SUCCESS.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId()));
success = true;
} else if (args[2].equalsIgnoreCase("start")) {
QuestStartResult response = qPlayer.startQuest(quest);
if (response == QuestStartResult.QUEST_LIMIT_REACHED) {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILLIMIT.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILLIMIT.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId()));
return true;
} else if (response == QuestStartResult.QUEST_ALREADY_COMPLETED) {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILCOMPLETE.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILCOMPLETE.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId()));
return true;
} else if (response == QuestStartResult.QUEST_COOLDOWN) {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILCOOLDOWN.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILCOOLDOWN.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId()));
return true;
} else if (response == QuestStartResult.QUEST_LOCKED) {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILLOCKED.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILLOCKED.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId()));
return true;
} else if (response == QuestStartResult.QUEST_ALREADY_STARTED) {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILSTARTED.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILSTARTED.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId()));
return true;
} else if (response == QuestStartResult.QUEST_NO_PERMISSION) {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILPERMISSION.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILPERMISSION.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId()));
return true;
} else if (response == QuestStartResult.NO_PERMISSION_FOR_CATEGORY) {
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILCATEGORYPERMISSION.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_FAILCATEGORYPERMISSION.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId()));
return true;
}
- plugin.getPlayerManager().savePlayer(uuid, questProgressFile);
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_SUCCESS.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ plugin.getPlayerManager().savePlayerSync(qPlayer.getPlayerUUID(), questProgressFile);
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_START_SUCCESS.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId()));
success = true;
} else if (args[2].equalsIgnoreCase("complete")) {
qPlayer.completeQuest(quest);
- plugin.getPlayerManager().savePlayer(uuid, questProgressFile);
- sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_COMPLETE_SUCCESS.getMessage().replace("{player}", name).replace("{quest}", quest.getId()));
+ plugin.getPlayerManager().savePlayerSync(qPlayer.getPlayerUUID(), questProgressFile);
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_COMPLETE_SUCCESS.getMessage().replace("{player}", args[3]).replace("{quest}", quest.getId()));
success = true;
}
if (!success) {
showAdminHelp(sender, "moddata");
}
- if (Bukkit.getPlayer(uuid) == null) {
- plugin.getPlayerManager().dropPlayer(uuid);
+ if (Bukkit.getPlayer(qPlayer.getPlayerUUID()) == null) {
+ plugin.getPlayerManager().dropPlayer(qPlayer.getPlayerUUID());
}
return true;
}
@@ -409,7 +377,7 @@ public class QuestsCommand implements TabExecutor {
Quest quest = plugin.getQuestManager().getQuestById(args[1]);
QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId());
if (qPlayer == null) {
- sender.sendMessage(ChatColor.RED + "Your quest progress file has not been loaded yet.");
+ player.sendMessage(Messages.COMMAND_DATA_NOT_LOADED.getMessage());
return true;
}
if (quest == null) {
@@ -434,10 +402,14 @@ public class QuestsCommand implements TabExecutor {
Player player = (Player) sender;
if (args.length >= 2) {
Category category = plugin.getQuestManager().getCategoryById(args[1]);
+ QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId());
+ if (qPlayer == null) {
+ player.sendMessage(Messages.COMMAND_DATA_NOT_LOADED.getMessage());
+ return true;
+ }
if (category == null) {
sender.sendMessage(Messages.COMMAND_CATEGORY_OPEN_DOESNTEXIST.getMessage().replace("{category}", args[1]));
} else {
- QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId());
qPlayer.openCategory(category, null, false);
return true;
}
@@ -447,7 +419,7 @@ public class QuestsCommand implements TabExecutor {
Player player = (Player) sender;
QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId());
if (qPlayer == null) {
- sender.sendMessage(ChatColor.RED + "Your quest progress file has not been loaded yet.");
+ player.sendMessage(Messages.COMMAND_DATA_NOT_LOADED.getMessage());
return true;
}
List<Quest> validQuests = new ArrayList<>();
@@ -467,6 +439,10 @@ public class QuestsCommand implements TabExecutor {
} else if (sender instanceof Player && (args[0].equalsIgnoreCase("started"))) {
Player player = (Player) sender;
QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId());
+ if (qPlayer == null) {
+ player.sendMessage(Messages.COMMAND_DATA_NOT_LOADED.getMessage());
+ return true;
+ }
qPlayer.openStartedQuests();
return true;
}
@@ -477,6 +453,30 @@ public class QuestsCommand implements TabExecutor {
return true;
}
+ private QPlayer getOtherPlayer(CommandSender sender, String name) {
+ OfflinePlayer ofp = Bukkit.getOfflinePlayer(name);
+ UUID uuid;
+ String username;
+ if (ofp.hasPlayedBefore()) {
+ uuid = ofp.getUniqueId();
+ username = ofp.getName();
+ } else {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_PLAYERNOTFOUND.getMessage().replace("{player}", name));
+ return null;
+ }
+ QPlayer qPlayer = plugin.getPlayerManager().getPlayer(uuid);
+ if (qPlayer == null) {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_LOADDATA.getMessage().replace("{player}", username));
+ plugin.getPlayerManager().loadPlayer(uuid);
+ qPlayer = plugin.getPlayerManager().getPlayer(uuid);
+ }
+ if (qPlayer == null) {
+ sender.sendMessage(Messages.COMMAND_QUEST_ADMIN_NODATA.getMessage().replace("{player}", username));
+ return null;
+ }
+ return qPlayer;
+ }
+
private void showProblems(CommandSender sender) {
if (!plugin.getQuestsConfigLoader().getFilesWithProblems().isEmpty()) {
// sender.sendMessage(ChatColor.DARK_GRAY.toString() + "----");
diff --git a/src/main/java/com/leonardobishop/quests/listener/PlayerJoinListener.java b/src/main/java/com/leonardobishop/quests/listener/PlayerJoinListener.java
index fcee6b40..53916c32 100644
--- a/src/main/java/com/leonardobishop/quests/listener/PlayerJoinListener.java
+++ b/src/main/java/com/leonardobishop/quests/listener/PlayerJoinListener.java
@@ -30,13 +30,6 @@ public class PlayerJoinListener implements Listener {
public void onEvent(PlayerJoinEvent event) {
UUID playerUuid = event.getPlayer().getUniqueId();
plugin.getPlayerManager().loadPlayer(playerUuid);
- if (Options.SOFT_CLEAN_QUESTSPROGRESSFILE_ON_JOIN.getBooleanValue()) {
- QPlayer qPlayer = plugin.getPlayerManager().getPlayer(playerUuid);
- qPlayer.getQuestProgressFile().clean();
- if (Options.PUSH_SOFT_CLEAN_TO_DISK.getBooleanValue()) {
- plugin.getPlayerManager().savePlayer(playerUuid, qPlayer.getQuestProgressFile());
- }
- }
if (plugin.getDescription().getVersion().contains("beta") && event.getPlayer().hasPermission("quests.admin")) {
event.getPlayer().sendMessage(Messages.BETA_REMINDER.getMessage());
}
@@ -45,8 +38,11 @@ public class PlayerJoinListener implements Listener {
Bukkit.getScheduler().runTaskLater(this.plugin, () -> event.getPlayer().sendMessage(plugin.getUpdater().getMessage()), 50L);
}
+ QPlayer qPlayer = plugin.getPlayerManager().getPlayer(playerUuid);
+ if (qPlayer == null) return;
+
// run a full check to check for any missed quest completions
- plugin.getQuestCompleter().queueFullCheck(plugin.getPlayerManager().getPlayer(playerUuid).getQuestProgressFile());
+ plugin.getQuestCompleter().queueFullCheck(qPlayer.getQuestProgressFile());
}
}
diff --git a/src/main/java/com/leonardobishop/quests/listener/PlayerLeaveListener.java b/src/main/java/com/leonardobishop/quests/listener/PlayerLeaveListener.java
index 99cad4e2..d246e1f6 100644
--- a/src/main/java/com/leonardobishop/quests/listener/PlayerLeaveListener.java
+++ b/src/main/java/com/leonardobishop/quests/listener/PlayerLeaveListener.java
@@ -20,8 +20,7 @@ public class PlayerLeaveListener implements Listener {
public void onEvent(PlayerQuitEvent event) {
QPlayer qPlayer = plugin.getPlayerManager().getPlayer(event.getPlayer().getUniqueId());
if (qPlayer == null) return;
- QuestProgressFile clonedProgressFile = new QuestProgressFile(qPlayer.getQuestProgressFile());
- Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> plugin.getPlayerManager().removePlayer(qPlayer.getPlayerUUID(), clonedProgressFile));
+ plugin.getPlayerManager().removePlayer(qPlayer.getPlayerUUID());
}
}
diff --git a/src/main/java/com/leonardobishop/quests/player/QPlayer.java b/src/main/java/com/leonardobishop/quests/player/QPlayer.java
index 872b02d2..4e04566b 100644
--- a/src/main/java/com/leonardobishop/quests/player/QPlayer.java
+++ b/src/main/java/com/leonardobishop/quests/player/QPlayer.java
@@ -78,10 +78,9 @@ public class QPlayer {
}
Player player = Bukkit.getPlayer(uuid);
if (player != null) {
- QPlayer questPlayer = QuestsAPI.getPlayerManager().getPlayer(uuid);
String questFinishMessage = Messages.QUEST_COMPLETE.getMessage().replace("{quest}", quest.getDisplayNameStripped());
// PlayerFinishQuestEvent -- start
- PlayerFinishQuestEvent questFinishEvent = new PlayerFinishQuestEvent(player, questPlayer, questProgress, questFinishMessage);
+ PlayerFinishQuestEvent questFinishEvent = new PlayerFinishQuestEvent(player, this, questProgress, questFinishMessage);
Bukkit.getPluginManager().callEvent(questFinishEvent);
// PlayerFinishQuestEvent -- end
Bukkit.getServer().getScheduler().runTask(plugin, () -> {
@@ -375,10 +374,10 @@ public class QPlayer {
}
if (Options.CATEGORIES_ENABLED.getBooleanValue()) {
- CategoryQMenu categoryQMenu = new CategoryQMenu(plugin, plugin.getPlayerManager().getPlayer(player.getUniqueId()));
+ CategoryQMenu categoryQMenu = new CategoryQMenu(plugin, this);
List<QuestQMenu> questMenus = new ArrayList<>();
for (Category category : plugin.getQuestManager().getCategories()) {
- QuestQMenu questQMenu = new QuestQMenu(plugin, plugin.getPlayerManager().getPlayer(player.getUniqueId()), category.getId(), categoryQMenu);
+ QuestQMenu questQMenu = new QuestQMenu(plugin, this, category.getId(), categoryQMenu);
List<Quest> quests = new ArrayList<>();
for (String questid : category.getRegisteredQuestIds()) {
Quest quest = plugin.getQuestManager().getQuestById(questid);
@@ -393,7 +392,7 @@ public class QPlayer {
plugin.getMenuController().openMenu(player, categoryQMenu, 1);
} else {
- QuestQMenu questQMenu = new QuestQMenu(plugin, plugin.getPlayerManager().getPlayer(player.getUniqueId()), "", null);
+ QuestQMenu questQMenu = new QuestQMenu(plugin, this, "", null);
List<Quest> quests = new ArrayList<>();
for (Map.Entry<String, Quest> entry : plugin.getQuestManager().getQuests().entrySet()) {
quests.add(entry.getValue());
@@ -414,7 +413,7 @@ public class QPlayer {
return;
}
- StartedQMenu startedQMenu = new StartedQMenu(plugin, plugin.getPlayerManager().getPlayer(player.getUniqueId()));
+ StartedQMenu startedQMenu = new StartedQMenu(plugin, this);
List<QuestSortWrapper> quests = new ArrayList<>();
for (Map.Entry<String, Quest> entry : plugin.getQuestManager().getQuests().entrySet()) {
quests.add(new QuestSortWrapper(plugin, entry.getValue()));
diff --git a/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java b/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java
index f521d2de..41c704e3 100644
--- a/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java
+++ b/src/main/java/com/leonardobishop/quests/player/QPlayerManager.java
@@ -6,6 +6,7 @@ import com.leonardobishop.quests.player.questprogressfile.QPlayerPreferences;
import com.leonardobishop.quests.player.questprogressfile.QuestProgress;
import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile;
import com.leonardobishop.quests.player.questprogressfile.TaskProgress;
+import com.leonardobishop.quests.storage.MySqlStorageProvider;
import com.leonardobishop.quests.storage.StorageProvider;
import com.leonardobishop.quests.storage.YamlStorageProvider;
import com.leonardobishop.quests.util.Options;
@@ -24,8 +25,22 @@ public class QPlayerManager {
private StorageProvider storageProvider;
public QPlayerManager(Quests plugin) {
- this.storageProvider = new YamlStorageProvider(plugin);
this.plugin = plugin;
+
+ String configuredProvider = plugin.getConfig().getString("options.storage.provider", "yaml");
+ if (configuredProvider.equalsIgnoreCase("yaml")) {
+ this.storageProvider = new YamlStorageProvider(plugin);
+ } else if (configuredProvider.equalsIgnoreCase("mysql")) {
+ this.storageProvider = new MySqlStorageProvider(plugin, plugin.getConfig().getConfigurationSection("options.storage.database-settings"));
+ } else {
+ plugin.getQuestsLogger().warning("No valid storage provider is configured - Quests will use YAML storage as a default");
+ this.storageProvider = new YamlStorageProvider(plugin);
+ }
+ try {
+ storageProvider.init();
+ } catch (Exception ignored) {
+ plugin.getQuestsLogger().severe("An error occurred initialising the storage provider.");
+ }
}
private final Map<UUID, QPlayer> qPlayers = new ConcurrentHashMap<>();
@@ -48,37 +63,69 @@ public class QPlayerManager {
}
/**
- * Unloads and saves the player to disk.
+ * Unloads and schedules a save for the player. See {@link QPlayerManager#savePlayer(UUID)}
*
* @param uuid the uuid of the player
- * @param questProgressFile the quest progress file to save
*/
- public void removePlayer(UUID uuid, QuestProgressFile questProgressFile) {
+ public void removePlayer(UUID uuid) {
plugin.getQuestsLogger().debug("Unloading and saving player " + uuid + ". Main thread: " + Bukkit.isPrimaryThread());
qPlayers.computeIfPresent(uuid, (mapUUID, qPlayer) -> {
- storageProvider.saveProgressFile(uuid, questProgressFile);
+ savePlayer(uuid);
return null;
});
}
/**
- * Saves the player to disk with a specified {@link QuestProgressFile}.
+ * Schedules a save for the player with the {@link QuestProgressFile} associated by the {@link QPlayerManager}.
+ * The modified status of the progress file will be reset.
*
* @param uuid the uuid of the player
- * @param questProgressFile the quest progress file to associate with and save
*/
- public void savePlayer(UUID uuid, QuestProgressFile questProgressFile) {
- plugin.getQuestsLogger().debug("Saving player " + uuid + ". Main thread: " + Bukkit.isPrimaryThread());
- storageProvider.saveProgressFile(uuid, questProgressFile);
+ public void savePlayer(UUID uuid) {
+ QPlayer qPlayer = getPlayer(uuid);
+ if (qPlayer == null) return;
+ savePlayer(uuid, qPlayer.getQuestProgressFile());
}
/**
- * Saves the player to disk using the {@link QuestProgressFile} associated by the {@link QPlayerManager}
+ * Schedules a save for the player with a specified {@link QuestProgressFile}. The modified status of the
+ * specified progress file will be reset.
*
* @param uuid the uuid of the player
+ * @param originalProgressFile the quest progress file to associate with and save
*/
- public void savePlayer(UUID uuid) {
- savePlayer(uuid, getPlayer(uuid).getQuestProgressFile());
+ public void savePlayer(UUID uuid, QuestProgressFile originalProgressFile) {
+ QuestProgressFile clonedProgressFile = new QuestProgressFile(originalProgressFile);
+ originalProgressFile.resetModified();
+ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> save(uuid, clonedProgressFile));
+ }
+
+ /**
+ * Immediately saves the player with the {@link QuestProgressFile} associated by the {@link QPlayerManager},
+ * on the same thread. The modified status of the specified progress file is not changed.
+ *
+ * @param uuid the uuid of the player
+ */
+ public void savePlayerSync(UUID uuid) {
+ QPlayer qPlayer = getPlayer(uuid);
+ if (qPlayer == null) return;
+ savePlayerSync(uuid, qPlayer.getQuestProgressFile());
+ }
+
+ /**
+ * Immediately saves the player with a specified {@link QuestProgressFile}, on the same thread. The modified status
+ * of the specified progress file is not changed.
+ *
+ * @param uuid the uuid of the player
+ * @param questProgressFile the quest progress file to associate with and save
+ */
+ public void savePlayerSync(UUID uuid, QuestProgressFile questProgressFile) {
+ save(uuid, questProgressFile);
+ }
+
+ private void save(UUID uuid, QuestProgressFile questProgressFile) {
+ plugin.getQuestsLogger().debug("Saving player " + uuid + ". Main thread: " + Bukkit.isPrimaryThread());
+ storageProvider.saveProgressFile(uuid, questProgressFile);
}
/**
@@ -96,7 +143,7 @@ public class QPlayerManager {
}
/**
- * Load the player from disk if they exist, otherwise create a new {@link QuestProgressFile}.
+ * Load the player if they exist, otherwise create a new {@link QuestProgressFile}.
* This will have no effect if player is already loaded. Can be invoked asynchronously.
*
* @param uuid the uuid of the player
@@ -105,7 +152,17 @@ public class QPlayerManager {
plugin.getQuestsLogger().debug("Loading player " + uuid + ". Main thread: " + Bukkit.isPrimaryThread());
qPlayers.computeIfAbsent(uuid, s -> {
QuestProgressFile questProgressFile = storageProvider.loadProgressFile(uuid);
+ if (questProgressFile == null) return null;
return new QPlayer(uuid, questProgressFile, new QPlayerPreferences(null), plugin);
});
}
+
+ /**
+ * Gets the current storage provider which loads and saves players.
+ *
+ * @return {@link StorageProvider}
+ */
+ public StorageProvider getStorageProvider() {
+ return storageProvider;
+ }
}
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 7d795fed..d7cac084 100644
--- a/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgress.java
+++ b/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgress.java
@@ -120,8 +120,7 @@ public class QuestProgress {
this.addTaskProgress(taskProgress);
}
- @Deprecated // this shit is annoying to maintain
- public boolean isWorthSaving() {
+ public boolean isModified() {
if (modified) return true;
else {
for (TaskProgress progress : this.taskProgress.values()) {
@@ -138,7 +137,7 @@ public class QuestProgress {
public void resetModified() {
this.modified = false;
for (TaskProgress progress : this.taskProgress.values()) {
- progress.setModified(false);
+ progress.resetModified();
}
}
}
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 0ddf3525..3f6d9900 100644
--- a/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgressFile.java
+++ b/src/main/java/com/leonardobishop/quests/player/questprogressfile/QuestProgressFile.java
@@ -4,6 +4,7 @@ import com.leonardobishop.quests.Quests;
import com.leonardobishop.quests.player.QPlayer;
import com.leonardobishop.quests.quest.Quest;
import com.leonardobishop.quests.quest.Task;
+import com.leonardobishop.quests.util.Options;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
@@ -40,6 +41,9 @@ public class QuestProgressFile {
}
public void addQuestProgress(QuestProgress questProgress) {
+ if (Options.VERIFY_QUEST_EXISTS_ON_LOAD.getBooleanValue(true) && plugin.getQuestManager().getQuestById(questProgress.getQuestId()) == null) {
+ return;
+ }
this.questProgress.put(questProgress.getQuestId(), questProgress);
}
@@ -244,4 +248,10 @@ public class QuestProgressFile {
}
}
+ public void resetModified() {
+ for (QuestProgress questProgress : questProgress.values()) {
+ questProgress.resetModified();
+ }
+ }
+
}
diff --git a/src/main/java/com/leonardobishop/quests/player/questprogressfile/TaskProgress.java b/src/main/java/com/leonardobishop/quests/player/questprogressfile/TaskProgress.java
index 14e1bea0..e0943ff3 100644
--- a/src/main/java/com/leonardobishop/quests/player/questprogressfile/TaskProgress.java
+++ b/src/main/java/com/leonardobishop/quests/player/questprogressfile/TaskProgress.java
@@ -67,7 +67,7 @@ public class TaskProgress {
return modified;
}
- public void setModified(boolean modified) {
- this.modified = modified;
+ public void resetModified() {
+ this.modified = false;
}
}
diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningCertainTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningCertainTaskType.java
index da497808..125bfecc 100644
--- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningCertainTaskType.java
+++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/MiningCertainTaskType.java
@@ -127,6 +127,9 @@ public final class MiningCertainTaskType extends TaskType {
if (event.getPlayer().hasMetadata("NPC")) return;
QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(event.getPlayer().getUniqueId());
+ if (qPlayer == null) {
+ return;
+ }
for (Quest quest : super.getRegisteredQuests()) {
if (qPlayer.hasStartedQuest(quest)) {
diff --git a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsBalanceTaskType.java b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsBalanceTaskType.java
index 581cbafb..22cef8a2 100644
--- a/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsBalanceTaskType.java
+++ b/src/main/java/com/leonardobishop/quests/quest/tasktype/type/dependent/EssentialsBalanceTaskType.java
@@ -47,6 +47,9 @@ public class EssentialsBalanceTaskType extends TaskType {
Essentials ess = (Essentials) Bukkit.getPluginManager().getPlugin("Essentials");
if (player != null && player.isOnline() && ess != null) {
QPlayer qPlayer = QuestsAPI.getPlayerManager().getPlayer(playerUUID);
+ if (qPlayer == null) {
+ return;
+ }
QuestProgressFile questProgressFile = qPlayer.getQuestProgressFile();
QuestProgress questProgress = questProgressFile.getQuestProgress(quest);
TaskProgress taskProgress = questProgress.getTaskProgress(task.getId());
diff --git a/src/main/java/com/leonardobishop/quests/storage/MySqlStorageProvider.java b/src/main/java/com/leonardobishop/quests/storage/MySqlStorageProvider.java
new file mode 100644
index 00000000..02692919
--- /dev/null
+++ b/src/main/java/com/leonardobishop/quests/storage/MySqlStorageProvider.java
@@ -0,0 +1,278 @@
+package com.leonardobishop.quests.storage;
+
+import com.leonardobishop.quests.Quests;
+import com.leonardobishop.quests.player.questprogressfile.QuestProgress;
+import com.leonardobishop.quests.player.questprogressfile.QuestProgressFile;
+import com.leonardobishop.quests.player.questprogressfile.TaskProgress;
+import com.leonardobishop.quests.util.Options;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.function.Function;
+
+public class MySqlStorageProvider implements StorageProvider {
+
+ private static final String CREATE_TABLE_QUEST_PROGRESS =
+ "CREATE TABLE IF NOT EXISTS `{prefix}quest_progress` (" +
+ " `uuid` VARCHAR(36) NOT NULL," +
+ " `quest_id` VARCHAR(50) NOT NULL," +
+ " `started` BOOL NOT NULL," +
+ " `completed` BOOL NOT NULL," +
+ " `completed_before` BOOL NOT NULL," +
+ " `completion_date` BIGINT NOT NULL," +
+ " PRIMARY KEY (`uuid`, `quest_id`));";
+ private static final String CREATE_TABLE_TASK_PROGRESS =
+ "CREATE TABLE IF NOT EXISTS `{prefix}task_progress` (" +
+ " `uuid` VARCHAR(36) NOT NULL," +
+ " `quest_id` VARCHAR(50) NOT NULL," +
+ " `task_id` VARCHAR(50) NOT NULL," +
+ " `completed` BOOL NOT NULL," +
+ " `progress` VARCHAR(64) NULL," +
+ " `data_type` VARCHAR(10) NULL," +
+ " PRIMARY KEY (`uuid`, `quest_id`, `task_id`));";
+ private static final String SELECT_PLAYER_QUEST_PROGRESS =
+ "SELECT quest_id, started, completed, completed_before, completion_date FROM `{prefix}quest_progress` WHERE uuid=?;";
+ private static final String SELECT_PLAYER_TASK_PROGRESS =
+ "SELECT quest_id, task_id, completed, progress, data_type FROM `{prefix}task_progress` WHERE uuid=?;";
+ private static final String SELECT_KNOWN_PLAYER_QUEST_PROGRESS =
+ "SELECT quest_id FROM `{prefix}quest_progress` WHERE uuid=?;";
+ private static final String SELECT_KNOWN_PLAYER_TASK_PROGRESS =
+ "SELECT quest_id, task_id FROM `{prefix}task_progress` WHERE uuid=?;";
+ private static final String WRITE_PLAYER_QUEST_PROGRESS =
+ "INSERT INTO `{prefix}quest_progress` (uuid, quest_id, started, completed, completed_before, completion_date) VALUES (?,?,?,?,?,?) ON DUPLICATE KEY UPDATE started=?, completed=?, completed_before=?, completion_date=?";
+ private static final String WRITE_PLAYER_TASK_PROGRESS =
+ "INSERT INTO `{prefix}task_progress` (uuid, quest_id, task_id, completed, progress, data_type) VALUES (?,?,?,?,?,?) ON DUPLICATE KEY UPDATE completed=?, progress=?, data_type=?";
+
+ private final ConfigurationSection configuration;
+ private final Quests plugin;
+ private HikariDataSource hikari;
+ private String prefix;
+ private Function<String, String> statementProcessor;
+ private boolean fault;
+
+ public MySqlStorageProvider(Quests plugin, ConfigurationSection configuration) {
+ this.plugin = plugin;
+ if (configuration == null) {
+ configuration = new YamlConfiguration();
+ }
+ this.configuration = configuration;
+ }
+
+ @Override
+ public void init() {
+ String address = configuration.getString("network.address", "localhost:3306");
+ String database = configuration.getString("network.database", "minecraft");
+ String url = "jdbc:mysql://" + address + "/" + database;
+
+ HikariConfig config = new HikariConfig();
+ config.setPoolName("quests-hikari");
+
+ config.setUsername(configuration.getString("network.username", "root"));
+ config.setPassword(configuration.getString("network.password", ""));
+ config.setJdbcUrl(url);
+ config.setMaximumPoolSize(configuration.getInt("connection-pool-settings.maximum-pool-size", 8));
+ config.setMinimumIdle(configuration.getInt("connection-pool-settings.minimum-idle", 8));
+ config.setMaxLifetime(configuration.getInt("connection-pool-settings.maximum-lifetime", 1800000));
+ config.setConnectionTimeout(configuration.getInt("connection-pool-settings.connection-timeout", 5000));
+
+ config.addDataSourceProperty("cachePrepStmts", true);
+ config.addDataSourceProperty("prepStmtCacheSize", 250);
+ config.addDataSourceProperty("prepStmtCacheSqlLimit", 2048);
+ config.addDataSourceProperty("useServerPrepStmts", true);
+ config.addDataSourceProperty("useLocalSessionState", true);
+ config.addDataSourceProperty("rewriteBatchedStatements", true);
+ config.addDataSourceProperty("cacheResultSetMetadata", true);
+ config.addDataSourceProperty("cacheServerConfiguration", true);
+ config.addDataSourceProperty("elideSetAutoCommits", true);
+ config.addDataSourceProperty("maintainTimeStats", false);
+
+ try {
+ this.hikari = new HikariDataSource(config);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fault = true;
+ }
+ this.prefix = configuration.getString("database-settings.table-prefix", "quests_");
+ this.statementProcessor = s -> s.replace("{prefix}", prefix);
+ try (Connection connection = hikari.getConnection()) {
+ try (Statement s = connection.createStatement()) {
+ plugin.getQuestsLogger().debug("Creating default tables");
+ s.addBatch(this.statementProcessor.apply(CREATE_TABLE_QUEST_PROGRESS));
+ s.addBatch(this.statementProcessor.apply(CREATE_TABLE_TASK_PROGRESS));
+
+ s.executeBatch();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ if (hikari != null) hikari.close();
+ }
+
+ @Override
+ public QuestProgressFile loadProgressFile(UUID uuid) {
+ if (fault) return null;
+ QuestProgressFile questProgressFile = new QuestProgressFile(uuid, plugin);
+ try (Connection connection = hikari.getConnection()) {
+ plugin.getQuestsLogger().debug("Querying player " + uuid);
+ Map<String, QuestProgress> questProgressMap = new HashMap<>();
+ try (PreparedStatement ps = connection.prepareStatement(this.statementProcessor.apply(SELECT_PLAYER_QUEST_PROGRESS))) {
+ ps.setString(1, uuid.toString());
+
+ try (ResultSet rs = ps.executeQuery()) {
+ while (rs.next()) {
+ String questId = rs.getString(1);
+ boolean started = rs.getBoolean(2);
+ boolean completed = rs.getBoolean(3);
+ boolean completedBefore = rs.getBoolean(4);
+ long completionDate = rs.getLong(5);
+
+ QuestProgress questProgress = new QuestProgress(plugin, questId, completed, completedBefore, completionDate, uuid, started);
+ questProgressMap.put(questId, questProgress);
+ }
+ }
+ }
+ try (PreparedStatement ps = connection.prepareStatement(this.statementProcessor.apply(SELECT_PLAYER_TASK_PROGRESS))) {
+ ps.setString(1, uuid.toString());
+
+ try (ResultSet rs = ps.executeQuery()) {
+ while (rs.next()) {
+ String questId = rs.getString(1);
+ String taskId = rs.getString(2);
+ boolean completed = rs.getBoolean(3);
+ String encodedProgress = rs.getString(4);
+ String type = rs.getString(5);
+ Object progress;
+ try {
+ if (type == null) {
+ progress = null;
+ } else if (type.equals("double")) {
+ progress = Double.valueOf(encodedProgress);
+ } else if (type.equals("float")) {
+ progress = Float.valueOf(encodedProgress);
+ } else if (type.equals("int")) {
+ progress = Integer.valueOf(encodedProgress);
+ } else {
+ throw new RuntimeException("unknown data type '" + type + "'");
+ }
+ } catch (NumberFormatException ex) {
+ plugin.getQuestsLogger().warning("Cannot retrieve progress for task '"
+ + taskId + "' in quest '" + questId + "' for player " + uuid
+ + " since data is malformed!");
+ continue;
+ } catch (RuntimeException ex) {
+ if (ex.getMessage().startsWith("unknown data type ")) {
+ plugin.getQuestsLogger().warning("Cannot retrieve progress for task '"
+ + taskId + "' in quest '" + questId + "' for player " + uuid
+ + ": " + ex.getMessage());
+ continue;
+ } else {
+ throw ex;
+ }
+ }
+
+ QuestProgress linkedQuestProgress = questProgressMap.get(questId);
+ if (linkedQuestProgress == null) continue; // lost quest progress ?
+ TaskProgress questProgress = new TaskProgress(linkedQuestProgress, taskId, progress, uuid, completed);
+ linkedQuestProgress.addTaskProgress(questProgress);
+ }
+ }
+ }
+ for (QuestProgress questProgress : questProgressMap.values()) {
+ questProgressFile.addQuestProgress(questProgress);
+ }
+ } catch (SQLException e) {
+ plugin.getQuestsLogger().severe("Failed to load player: " + uuid + "!");
+ e.printStackTrace();
+ return null;
+ }
+ return questProgressFile;
+ }
+
+ @Override
+ public void saveProgressFile(UUID uuid, QuestProgressFile questProgressFile) {
+ if (fault) return;
+ try (Connection connection = hikari.getConnection()) {
+ try (PreparedStatement writeQuestProgress = connection.prepareStatement(this.statementProcessor.apply(WRITE_PLAYER_QUEST_PROGRESS));
+ PreparedStatement writeTaskProgress = connection.prepareStatement(this.statementProcessor.apply(WRITE_PLAYER_TASK_PROGRESS))) {
+
+ List<QuestProgress> questProgressValues = new ArrayList<>(questProgressFile.getAllQuestProgress());
+ for (QuestProgress questProgress : questProgressValues) {
+ if (!questProgress.isModified()) continue;
+
+ String questId = questProgress.getQuestId();
+ writeQuestProgress.setString(1, uuid.toString());
+ writeQuestProgress.setString(2, questProgress.getQuestId());
+ writeQuestProgress.setBoolean(3, questProgress.isStarted());
+ writeQuestProgress.setBoolean(4, questProgress.isCompleted());
+ writeQuestProgress.setBoolean(5, questProgress.isCompletedBefore());
+ writeQuestProgress.setLong(6, questProgress.getCompletionDate());
+ writeQuestProgress.setBoolean(7, questProgress.isStarted());
+ writeQuestProgress.setBoolean(8, questProgress.isCompleted());
+ writeQuestProgress.setBoolean(9, questProgress.isCompletedBefore());
+ writeQuestProgress.setLong(10, questProgress.getCompletionDate());
+ writeQuestProgress.addBatch();
+
+ for (TaskProgress taskProgress : questProgress.getTaskProgress()) {
+ String taskId = taskProgress.getTaskId();
+
+ String encodedProgress;
+ Object progress = taskProgress.getProgress();
+ String type;
+ if (progress == null) {
+ type = null;
+ encodedProgress = null;
+ } else if (progress instanceof Double) {
+ type = "double";
+ encodedProgress = String.valueOf(progress);
+ } else if (progress instanceof Integer) {
+ type = "int";
+ encodedProgress = String.valueOf(progress);
+ } else if (progress instanceof Float) {
+ type = "float";
+ encodedProgress = String.valueOf(progress);
+ } else {
+ plugin.getQuestsLogger().warning("Cannot store progress for task '"
+ + taskId + "' in quest '" + questId + "' for player " + uuid
+ + " since type " + progress.getClass().getName() + " cannot be encoded!");
+ continue;
+ }
+ writeTaskProgress.setString(1, uuid.toString());
+ writeTaskProgress.setString(2, questId);
+ writeTaskProgress.setString(3, taskProgress.getTaskId());
+ writeTaskProgress.setBoolean(4, taskProgress.isCompleted());
+ writeTaskProgress.setString(5, encodedProgress);
+ writeTaskProgress.setString(6, type);
+ writeTaskProgress.setBoolean(7, taskProgress.isCompleted());
+ writeTaskProgress.setString(8, encodedProgress);
+ writeTaskProgress.setString(9, type);
+ writeTaskProgress.addBatch();
+ }
+ }
+
+ writeQuestProgress.executeBatch();
+ writeTaskProgress.executeBatch();
+ }
+ } catch (SQLException e) {
+ plugin.getQuestsLogger().severe("Failed to save player: " + uuid + "!");
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/com/leonardobishop/quests/storage/StorageProvider.java b/src/main/java/com/leonardobishop/quests/storage/StorageProvider.java
index 65e4e091..f1d00203 100644
--- a/src/main/java/com/leonardobishop/quests/storage/StorageProvider.java
+++ b/src/main/java/com/leonardobishop/quests/storage/StorageProvider.java
@@ -6,6 +6,8 @@ import java.util.UUID;
public interface StorageProvider {
+ void init();
+ void shutdown();
QuestProgressFile loadProgressFile(UUID uuid);
void saveProgressFile(UUID uuid, QuestProgressFile questProgressFile);
diff --git a/src/main/java/com/leonardobishop/quests/storage/YamlStorageProvider.java b/src/main/java/com/leonardobishop/quests/storage/YamlStorageProvider.java
index ababef3e..8ba30a4e 100644
--- a/src/main/java/com/leonardobishop/quests/storage/YamlStorageProvider.java
+++ b/src/main/java/com/leonardobishop/quests/storage/YamlStorageProvider.java
@@ -31,6 +31,17 @@ public class YamlStorageProvider implements StorageProvider {
return lock;
}
+ @Override
+ public void init() {
+ File directory = new File(plugin.getDataFolder() + File.separator + "playerdata");
+ directory.mkdirs();
+ }
+
+ @Override
+ public void shutdown() {
+ // no impl
+ }
+
public QuestProgressFile loadProgressFile(UUID uuid) {
ReentrantLock lock = lock(uuid);
QuestProgressFile questProgressFile = new QuestProgressFile(uuid, plugin);
@@ -97,8 +108,8 @@ public class YamlStorageProvider implements StorageProvider {
}
YamlConfiguration data = YamlConfiguration.loadConfiguration(file);
- data.set("quest-progress", null);
for (QuestProgress questProgress : questProgressValues) {
+ if (!questProgress.isModified()) continue;
data.set("quest-progress." + questProgress.getQuestId() + ".started", questProgress.isStarted());
data.set("quest-progress." + questProgress.getQuestId() + ".completed", questProgress.isCompleted());
data.set("quest-progress." + questProgress.getQuestId() + ".completed-before", questProgress.isCompletedBefore());
diff --git a/src/main/java/com/leonardobishop/quests/util/Messages.java b/src/main/java/com/leonardobishop/quests/util/Messages.java
index ba9e42da..a86a4144 100644
--- a/src/main/java/com/leonardobishop/quests/util/Messages.java
+++ b/src/main/java/com/leonardobishop/quests/util/Messages.java
@@ -22,6 +22,7 @@ public enum Messages {
QUEST_CATEGORY_PERMISSION("messages.quest-category-permission"),
QUEST_CANCEL_NOTSTARTED("messages.quest-cancel-notstarted"),
QUEST_UPDATER("messages.quest-updater"),
+ COMMAND_DATA_NOT_LOADED("messages.command-data-not-loaded"),
COMMAND_SUB_DOESNTEXIST("messages.command-sub-doesntexist"),
COMMAND_QUEST_START_DOESNTEXIST("messages.command-quest-start-doesntexist"),
COMMAND_QUEST_GENERAL_DOESNTEXIST("messages.command-quest-general-doesntexist"),
diff --git a/src/main/java/com/leonardobishop/quests/util/Options.java b/src/main/java/com/leonardobishop/quests/util/Options.java
index 34922f18..0ad0a41d 100644
--- a/src/main/java/com/leonardobishop/quests/util/Options.java
+++ b/src/main/java/com/leonardobishop/quests/util/Options.java
@@ -25,8 +25,7 @@ public enum Options {
GUITITLE_QUEST_CANCEL("options.guinames.quest-cancel"),
ALLOW_QUEST_CANCEL("options.allow-quest-cancel"),
ALLOW_QUEST_TRACK("options.allow-quest-track"),
- SOFT_CLEAN_QUESTSPROGRESSFILE_ON_JOIN("options.soft-clean-questsprogressfile-on-join"),
- PUSH_SOFT_CLEAN_TO_DISK("options.tab-completion.push-soft-clean-to-disk"),
+ VERIFY_QUEST_EXISTS_ON_LOAD("options.verify-quest-exists-on-load"),
TAB_COMPLETE_ENABLED("options.tab-completion.enabled"),
ERROR_CHECKING_OVERRIDE("options.error-checking.override-errors"),
QUEST_AUTOSTART("options.quest-autostart"),