Perform /questadmin reload asynchronously, fixes #1179

This commit is contained in:
PikaMug 2020-04-07 06:58:46 -04:00
parent b91574efc3
commit 0bd7474aa6
8 changed files with 163 additions and 61 deletions

View File

@ -46,6 +46,7 @@ import org.bukkit.inventory.ItemStack;
import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.managers.RegionManager;
import me.blackvein.quests.Quests.ReloadCallback;
import me.blackvein.quests.actions.Action; import me.blackvein.quests.actions.Action;
import me.blackvein.quests.convo.quests.QuestsEditorNumericPrompt; import me.blackvein.quests.convo.quests.QuestsEditorNumericPrompt;
import me.blackvein.quests.convo.quests.QuestsEditorStringPrompt; import me.blackvein.quests.convo.quests.QuestsEditorStringPrompt;
@ -1059,7 +1060,7 @@ public class QuestFactory implements ConversationAbandonedListener {
} }
private void deleteQuest(ConversationContext context) { private void deleteQuest(ConversationContext context) {
YamlConfiguration data = new YamlConfiguration(); FileConfiguration data = new YamlConfiguration();
File questsFile = new File(plugin.getDataFolder(), "quests.yml"); File questsFile = new File(plugin.getDataFolder(), "quests.yml");
try { try {
data.load(questsFile); data.load(questsFile);
@ -1088,7 +1089,14 @@ public class QuestFactory implements ConversationAbandonedListener {
((Player) context.getForWhom()).sendMessage(ChatColor.RED + Lang.get("questSaveError")); ((Player) context.getForWhom()).sendMessage(ChatColor.RED + Lang.get("questSaveError"));
return; return;
} }
plugin.reloadQuests(); ReloadCallback<Boolean> callback = new ReloadCallback<Boolean>() {
public void execute(Boolean response) {
if (!response) {
context.getForWhom().sendRawMessage(ChatColor.RED + Lang.get("unknownError"));
}
}
};
plugin.reload(callback);
context.getForWhom().sendRawMessage(ChatColor.GREEN + Lang.get("questDeleted")); context.getForWhom().sendRawMessage(ChatColor.GREEN + Lang.get("questDeleted"));
} }

View File

@ -72,7 +72,7 @@ import net.citizensnpcs.api.npc.NPC;
public class Quester { public class Quester {
private Quests plugin; private final Quests plugin;
public boolean hasJournal = false; public boolean hasJournal = false;
private UUID id; private UUID id;
protected String questToTake; protected String questToTake;
@ -229,8 +229,8 @@ public class Quester {
} }
}; };
public Quester(Quests newPlugin) { public Quester(Quests plugin) {
plugin = newPlugin; this.plugin = plugin;
} }
public UUID getUUID() { public UUID getUUID() {
@ -3398,18 +3398,26 @@ public class Quester {
if (quest != null) { if (quest != null) {
boolean exists = false; boolean exists = false;
for (Quest q : plugin.getQuests()) { for (Quest q : plugin.getQuests()) {
if (q.getName().equalsIgnoreCase(quest.getName())) { if (q.getId().equalsIgnoreCase(quest.getId())) {
Stage stage = getCurrentStage(quest); Stage stage = getCurrentStage(quest);
quest.updateCompass(this, stage); if (stage != null) {
exists = true; quest.updateCompass(this, stage);
break; exists = true;
if (q.equals(quest) == false) {
// TODO - decide whether or not to handle this
/*if (getPlayer() != null && getPlayer().isOnline()) {
quitQuest(quest, ChatColor.GOLD + Lang.get("questModified")
.replace("<quest>", ChatColor.DARK_PURPLE + quest.getName() + ChatColor.GOLD));
}*/
}
break;
}
} }
} }
if (exists == false) { if (!exists) {
if (plugin.getServer().getPlayer(id) != null) { if (getPlayer() != null && getPlayer().isOnline()) {
String error = Lang.get("questNotExist"); getPlayer().sendMessage(ChatColor.RED + Lang.get("questNotExist")
error = error.replace("<quest>", ChatColor.DARK_PURPLE + quest.getName() + ChatColor.RED); .replace("<quest>", ChatColor.DARK_PURPLE + quest.getName() + ChatColor.RED));
plugin.getServer().getPlayer(id).sendMessage(ChatColor.GOLD + "[Quests] " + ChatColor.RED + error);
} }
} }
} }

View File

@ -98,6 +98,7 @@ import net.citizensnpcs.api.npc.NPC;
public class Quests extends JavaPlugin implements ConversationAbandonedListener { public class Quests extends JavaPlugin implements ConversationAbandonedListener {
private boolean loading = true;
private String bukkitVersion = "0"; private String bukkitVersion = "0";
private Dependencies depends; private Dependencies depends;
private Settings settings; private Settings settings;
@ -106,7 +107,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
private final List<CustomObjective> customObjectives = new LinkedList<CustomObjective>(); private final List<CustomObjective> customObjectives = new LinkedList<CustomObjective>();
private LinkedList<Quester> questers = new LinkedList<Quester>(); private LinkedList<Quester> questers = new LinkedList<Quester>();
private LinkedList<Quest> quests = new LinkedList<Quest>(); private LinkedList<Quest> quests = new LinkedList<Quest>();
private LinkedList<Action> events = new LinkedList<Action>(); private LinkedList<Action> actions = new LinkedList<Action>();
private LinkedList<NPC> questNpcs = new LinkedList<NPC>(); private LinkedList<NPC> questNpcs = new LinkedList<NPC>();
private CommandExecutor cmdExecutor; private CommandExecutor cmdExecutor;
private ConversationFactory conversationFactory; private ConversationFactory conversationFactory;
@ -220,6 +221,10 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
} }
} }
public boolean isLoading() {
return loading;
}
public String getDetectedBukkitVersion() { public String getDetectedBukkitVersion() {
return bukkitVersion; return bukkitVersion;
} }
@ -279,11 +284,11 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
} }
public LinkedList<Action> getActions() { public LinkedList<Action> getActions() {
return events; return actions;
} }
public void setActions(LinkedList<Action> actions) { public void setActions(LinkedList<Action> actions) {
this.events = actions; this.actions = actions;
} }
public LinkedList<Quester> getQuesters() { public LinkedList<Quester> getQuesters() {
@ -411,7 +416,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
jar.close(); jar.close();
} }
try { try {
Lang.loadLang(this); Lang.init(this);
} catch (InvalidConfigurationException e) { } catch (InvalidConfigurationException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -470,7 +475,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
/** /**
* Load quests, actions, and modules after specified delay<p> * Load quests, actions, and modules after specified delay<p>
* *
* At startup, this permits Citizens to fully load first * At startup, this lets soft-depends (namely Citizens) fully load first
*/ */
private void delayLoadQuestInfo(long ticks) { private void delayLoadQuestInfo(long ticks) {
getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() { getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
@ -480,9 +485,18 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
loadQuests(); loadQuests();
loadActions(); loadActions();
getLogger().log(Level.INFO, "Loaded " + quests.size() + " Quest(s)" getLogger().log(Level.INFO, "Loaded " + quests.size() + " Quest(s)"
+ ", " + events.size() + " Action(s)" + ", " + actions.size() + " Action(s)"
+ ", " + Lang.size() + " Phrase(s)"); + ", " + Lang.size() + " Phrase(s)");
questers.addAll(getOnlineQuesters()); for (Player p : getServer().getOnlinePlayers()) {
Quester quester = new Quester(Quests.this);
quester.setUUID(p.getUniqueId());
if (quester.loadData() == false) {
quester.saveData();
}
// Workaround for issues with the compass on fast join
quester.findCompassTarget();
questers.add(quester);
}
if (depends.getCitizens() != null) { if (depends.getCitizens() != null) {
if (depends.getCitizens().getNPCRegistry() == null) { if (depends.getCitizens().getNPCRegistry() == null) {
getLogger().log(Level.SEVERE, getLogger().log(Level.SEVERE,
@ -491,6 +505,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
} }
} }
loadModules(); loadModules();
loading = false;
} }
}, ticks); }, ticks);
} }
@ -525,7 +540,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
if (config.contains("quests")) { if (config.contains("quests")) {
questsSection = config.getConfigurationSection("quests"); questsSection = config.getConfigurationSection("quests");
for (String questKey : questsSection.getKeys(false)) { for (String questKey : questsSection.getKeys(false)) {
try { // main "skip quest" try/catch block try {
Quest quest = new Quest(); Quest quest = new Quest();
failedToLoad = false; failedToLoad = false;
if (config.contains("quests." + questKey + ".name")) { if (config.contains("quests." + questKey + ".name")) {
@ -535,7 +550,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
} else { } else {
throw new QuestFormatException("Quest block is missing", questKey); throw new QuestFormatException("Quest block is missing", questKey);
} }
if (failedToLoad == true) { if (failedToLoad) {
getLogger().log(Level.SEVERE, "Failed to load Quest \"" + questKey + "\". Skipping."); getLogger().log(Level.SEVERE, "Failed to load Quest \"" + questKey + "\". Skipping.");
} }
} catch (QuestFormatException ex) { } catch (QuestFormatException ex) {
@ -1137,37 +1152,71 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
} }
} }
} }
public interface ReloadCallback<T> {
public void execute(T response);
}
/**
* @deprecated Use {@link #reload(ReloadCallback)}
*/
public void reloadQuests() {
reload(null);
}
/** /**
* Reload quests, actions, config settings, lang and modules, and player data * Reload quests, actions, config settings, lang and modules, and player data
*/ */
public void reloadQuests() { public void reload(final ReloadCallback<Boolean> callback) {
for (Quester quester : questers) {
quester.saveData();
}
quests.clear();
events.clear();
loadQuests();
loadActions();
// Reload config from disc in-case a setting was changed
reloadConfig(); reloadConfig();
settings.init(); Bukkit.getScheduler().runTaskAsynchronously(this, new Runnable() {
Lang.clear();
try { @Override
Lang.loadLang(this); public void run() {
} catch (InvalidConfigurationException e) { loading = true;
e.printStackTrace(); try {
} catch (IOException e) { for (Quester quester : questers) {
e.printStackTrace(); quester.saveData();
} }
loadModules(); quests.clear();
for (Quester quester : questers) { actions.clear();
quester.loadData(); Lang.clear();
for (Quest q : quester.currentQuests.keySet()) { settings.init();
quester.checkQuest(q); Lang.init(Quests.this);
loadQuests();
loadActions();
for (Quester quester : questers) {
quester.loadData();
for (Quest q : quester.currentQuests.keySet()) {
quester.checkQuest(q);
}
}
loadModules();
if (callback != null) {
Bukkit.getScheduler().runTask(Quests.this, new Runnable() {
@Override
public void run() {
callback.execute(true);
}
});
}
} catch (Exception e) {
e.printStackTrace();
if (callback != null) {
Bukkit.getScheduler().runTask(Quests.this, new Runnable() {
@Override
public void run() {
callback.execute(false);
}
});
}
}
loading = false;
} }
} });
} }
/** /**
@ -1202,6 +1251,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
/** /**
* Get a list of all online Questers * Get a list of all online Questers
* *
* @deprecated Use {@link Bukkit#getOnlinePlayers()} and then {@link #getQuester(UUID)}
* @return list of online Questers * @return list of online Questers
*/ */
public LinkedList<Quester> getOnlineQuesters() { public LinkedList<Quester> getOnlineQuesters() {
@ -2936,7 +2986,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
for (String s : sec.getKeys(false)) { for (String s : sec.getKeys(false)) {
Action event = Action.loadAction(s, this); Action event = Action.loadAction(s, this);
if (event != null) { if (event != null) {
events.add(event); actions.add(event);
} else { } else {
getLogger().log(Level.SEVERE, "Failed to load Action \"" + s + "\". Skipping."); getLogger().log(Level.SEVERE, "Failed to load Action \"" + s + "\". Skipping.");
} }
@ -3090,7 +3140,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
if (name == null) { if (name == null) {
return null; return null;
} }
LinkedList<Action> as = events; LinkedList<Action> as = actions;
for (Action a : as) { for (Action a : as) {
if (a.getName().equalsIgnoreCase(ChatColor.translateAlternateColorCodes('&', name))) { if (a.getName().equalsIgnoreCase(ChatColor.translateAlternateColorCodes('&', name))) {
return a; return a;

View File

@ -21,7 +21,7 @@ import me.blackvein.quests.util.Lang;
public class Settings { public class Settings {
private Quests plugin; private final Quests plugin;
private int acceptTimeout = 20; private int acceptTimeout = 20;
private boolean allowCommands = true; private boolean allowCommands = true;
private boolean allowCommandsForNpcQuests = false; private boolean allowCommandsForNpcQuests = false;

View File

@ -50,6 +50,7 @@ import me.blackvein.quests.QuestMob;
import me.blackvein.quests.Quester; import me.blackvein.quests.Quester;
import me.blackvein.quests.Quests; import me.blackvein.quests.Quests;
import me.blackvein.quests.Stage; import me.blackvein.quests.Stage;
import me.blackvein.quests.Quests.ReloadCallback;
import me.blackvein.quests.convo.actions.ActionsEditorNumericPrompt; import me.blackvein.quests.convo.actions.ActionsEditorNumericPrompt;
import me.blackvein.quests.convo.actions.ActionsEditorStringPrompt; import me.blackvein.quests.convo.actions.ActionsEditorStringPrompt;
import me.blackvein.quests.convo.quests.prompts.ItemStackPrompt; import me.blackvein.quests.convo.quests.prompts.ItemStackPrompt;
@ -1159,7 +1160,14 @@ public class ActionFactory implements ConversationAbandonedListener {
((Player) context.getForWhom()).sendMessage(ChatColor.RED + Lang.get("eventEditorErrorSaving")); ((Player) context.getForWhom()).sendMessage(ChatColor.RED + Lang.get("eventEditorErrorSaving"));
return; return;
} }
plugin.reloadQuests(); ReloadCallback<Boolean> callback = new ReloadCallback<Boolean>() {
public void execute(Boolean response) {
if (!response) {
context.getForWhom().sendRawMessage(ChatColor.RED + Lang.get("unknownError"));
}
}
};
plugin.reload(callback);
((Player) context.getForWhom()).sendMessage(ChatColor.YELLOW + Lang.get("eventEditorDeleted")); ((Player) context.getForWhom()).sendMessage(ChatColor.YELLOW + Lang.get("eventEditorDeleted"));
for (Quester q : plugin.getQuesters()) { for (Quester q : plugin.getQuesters()) {
for (Quest quest : q.getCurrentQuests().keySet()) { for (Quest quest : q.getCurrentQuests().keySet()) {
@ -1324,7 +1332,14 @@ public class ActionFactory implements ConversationAbandonedListener {
((Player) context.getForWhom()).sendMessage(ChatColor.RED + Lang.get("eventEditorErrorSaving")); ((Player) context.getForWhom()).sendMessage(ChatColor.RED + Lang.get("eventEditorErrorSaving"));
return; return;
} }
plugin.reloadQuests(); ReloadCallback<Boolean> callback = new ReloadCallback<Boolean>() {
public void execute(Boolean response) {
if (!response) {
context.getForWhom().sendRawMessage(ChatColor.RED + Lang.get("unknownError"));
}
}
};
plugin.reload(callback);
((Player) context.getForWhom()).sendMessage(ChatColor.YELLOW + Lang.get("eventEditorSaved")); ((Player) context.getForWhom()).sendMessage(ChatColor.YELLOW + Lang.get("eventEditorSaved"));
for (Quester q : plugin.getQuesters()) { for (Quester q : plugin.getQuesters()) {
for (Quest quest : q.getCurrentQuests().keySet()) { for (Quest quest : q.getCurrentQuests().keySet()) {

View File

@ -28,6 +28,7 @@ import java.util.Map.Entry;
import me.blackvein.quests.Quest; import me.blackvein.quests.Quest;
import me.blackvein.quests.Quester; import me.blackvein.quests.Quester;
import me.blackvein.quests.Quests; import me.blackvein.quests.Quests;
import me.blackvein.quests.Quests.ReloadCallback;
import me.blackvein.quests.Requirements; import me.blackvein.quests.Requirements;
import me.blackvein.quests.Stage; import me.blackvein.quests.Stage;
import me.blackvein.quests.events.command.QuestsCommandPreQuestsEditorEvent; import me.blackvein.quests.events.command.QuestsCommandPreQuestsEditorEvent;
@ -67,6 +68,10 @@ public class CmdExecutor implements CommandExecutor {
@Override @Override
public boolean onCommand(CommandSender cs, Command cmd, String label, String[] args) { public boolean onCommand(CommandSender cs, Command cmd, String label, String[] args) {
if (plugin.isLoading()) {
cs.sendMessage(ChatColor.RED + Lang.get("errorLoading"));
return true;
}
if (cs instanceof Player) { if (cs instanceof Player) {
if (!plugin.canUseQuests(((Player) cs).getUniqueId())) { if (!plugin.canUseQuests(((Player) cs).getUniqueId())) {
cs.sendMessage(ChatColor.RED + Lang.get((Player) cs, "noPermission")); cs.sendMessage(ChatColor.RED + Lang.get((Player) cs, "noPermission"));
@ -889,12 +894,20 @@ public class CmdExecutor implements CommandExecutor {
private void adminReload(final CommandSender cs) { private void adminReload(final CommandSender cs) {
if (cs.hasPermission("quests.admin.*") || cs.hasPermission("quests.admin.reload")) { if (cs.hasPermission("quests.admin.*") || cs.hasPermission("quests.admin.reload")) {
plugin.reloadQuests(); ReloadCallback<Boolean> callback = new ReloadCallback<Boolean>() {
cs.sendMessage(ChatColor.GOLD + Lang.get("questsReloaded")); public void execute(Boolean response) {
String msg = Lang.get("numQuestsLoaded"); if (response) {
msg = msg.replace("<number>", ChatColor.DARK_PURPLE + String.valueOf(plugin.getQuests().size()) cs.sendMessage(ChatColor.GOLD + Lang.get("questsReloaded"));
+ ChatColor.GOLD); String msg = Lang.get("numQuestsLoaded");
cs.sendMessage(ChatColor.GOLD + msg); msg = msg.replace("<number>", ChatColor.DARK_PURPLE + String.valueOf(plugin.getQuests().size())
+ ChatColor.GOLD);
cs.sendMessage(ChatColor.GOLD + msg);
} else {
cs.sendMessage(ChatColor.RED + Lang.get("unknownError"));
}
}
};
plugin.reload(callback);
} else { } else {
cs.sendMessage(ChatColor.RED + Lang.get("noPermission")); cs.sendMessage(ChatColor.RED + Lang.get("noPermission"));
} }

View File

@ -114,8 +114,15 @@ public class Lang {
} }
return orig; return orig;
} }
/**
* @deprecated Use {@link #init(Quests)}
*/
public static void loadLang(Quests plugin) throws InvalidConfigurationException, IOException { public static void loadLang(Quests plugin) throws InvalidConfigurationException, IOException {
init(plugin);
}
public static void init(Quests plugin) throws InvalidConfigurationException, IOException {
File langFile = new File(plugin.getDataFolder(), File.separator + "lang" + File.separator + iso + File.separator File langFile = new File(plugin.getDataFolder(), File.separator + "lang" + File.separator + iso + File.separator
+ "strings.yml"); + "strings.yml");
File langFile_new = new File(plugin.getDataFolder(), File.separator + "lang" + File.separator + iso File langFile_new = new File(plugin.getDataFolder(), File.separator + "lang" + File.separator + iso
@ -160,7 +167,7 @@ public class Lang {
plugin.getLogger() plugin.getLogger()
.info("If the plugin has not generated language files, ensure Quests has write permissions"); .info("If the plugin has not generated language files, ensure Quests has write permissions");
plugin.getLogger() plugin.getLogger()
.info("For help, visit https://github.com/FlyingPikachu/Quests/wiki/Casual-%E2%80%90-Translations"); .info("For help, visit https://github.com/PikaMug/Quests/wiki/Casual-%E2%80%90-Translations");
iso = "en-US"; iso = "en-US";
FileConfiguration config = YamlConfiguration FileConfiguration config = YamlConfiguration
.loadConfiguration(new InputStreamReader(plugin.getResource("strings.yml"), "UTF-8")); .loadConfiguration(new InputStreamReader(plugin.getResource("strings.yml"), "UTF-8"));

View File

@ -675,6 +675,7 @@ questErrorReadingFile: "Error reading <file>."
errorReading: "Error reading <file>, skipping..." errorReading: "Error reading <file>, skipping..."
errorReadingSuppress: "Error reading <file>, suppressing further errors." errorReadingSuppress: "Error reading <file>, suppressing further errors."
errorDataFolder: "Error: Unable to read from data folder!" errorDataFolder: "Error: Unable to read from data folder!"
errorLoading: "Quests is currently loading. Please try again later!"
unknownError: "An unknown error occurred. See console output." unknownError: "An unknown error occurred. See console output."
journalTitle: "Quest Journal" journalTitle: "Quest Journal"
journalTaken: "You take out your <journal>." journalTaken: "You take out your <journal>."