From befee1c7293ad3d8dd6fe276185b1c1f26f4013b Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Mon, 9 Jun 2025 12:49:46 -0500 Subject: [PATCH] [Quests] Support Multiple Quest, Plugin, and Lua Module Paths (#4906) * [Quests] Add Support for Multiple Load Paths * Adjust load paths * plugin != m_lua_module_directories --- common/eqemu_config.cpp | 15 + common/eqemu_config.h | 21 ++ common/path_manager.cpp | 65 ++-- common/path_manager.h | 30 +- zone/embperl.cpp | 41 ++- zone/lua_parser.cpp | 81 +++-- zone/quest_parser_collection.cpp | 592 ++++++++++++++++--------------- 7 files changed, 471 insertions(+), 374 deletions(-) diff --git a/common/eqemu_config.cpp b/common/eqemu_config.cpp index fe06c9265..453234604 100644 --- a/common/eqemu_config.cpp +++ b/common/eqemu_config.cpp @@ -177,6 +177,21 @@ void EQEmuConfig::parse_config() SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString(); LogDir = _root["server"]["directories"].get("logs", "logs/").asString(); + auto load_paths = [&](const std::string& key, std::vector& target) { + const auto& paths = _root["server"]["directories"][key]; + if (paths.isArray()) { + for (const auto& dir : paths) { + if (dir.isString()) { + target.push_back(dir.asString()); + } + } + } + }; + + load_paths("quest_paths", m_quest_directories); + load_paths("plugin_paths", m_plugin_directories); + load_paths("lua_module_paths", m_lua_module_directories); + /** * Logs */ diff --git a/common/eqemu_config.h b/common/eqemu_config.h index e3924c260..6ba637ea8 100644 --- a/common/eqemu_config.h +++ b/common/eqemu_config.h @@ -120,6 +120,22 @@ class EQEmuConfig const std::string &GetUCSHost() const; uint16 GetUCSPort() const; + std::vector GetQuestDirectories() const + { + return m_quest_directories; + } + + std::vector GetPluginsDirectories() const + { + return m_plugin_directories; + } + + std::vector GetLuaModuleDirectories() const + { + return m_lua_module_directories; + } + + // uint16 DynamicCount; // map StaticZones; @@ -133,6 +149,11 @@ class EQEmuConfig Json::Value _root; static std::string ConfigFile; + std::vector m_quest_directories = {}; + std::vector m_plugin_directories = {}; + std::vector m_lua_module_directories = {}; + + protected: void parse_config(); EQEmuConfig() diff --git a/common/path_manager.cpp b/common/path_manager.cpp index 6acdeac35..ed57f2f4a 100644 --- a/common/path_manager.cpp +++ b/common/path_manager.cpp @@ -48,10 +48,23 @@ void PathManager::LoadPaths() return dir; }; + auto load_many_paths_fallback = [&](const std::vector& dirs, const std::string& fallback, std::vector& target) { + target.clear(); + if (!dirs.empty()) { + for (const auto& path : dirs) { + target.push_back(resolve_path(path)); + } + } else { + target.push_back(resolve_path(fallback)); + } + }; + + load_many_paths_fallback(c->GetQuestDirectories(), c->QuestDir, m_quests_paths); + load_many_paths_fallback(c->GetPluginsDirectories(), c->PluginDir, m_plugin_paths); + load_many_paths_fallback(c->GetLuaModuleDirectories(), c->LuaModuleDir, m_lua_module_paths); + + // resolve all paths m_maps_path = resolve_path(c->MapDir, {"maps", "Maps"}); - m_quests_path = resolve_path(c->QuestDir); - m_plugins_path = resolve_path(c->PluginDir); - m_lua_modules_path = resolve_path(c->LuaModuleDir); m_lua_mods_path = resolve_path("mods"); m_patch_path = resolve_path(c->PatchDir); m_opcode_path = resolve_path(c->OpcodeDir); @@ -62,13 +75,10 @@ void PathManager::LoadPaths() std::vector> paths = { {"server", m_server_path}, {"logs", m_log_path}, - {"lua mods", m_lua_mods_path}, - {"lua_modules", m_lua_modules_path}, {"maps", m_maps_path}, + {"lua mods", m_lua_mods_path}, {"patches", m_patch_path}, {"opcode", m_opcode_path}, - {"plugins", m_plugins_path}, - {"quests", m_quests_path}, {"shared_memory", m_shared_memory_path} }; @@ -83,6 +93,17 @@ void PathManager::LoadPaths() LogInfo("{:>{}} > [{:<{}}]", name, name_width, in_path, path_width); } } + + auto log_paths = [&](const std::string& label, const std::vector& paths) { + if (!paths.empty()) { + LogInfo("{:>{}} > [{:<{}}]", label, name_width - 1, Strings::Join(paths, ";"), path_width); + } + }; + + log_paths("quests", m_quests_paths); + log_paths("plugins", m_plugin_paths); + log_paths("lua_modules", m_lua_module_paths); + LogInfo("{}", Strings::Repeat("-", break_length)); } @@ -96,21 +117,26 @@ const std::string &PathManager::GetMapsPath() const return m_maps_path; } -const std::string &PathManager::GetQuestsPath() const -{ - return m_quests_path; -} - -const std::string &PathManager::GetPluginsPath() const -{ - return m_plugins_path; -} - const std::string &PathManager::GetSharedMemoryPath() const { return m_shared_memory_path; } +std::vector PathManager::GetQuestPaths() const +{ + return m_quests_paths; +} + +std::vector PathManager::GetPluginPaths() const +{ + return m_plugin_paths; +} + +std::vector PathManager::GetLuaModulePaths() const +{ + return m_lua_module_paths; +} + const std::string &PathManager::GetLogPath() const { return m_log_path; @@ -126,11 +152,6 @@ const std::string &PathManager::GetOpcodePath() const return m_opcode_path; } -const std::string &PathManager::GetLuaModulesPath() const -{ - return m_lua_modules_path; -} - const std::string &PathManager::GetLuaModsPath() const { return m_lua_mods_path; diff --git a/common/path_manager.h b/common/path_manager.h index 3ef55d0a7..55cc1489c 100644 --- a/common/path_manager.h +++ b/common/path_manager.h @@ -3,6 +3,7 @@ #include +#include class PathManager { public: @@ -14,22 +15,27 @@ public: [[nodiscard]] const std::string &GetMapsPath() const; [[nodiscard]] const std::string &GetPatchPath() const; [[nodiscard]] const std::string &GetOpcodePath() const; - [[nodiscard]] const std::string &GetPluginsPath() const; - [[nodiscard]] const std::string &GetQuestsPath() const; [[nodiscard]] const std::string &GetServerPath() const; [[nodiscard]] const std::string &GetSharedMemoryPath() const; + [[nodiscard]] std::vector GetQuestPaths() const; + [[nodiscard]] std::vector GetPluginPaths() const; + [[nodiscard]] std::vector GetLuaModulePaths() const; private: - std::string m_log_path; - std::string m_lua_mods_path; - std::string m_lua_modules_path; - std::string m_maps_path; - std::string m_patch_path; - std::string m_opcode_path; - std::string m_plugins_path; - std::string m_quests_path; - std::string m_server_path; - std::string m_shared_memory_path; + std::string m_log_path; + std::string m_lua_mods_path; + std::string m_maps_path; + std::string m_patch_path; + std::string m_opcode_path; + std::string m_quests_path; + std::vector m_quests_paths; + std::vector m_plugin_paths; + std::vector m_lua_module_paths; + + +private: + std::string m_server_path; + std::string m_shared_memory_path; }; extern PathManager path; diff --git a/zone/embperl.cpp b/zone/embperl.cpp index 21a82f111..799669ec3 100644 --- a/zone/embperl.cpp +++ b/zone/embperl.cpp @@ -137,25 +137,28 @@ void Embperl::DoInit() catch (std::string& e) { LogQuests("Warning [{}]: [{}]", Config->PluginPlFile, e); } - try { - //should probably read the directory in c, instead, so that - //I can echo filenames as I do it, but c'mon... I'm lazy and this 1 line reads in all the plugins - const std::string& perl_command = ( - "if(opendir(D,'" + - path.GetPluginsPath() + - "')) { " - " my @d = readdir(D);" - " closedir(D);" - " foreach(@d){ " - " main::eval_file('plugin','" + - path.GetPluginsPath() + - "/'.$_)if/\\.pl$/;" - " }" - "}"); - eval_pv(perl_command.c_str(), FALSE); - } - catch (std::string& e) { - LogQuests("Warning [{}]", e); + + for (auto & dir : path.GetPluginPaths()) { + try { + //should probably read the directory in c, instead, so that + //I can echo filenames as I do it, but c'mon... I'm lazy and this 1 line reads in all the plugins + const std::string& perl_command = ( + "if(opendir(D,'" + + dir + + "')) { " + " my @d = readdir(D);" + " closedir(D);" + " foreach(@d){ " + " main::eval_file('plugin','" + + dir + + "/'.$_)if/\\.pl$/;" + " }" + "}"); + eval_pv(perl_command.c_str(), FALSE); + } + catch (std::string& e) { + LogQuests("Warning [{}]", e); + } } #endif //EMBPERL_PLUGIN } diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index fa684a490..bd3544b6a 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -1067,13 +1067,16 @@ void LuaParser::ReloadQuests() { lua_getglobal(L, "package"); lua_getfield(L, -1, "path"); - std::string module_path = lua_tostring(L,-1); - module_path += ";" + path.GetLuaModulesPath() + "/?.lua;" + path.GetLuaModulesPath() + "/?/init.lua"; - // luarock paths using lua_modules as tree - // to path it adds foo/share/lua/5.1/?.lua and foo/share/lua/5.1/?/init.lua - module_path += ";" + path.GetLuaModulesPath() + "/share/lua/" + lua_version + "/?.lua"; - module_path += ";" + path.GetLuaModulesPath() + "/share/lua/" + lua_version + "/?/init.lua"; + std::string module_path = lua_tostring(L, -1); lua_pop(L, 1); + + for (const auto& dir : path.GetLuaModulePaths()) { + module_path += fmt::format(";{}/?.lua", dir); + module_path += fmt::format(";{}/?/init.lua", dir); + module_path += fmt::format(";{}/share/lua/{}/?.lua", dir, lua_version); + module_path += fmt::format(";{}/share/lua/{}/?/init.lua", dir, lua_version); + } + lua_pushstring(L, module_path.c_str()); lua_setfield(L, -2, "path"); lua_pop(L, 1); @@ -1081,11 +1084,13 @@ void LuaParser::ReloadQuests() { lua_getglobal(L, "package"); lua_getfield(L, -1, "cpath"); module_path = lua_tostring(L, -1); - module_path += ";" + path.GetLuaModulesPath() + "/?" + libext; - // luarock paths using lua_modules as tree - // luarocks adds foo/lib/lua/5.1/?.so for cpath - module_path += ";" + path.GetLuaModulesPath() + "/lib/lua/" + lua_version + "/?" + libext; lua_pop(L, 1); + + for (const auto& dir : path.GetLuaModulePaths()) { + module_path += fmt::format(";{}/?{}", dir, libext); + module_path += fmt::format(";{}/lib/lua/{}/?{}", dir, lua_version, libext); + } + lua_pushstring(L, module_path.c_str()); lua_setfield(L, -2, "cpath"); lua_pop(L, 1); @@ -1093,40 +1098,31 @@ void LuaParser::ReloadQuests() { MapFunctions(L); // load init - std::string filename = fmt::format("{}/{}/script_init.lua", path.GetQuestsPath(), QUEST_GLOBAL_DIRECTORY); + for (auto& dir : path.GetQuestPaths()) { + std::string filename = fmt::format("{}/{}/script_init.lua", dir, QUEST_GLOBAL_DIRECTORY); - FILE *f = fopen(filename.c_str(), "r"); - if(f) { - fclose(f); - - if(luaL_dofile(L, filename.c_str())) { - std::string error = lua_tostring(L, -1); - AddError(error); - } - } - - //zone init - always loads after global - if(zone) { - std::string zone_script = fmt::format( - "{}/{}/script_init_v{}.lua", - path.GetQuestsPath(), - zone->GetShortName(), - zone->GetInstanceVersion() - ); - - f = fopen(zone_script.c_str(), "r"); - if(f) { + FILE* f = fopen(filename.c_str(), "r"); + if (f) { fclose(f); - if(luaL_dofile(L, zone_script.c_str())) { + if (luaL_dofile(L, filename.c_str())) { std::string error = lua_tostring(L, -1); AddError(error); } } - else { - zone_script = fmt::format("{}/{}/script_init.lua", path.GetQuestsPath(), zone->GetShortName()); + } - f = fopen(zone_script.c_str(), "r"); + //zone init - always loads after global + if (zone) { + for (auto& dir : path.GetQuestPaths()) { + std::string zone_script = fmt::format( + "{}/{}/script_init_v{}.lua", + dir, + zone->GetShortName(), + zone->GetInstanceVersion() + ); + + FILE* f = fopen(zone_script.c_str(), "r"); if (f) { fclose(f); @@ -1135,6 +1131,19 @@ void LuaParser::ReloadQuests() { AddError(error); } } + else { + zone_script = fmt::format("{}/{}/script_init.lua", dir, zone->GetShortName()); + + f = fopen(zone_script.c_str(), "r"); + if (f) { + fclose(f); + + if (luaL_dofile(L, zone_script.c_str())) { + std::string error = lua_tostring(L, -1); + AddError(error); + } + } + } } } diff --git a/zone/quest_parser_collection.cpp b/zone/quest_parser_collection.cpp index 5a5db703d..18022b570 100644 --- a/zone/quest_parser_collection.cpp +++ b/zone/quest_parser_collection.cpp @@ -939,59 +939,61 @@ QuestInterface* QuestParserCollection::GetQIByNPCQuest(uint32 npc_id, std::strin Strings::FindReplace(npc_name, "`", "-"); - const std::string& npc_id_and_name = fmt::format( - "{}_{}", - npc_name, - npc_id - ); + for (auto & dir : path.GetQuestPaths()) { + const std::string& npc_id_and_name = fmt::format( + "{}_{}", + npc_name, + npc_id + ); - const std::string& global_path = fmt::format( - "{}/{}", - path.GetQuestsPath(), - QUEST_GLOBAL_DIRECTORY - ); + const std::string& global_path = fmt::format( + "{}/{}", + dir, + QUEST_GLOBAL_DIRECTORY + ); - const std::string& zone_path = fmt::format( - "{}/{}", - path.GetQuestsPath(), - zone->GetShortName() - ); + const std::string& zone_path = fmt::format( + "{}/{}", + dir, + zone->GetShortName() + ); - const std::string& zone_versioned_path = fmt::format( - "{}/{}/v{}", - path.GetQuestsPath(), - zone->GetShortName(), - zone->GetInstanceVersion() - ); + const std::string& zone_versioned_path = fmt::format( + "{}/{}/v{}", + dir, + zone->GetShortName(), + zone->GetInstanceVersion() + ); - std::vector file_names = { - fmt::format("{}/{}", zone_versioned_path, npc_id), // Local versioned by NPC ID (./quests/zone/v0/10.ext) - fmt::format("{}/{}", zone_versioned_path, npc_name), // Local versioned by NPC Name (./quests/zone/v0/name.ext) - fmt::format("{}/{}", zone_versioned_path, npc_id_and_name), // Local versioned by NPC ID and NPC Name (./quests/zone/v0/10_name.ext) - fmt::format("{}/{}", zone_path, npc_id), // Local by NPC ID - fmt::format("{}/{}", zone_path, npc_name), // Local by NPC Name - fmt::format("{}/{}", zone_path, npc_id_and_name), // Local by NPC ID and NPC Name - fmt::format("{}/{}", global_path, npc_id), // Global by NPC ID - fmt::format("{}/{}", global_path, npc_name), // Global by NPC ID - fmt::format("{}/{}", global_path, npc_id_and_name), // Global by NPC ID and NPC Name - fmt::format("{}/default", zone_versioned_path), // Zone Versioned Default (./quests/zone/v0/default.ext) - fmt::format("{}/default", zone_path), // Zone Default - fmt::format("{}/default", global_path), // Global Default - }; + std::vector file_names = { + fmt::format("{}/{}", zone_versioned_path, npc_id), // Local versioned by NPC ID (./quests/zone/v0/10.ext) + fmt::format("{}/{}", zone_versioned_path, npc_name), // Local versioned by NPC Name (./quests/zone/v0/name.ext) + fmt::format("{}/{}", zone_versioned_path, npc_id_and_name), // Local versioned by NPC ID and NPC Name (./quests/zone/v0/10_name.ext) + fmt::format("{}/{}", zone_path, npc_id), // Local by NPC ID + fmt::format("{}/{}", zone_path, npc_name), // Local by NPC Name + fmt::format("{}/{}", zone_path, npc_id_and_name), // Local by NPC ID and NPC Name + fmt::format("{}/{}", global_path, npc_id), // Global by NPC ID + fmt::format("{}/{}", global_path, npc_name), // Global by NPC ID + fmt::format("{}/{}", global_path, npc_id_and_name), // Global by NPC ID and NPC Name + fmt::format("{}/default", zone_versioned_path), // Zone Versioned Default (./quests/zone/v0/default.ext) + fmt::format("{}/default", zone_path), // Zone Default + fmt::format("{}/default", global_path), // Global Default + }; - std::string file_name; + std::string file_name; - for (auto & file : file_names) { - for (auto* e: _load_precedence) { - file_name = fmt::format( - "{}.{}", - file, - _extensions.find(e->GetIdentifier())->second - ); + for (auto & file : file_names) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}.{}", + file, + _extensions.find(e->GetIdentifier())->second + ); - if (File::Exists(file_name)) { - filename = file_name; - return e; + if (File::Exists(file_name)) { + filename = file_name; + return e; + } } } } @@ -1005,44 +1007,46 @@ QuestInterface* QuestParserCollection::GetQIByPlayerQuest(std::string& filename) return nullptr; } - const std::string& global_path = fmt::format( - "{}/{}", - path.GetQuestsPath(), - QUEST_GLOBAL_DIRECTORY - ); + for (auto & dir : path.GetQuestPaths()) { + const std::string& global_path = fmt::format( + "{}/{}", + dir, + QUEST_GLOBAL_DIRECTORY + ); - const std::string& zone_path = fmt::format( - "{}/{}", - path.GetQuestsPath(), - zone->GetShortName() - ); + const std::string& zone_path = fmt::format( + "{}/{}", + dir, + zone->GetShortName() + ); - const std::string& zone_versioned_path = fmt::format( - "{}/{}/v{}", - path.GetQuestsPath(), - zone->GetShortName(), - zone->GetInstanceVersion() - ); + const std::string& zone_versioned_path = fmt::format( + "{}/{}/v{}", + dir, + zone->GetShortName(), + zone->GetInstanceVersion() + ); - std::vector file_names = { - fmt::format("{}/player", zone_versioned_path), // Local by Instance Version ./quests/zone/v0/player.ext - fmt::format("{}/player_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version - fmt::format("{}/player", zone_path), // Local - fmt::format("{}/player", global_path) // Global - }; + std::vector file_names = { + fmt::format("{}/player", zone_versioned_path), // Local by Instance Version ./quests/zone/v0/player.ext + fmt::format("{}/player_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version + fmt::format("{}/player", zone_path), // Local + fmt::format("{}/player", global_path) // Global + }; - std::string file_name; - for (auto & file : file_names) { - for (auto* e: _load_precedence) { - file_name = fmt::format( - "{}.{}", - file, - _extensions.find(e->GetIdentifier())->second - ); + std::string file_name; + for (auto & file : file_names) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}.{}", + file, + _extensions.find(e->GetIdentifier())->second + ); - if (File::Exists(file_name)) { - filename = file_name; - return e; + if (File::Exists(file_name)) { + filename = file_name; + return e; + } } } } @@ -1058,17 +1062,19 @@ QuestInterface* QuestParserCollection::GetQIByGlobalNPCQuest(std::string& filena std::string file_name; - for (auto* e: _load_precedence) { - file_name = fmt::format( - "{}/{}/global_npc.{}", - path.GetQuestsPath(), - QUEST_GLOBAL_DIRECTORY, - _extensions.find(e->GetIdentifier())->second - ); + for (auto & dir : path.GetQuestPaths()) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}/{}/global_npc.{}", + dir, + QUEST_GLOBAL_DIRECTORY, + _extensions.find(e->GetIdentifier())->second + ); - if (File::Exists(file_name)) { - filename = file_name; - return e; + if (File::Exists(file_name)) { + filename = file_name; + return e; + } } } @@ -1082,17 +1088,19 @@ QuestInterface* QuestParserCollection::GetQIByGlobalPlayerQuest(std::string& fil } std::string file_name; - for (auto* e: _load_precedence) { - file_name = fmt::format( - "{}/{}/global_player.{}", - path.GetQuestsPath(), - QUEST_GLOBAL_DIRECTORY, - _extensions.find(e->GetIdentifier())->second - ); + for (auto & dir : path.GetQuestPaths()) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}/{}/global_player.{}", + dir, + QUEST_GLOBAL_DIRECTORY, + _extensions.find(e->GetIdentifier())->second + ); - if (File::Exists(file_name)) { - filename = file_name; - return e; + if (File::Exists(file_name)) { + filename = file_name; + return e; + } } } @@ -1105,45 +1113,47 @@ QuestInterface* QuestParserCollection::GetQIBySpellQuest(uint32 spell_id, std::s return nullptr; } - const std::string& global_path = fmt::format( - "{}/{}/spells", - path.GetQuestsPath(), - QUEST_GLOBAL_DIRECTORY - ); + for (auto & dir : path.GetQuestPaths()) { + const std::string& global_path = fmt::format( + "{}/{}/spells", + dir, + QUEST_GLOBAL_DIRECTORY + ); - const std::string& zone_path = fmt::format( - "{}/{}/spells", - path.GetQuestsPath(), - zone->GetShortName() - ); + const std::string& zone_path = fmt::format( + "{}/{}/spells", + dir, + zone->GetShortName() + ); - const std::string& zone_versioned_path = fmt::format( - "{}/{}/v{}/spells", - path.GetQuestsPath(), - zone->GetShortName(), - zone->GetInstanceVersion() - ); + const std::string& zone_versioned_path = fmt::format( + "{}/{}/v{}/spells", + dir, + zone->GetShortName(), + zone->GetInstanceVersion() + ); - std::vector file_names = { - fmt::format("{}/{}", zone_versioned_path, spell_id), // Local versioned by Spell ID ./quests/zone/v0/spells/10.ext - fmt::format("{}/{}", zone_path, spell_id), // Local - fmt::format("{}/{}", global_path, spell_id), // Global - fmt::format("{}/default", zone_path), // Local Default - fmt::format("{}/default", global_path) // Global Default - }; + std::vector file_names = { + fmt::format("{}/{}", zone_versioned_path, spell_id), // Local versioned by Spell ID ./quests/zone/v0/spells/10.ext + fmt::format("{}/{}", zone_path, spell_id), // Local + fmt::format("{}/{}", global_path, spell_id), // Global + fmt::format("{}/default", zone_path), // Local Default + fmt::format("{}/default", global_path) // Global Default + }; - std::string file_name; - for (auto & file : file_names) { - for (auto* e: _load_precedence) { - file_name = fmt::format( - "{}.{}", - file, - _extensions.find(e->GetIdentifier())->second - ); + std::string file_name; + for (auto & file : file_names) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}.{}", + file, + _extensions.find(e->GetIdentifier())->second + ); - if (File::Exists(file_name)) { - filename = file_name; - return e; + if (File::Exists(file_name)) { + filename = file_name; + return e; + } } } } @@ -1157,45 +1167,47 @@ QuestInterface* QuestParserCollection::GetQIByItemQuest(std::string item_script, return nullptr; } - const std::string& global_path = fmt::format( - "{}/{}/items", - path.GetQuestsPath(), - QUEST_GLOBAL_DIRECTORY - ); + for (auto & dir : path.GetQuestPaths()) { + const std::string& global_path = fmt::format( + "{}/{}/items", + dir, + QUEST_GLOBAL_DIRECTORY + ); - const std::string& zone_path = fmt::format( - "{}/{}/items", - path.GetQuestsPath(), - zone->GetShortName() - ); + const std::string& zone_path = fmt::format( + "{}/{}/items", + dir, + zone->GetShortName() + ); - const std::string& zone_versioned_path = fmt::format( - "{}/{}/v{}/items", - path.GetQuestsPath(), - zone->GetShortName(), - zone->GetInstanceVersion() - ); + const std::string& zone_versioned_path = fmt::format( + "{}/{}/v{}/items", + dir, + zone->GetShortName(), + zone->GetInstanceVersion() + ); - std::vector file_names = { - fmt::format("{}/{}", zone_versioned_path, item_script), // Local versioned by Item Script ./quests/zone/v0/items/10.ext - fmt::format("{}/{}", zone_path, item_script), // Local - fmt::format("{}/{}", global_path, item_script), // Global - fmt::format("{}/default", zone_path), // Local Default - fmt::format("{}/default", global_path) // Global Default - }; + std::vector file_names = { + fmt::format("{}/{}", zone_versioned_path, item_script), // Local versioned by Item Script ./quests/zone/v0/items/10.ext + fmt::format("{}/{}", zone_path, item_script), // Local + fmt::format("{}/{}", global_path, item_script), // Global + fmt::format("{}/default", zone_path), // Local Default + fmt::format("{}/default", global_path) // Global Default + }; - std::string file_name; - for (auto & file : file_names) { - for (auto* e: _load_precedence) { - file_name = fmt::format( - "{}.{}", - file, - _extensions.find(e->GetIdentifier())->second - ); + std::string file_name; + for (auto & file : file_names) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}.{}", + file, + _extensions.find(e->GetIdentifier())->second + ); - if (File::Exists(file_name)) { - filename = file_name; - return e; + if (File::Exists(file_name)) { + filename = file_name; + return e; + } } } } @@ -1209,43 +1221,45 @@ QuestInterface* QuestParserCollection::GetQIByEncounterQuest(std::string encount return nullptr; } - const std::string& global_path = fmt::format( - "{}/{}/encounters", - path.GetQuestsPath(), - QUEST_GLOBAL_DIRECTORY - ); + for (auto & dir : path.GetQuestPaths()) { + const std::string& global_path = fmt::format( + "{}/{}/encounters", + dir, + QUEST_GLOBAL_DIRECTORY + ); - const std::string& zone_path = fmt::format( - "{}/{}/encounters", - path.GetQuestsPath(), - zone->GetShortName() - ); + const std::string& zone_path = fmt::format( + "{}/{}/encounters", + dir, + zone->GetShortName() + ); - const std::string& zone_versioned_path = fmt::format( - "{}/{}/v{}/encounters", - path.GetQuestsPath(), - zone->GetShortName(), - zone->GetInstanceVersion() - ); + const std::string& zone_versioned_path = fmt::format( + "{}/{}/v{}/encounters", + dir, + zone->GetShortName(), + zone->GetInstanceVersion() + ); - std::vector file_names = { - fmt::format("{}/{}", zone_versioned_path, encounter_name), // Local versioned ./quests/zone/v0/encounters/name.ext - fmt::format("{}/{}", zone_path, encounter_name), // Local - fmt::format("{}/{}", global_path, encounter_name) // Global - }; + std::vector file_names = { + fmt::format("{}/{}", zone_versioned_path, encounter_name), // Local versioned ./quests/zone/v0/encounters/name.ext + fmt::format("{}/{}", zone_path, encounter_name), // Local + fmt::format("{}/{}", global_path, encounter_name) // Global + }; - std::string file_name; - for (auto & file : file_names) { - for (auto* e: _load_precedence) { - file_name = fmt::format( - "{}.{}", - file, - _extensions.find(e->GetIdentifier())->second - ); + std::string file_name; + for (auto & file : file_names) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}.{}", + file, + _extensions.find(e->GetIdentifier())->second + ); - if (File::Exists(file_name)) { - filename = file_name; - return e; + if (File::Exists(file_name)) { + filename = file_name; + return e; + } } } } @@ -1259,44 +1273,46 @@ QuestInterface* QuestParserCollection::GetQIByBotQuest(std::string& filename) return nullptr; } - const std::string& global_path = fmt::format( - "{}/{}", - path.GetQuestsPath(), - QUEST_GLOBAL_DIRECTORY - ); + for (auto & dir : path.GetQuestPaths()) { + const std::string& global_path = fmt::format( + "{}/{}", + dir, + QUEST_GLOBAL_DIRECTORY + ); - const std::string& zone_path = fmt::format( - "{}/{}", - path.GetQuestsPath(), - zone->GetShortName() - ); + const std::string& zone_path = fmt::format( + "{}/{}", + dir, + zone->GetShortName() + ); - const std::string& zone_versioned_path = fmt::format( - "{}/{}/v{}", - path.GetQuestsPath(), - zone->GetShortName(), - zone->GetInstanceVersion() - ); + const std::string& zone_versioned_path = fmt::format( + "{}/{}/v{}", + dir, + zone->GetShortName(), + zone->GetInstanceVersion() + ); - std::vector file_names = { - fmt::format("{}/bot", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/bot.ext - fmt::format("{}/bot_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version - fmt::format("{}/bot", zone_path), // Local - fmt::format("{}/bot", global_path) // Global - }; + std::vector file_names = { + fmt::format("{}/bot", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/bot.ext + fmt::format("{}/bot_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version + fmt::format("{}/bot", zone_path), // Local + fmt::format("{}/bot", global_path) // Global + }; - std::string file_name; - for (auto & file : file_names) { - for (auto* e: _load_precedence) { - file_name = fmt::format( - "{}.{}", - file, - _extensions.find(e->GetIdentifier())->second - ); + std::string file_name; + for (auto & file : file_names) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}.{}", + file, + _extensions.find(e->GetIdentifier())->second + ); - if (File::Exists(file_name)) { - filename = file_name; - return e; + if (File::Exists(file_name)) { + filename = file_name; + return e; + } } } } @@ -1311,17 +1327,19 @@ QuestInterface* QuestParserCollection::GetQIByGlobalBotQuest(std::string& filena } std::string file_name; - for (auto* e: _load_precedence) { - file_name = fmt::format( - "{}/{}/global_bot.{}", - path.GetQuestsPath(), - QUEST_GLOBAL_DIRECTORY, - _extensions.find(e->GetIdentifier())->second - ); + for (auto & dir : path.GetQuestPaths()) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}/{}/global_bot.{}", + dir, + QUEST_GLOBAL_DIRECTORY, + _extensions.find(e->GetIdentifier())->second + ); - if (File::Exists(file_name)) { - filename = file_name; - return e; + if (File::Exists(file_name)) { + filename = file_name; + return e; + } } } @@ -1334,44 +1352,46 @@ QuestInterface* QuestParserCollection::GetQIByMercQuest(std::string& filename) return nullptr; } - const std::string& global_path = fmt::format( - "{}/{}", - path.GetQuestsPath(), - QUEST_GLOBAL_DIRECTORY - ); + for (auto & dir : path.GetQuestPaths()) { + const std::string& global_path = fmt::format( + "{}/{}", + dir, + QUEST_GLOBAL_DIRECTORY + ); - const std::string& zone_path = fmt::format( - "{}/{}", - path.GetQuestsPath(), - zone->GetShortName() - ); + const std::string& zone_path = fmt::format( + "{}/{}", + dir, + zone->GetShortName() + ); - const std::string& zone_versioned_path = fmt::format( - "{}/{}/v{}", - path.GetQuestsPath(), - zone->GetShortName(), - zone->GetInstanceVersion() - ); + const std::string& zone_versioned_path = fmt::format( + "{}/{}/v{}", + dir, + zone->GetShortName(), + zone->GetInstanceVersion() + ); - std::vector file_names = { - fmt::format("{}/merc", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/merc.ext - fmt::format("{}/merc_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version - fmt::format("{}/merc", zone_path), // Local - fmt::format("{}/merc", global_path) // Global - }; + std::vector file_names = { + fmt::format("{}/merc", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/merc.ext + fmt::format("{}/merc_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version + fmt::format("{}/merc", zone_path), // Local + fmt::format("{}/merc", global_path) // Global + }; - std::string file_name; - for (auto & file : file_names) { - for (auto* e: _load_precedence) { - file_name = fmt::format( - "{}.{}", - file, - _extensions.find(e->GetIdentifier())->second - ); + std::string file_name; + for (auto & file : file_names) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}.{}", + file, + _extensions.find(e->GetIdentifier())->second + ); - if (File::Exists(file_name)) { - filename = file_name; - return e; + if (File::Exists(file_name)) { + filename = file_name; + return e; + } } } } @@ -1386,17 +1406,19 @@ QuestInterface* QuestParserCollection::GetQIByGlobalMercQuest(std::string& filen } std::string file_name; - for (auto* e: _load_precedence) { - file_name = fmt::format( - "{}/{}/global_merc.{}", - path.GetQuestsPath(), - QUEST_GLOBAL_DIRECTORY, - _extensions.find(e->GetIdentifier())->second - ); + for (auto & dir : path.GetQuestPaths()) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}/{}/global_merc.{}", + dir, + QUEST_GLOBAL_DIRECTORY, + _extensions.find(e->GetIdentifier())->second + ); - if (File::Exists(file_name)) { - filename = file_name; - return e; + if (File::Exists(file_name)) { + filename = file_name; + return e; + } } }