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 me.blackvein.quests.Quests.ReloadCallback;
import me.blackvein.quests.actions.Action;
import me.blackvein.quests.convo.quests.QuestsEditorNumericPrompt;
import me.blackvein.quests.convo.quests.QuestsEditorStringPrompt;
@ -1059,7 +1060,7 @@ public class QuestFactory implements ConversationAbandonedListener {
}
private void deleteQuest(ConversationContext context) {
YamlConfiguration data = new YamlConfiguration();
FileConfiguration data = new YamlConfiguration();
File questsFile = new File(plugin.getDataFolder(), "quests.yml");
try {
data.load(questsFile);
@ -1088,7 +1089,14 @@ public class QuestFactory implements ConversationAbandonedListener {
((Player) context.getForWhom()).sendMessage(ChatColor.RED + Lang.get("questSaveError"));
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"));
}

View File

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

View File

@ -98,6 +98,7 @@ import net.citizensnpcs.api.npc.NPC;
public class Quests extends JavaPlugin implements ConversationAbandonedListener {
private boolean loading = true;
private String bukkitVersion = "0";
private Dependencies depends;
private Settings settings;
@ -106,7 +107,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
private final List<CustomObjective> customObjectives = new LinkedList<CustomObjective>();
private LinkedList<Quester> questers = new LinkedList<Quester>();
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 CommandExecutor cmdExecutor;
private ConversationFactory conversationFactory;
@ -220,6 +221,10 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
}
}
public boolean isLoading() {
return loading;
}
public String getDetectedBukkitVersion() {
return bukkitVersion;
}
@ -279,11 +284,11 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
}
public LinkedList<Action> getActions() {
return events;
return actions;
}
public void setActions(LinkedList<Action> actions) {
this.events = actions;
this.actions = actions;
}
public LinkedList<Quester> getQuesters() {
@ -411,7 +416,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
jar.close();
}
try {
Lang.loadLang(this);
Lang.init(this);
} catch (InvalidConfigurationException e) {
e.printStackTrace();
}
@ -470,7 +475,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
/**
* 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) {
getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
@ -480,9 +485,18 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
loadQuests();
loadActions();
getLogger().log(Level.INFO, "Loaded " + quests.size() + " Quest(s)"
+ ", " + events.size() + " Action(s)"
+ ", " + actions.size() + " Action(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().getNPCRegistry() == null) {
getLogger().log(Level.SEVERE,
@ -491,6 +505,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
}
}
loadModules();
loading = false;
}
}, ticks);
}
@ -525,7 +540,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
if (config.contains("quests")) {
questsSection = config.getConfigurationSection("quests");
for (String questKey : questsSection.getKeys(false)) {
try { // main "skip quest" try/catch block
try {
Quest quest = new Quest();
failedToLoad = false;
if (config.contains("quests." + questKey + ".name")) {
@ -535,7 +550,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
} else {
throw new QuestFormatException("Quest block is missing", questKey);
}
if (failedToLoad == true) {
if (failedToLoad) {
getLogger().log(Level.SEVERE, "Failed to load Quest \"" + questKey + "\". Skipping.");
}
} 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
*/
public void reloadQuests() {
for (Quester quester : questers) {
quester.saveData();
}
quests.clear();
events.clear();
loadQuests();
loadActions();
// Reload config from disc in-case a setting was changed
public void reload(final ReloadCallback<Boolean> callback) {
reloadConfig();
settings.init();
Lang.clear();
try {
Lang.loadLang(this);
} catch (InvalidConfigurationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
loadModules();
for (Quester quester : questers) {
quester.loadData();
for (Quest q : quester.currentQuests.keySet()) {
quester.checkQuest(q);
Bukkit.getScheduler().runTaskAsynchronously(this, new Runnable() {
@Override
public void run() {
loading = true;
try {
for (Quester quester : questers) {
quester.saveData();
}
quests.clear();
actions.clear();
Lang.clear();
settings.init();
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
*
* @deprecated Use {@link Bukkit#getOnlinePlayers()} and then {@link #getQuester(UUID)}
* @return list of online Questers
*/
public LinkedList<Quester> getOnlineQuesters() {
@ -2936,7 +2986,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
for (String s : sec.getKeys(false)) {
Action event = Action.loadAction(s, this);
if (event != null) {
events.add(event);
actions.add(event);
} else {
getLogger().log(Level.SEVERE, "Failed to load Action \"" + s + "\". Skipping.");
}
@ -3090,7 +3140,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
if (name == null) {
return null;
}
LinkedList<Action> as = events;
LinkedList<Action> as = actions;
for (Action a : as) {
if (a.getName().equalsIgnoreCase(ChatColor.translateAlternateColorCodes('&', name))) {
return a;

View File

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

View File

@ -50,6 +50,7 @@ import me.blackvein.quests.QuestMob;
import me.blackvein.quests.Quester;
import me.blackvein.quests.Quests;
import me.blackvein.quests.Stage;
import me.blackvein.quests.Quests.ReloadCallback;
import me.blackvein.quests.convo.actions.ActionsEditorNumericPrompt;
import me.blackvein.quests.convo.actions.ActionsEditorStringPrompt;
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"));
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"));
for (Quester q : plugin.getQuesters()) {
for (Quest quest : q.getCurrentQuests().keySet()) {
@ -1324,7 +1332,14 @@ public class ActionFactory implements ConversationAbandonedListener {
((Player) context.getForWhom()).sendMessage(ChatColor.RED + Lang.get("eventEditorErrorSaving"));
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"));
for (Quester q : plugin.getQuesters()) {
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.Quester;
import me.blackvein.quests.Quests;
import me.blackvein.quests.Quests.ReloadCallback;
import me.blackvein.quests.Requirements;
import me.blackvein.quests.Stage;
import me.blackvein.quests.events.command.QuestsCommandPreQuestsEditorEvent;
@ -67,6 +68,10 @@ public class CmdExecutor implements CommandExecutor {
@Override
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 (!plugin.canUseQuests(((Player) cs).getUniqueId())) {
cs.sendMessage(ChatColor.RED + Lang.get((Player) cs, "noPermission"));
@ -889,12 +894,20 @@ public class CmdExecutor implements CommandExecutor {
private void adminReload(final CommandSender cs) {
if (cs.hasPermission("quests.admin.*") || cs.hasPermission("quests.admin.reload")) {
plugin.reloadQuests();
cs.sendMessage(ChatColor.GOLD + Lang.get("questsReloaded"));
String msg = Lang.get("numQuestsLoaded");
msg = msg.replace("<number>", ChatColor.DARK_PURPLE + String.valueOf(plugin.getQuests().size())
+ ChatColor.GOLD);
cs.sendMessage(ChatColor.GOLD + msg);
ReloadCallback<Boolean> callback = new ReloadCallback<Boolean>() {
public void execute(Boolean response) {
if (response) {
cs.sendMessage(ChatColor.GOLD + Lang.get("questsReloaded"));
String msg = Lang.get("numQuestsLoaded");
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 {
cs.sendMessage(ChatColor.RED + Lang.get("noPermission"));
}

View File

@ -114,8 +114,15 @@ public class Lang {
}
return orig;
}
/**
* @deprecated Use {@link #init(Quests)}
*/
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
+ "strings.yml");
File langFile_new = new File(plugin.getDataFolder(), File.separator + "lang" + File.separator + iso
@ -160,7 +167,7 @@ public class Lang {
plugin.getLogger()
.info("If the plugin has not generated language files, ensure Quests has write permissions");
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";
FileConfiguration config = YamlConfiguration
.loadConfiguration(new InputStreamReader(plugin.getResource("strings.yml"), "UTF-8"));

View File

@ -675,6 +675,7 @@ questErrorReadingFile: "Error reading <file>."
errorReading: "Error reading <file>, skipping..."
errorReadingSuppress: "Error reading <file>, suppressing further errors."
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."
journalTitle: "Quest Journal"
journalTaken: "You take out your <journal>."