diff --git a/include/addons/addon_manager.hpp b/include/addons/addon_manager.hpp index 681d3822..cfbfd297 100644 --- a/include/addons/addon_manager.hpp +++ b/include/addons/addon_manager.hpp @@ -26,6 +26,7 @@ public: bool isInitialized() const { return luaEngine_.isInitialized(); } void saveAllSavedVariables(); + void setCharacterName(const std::string& name) { characterName_ = name; } /// Re-initialize the Lua VM and reload all addons (used by /reload). bool reload(); @@ -38,6 +39,8 @@ private: bool loadAddon(const TocFile& addon); std::string getSavedVariablesPath(const TocFile& addon) const; + std::string getSavedVariablesPerCharacterPath(const TocFile& addon) const; + std::string characterName_; }; } // namespace wowee::addons diff --git a/include/addons/toc_parser.hpp b/include/addons/toc_parser.hpp index 7bfff469..b19b4a78 100644 --- a/include/addons/toc_parser.hpp +++ b/include/addons/toc_parser.hpp @@ -18,6 +18,7 @@ struct TocFile { std::string getInterface() const; bool isLoadOnDemand() const; std::vector getSavedVariables() const; + std::vector getSavedVariablesPerCharacter() const; }; std::optional parseTocFile(const std::string& tocPath); diff --git a/src/addons/addon_manager.cpp b/src/addons/addon_manager.cpp index e826097f..ca91e92d 100644 --- a/src/addons/addon_manager.cpp +++ b/src/addons/addon_manager.cpp @@ -68,6 +68,11 @@ std::string AddonManager::getSavedVariablesPath(const TocFile& addon) const { return addon.basePath + "/" + addon.addonName + ".lua.saved"; } +std::string AddonManager::getSavedVariablesPerCharacterPath(const TocFile& addon) const { + if (characterName_.empty()) return ""; + return addon.basePath + "/" + addon.addonName + "." + characterName_ + ".lua.saved"; +} + bool AddonManager::loadAddon(const TocFile& addon) { // Load SavedVariables before addon code (so globals are available at load time) auto savedVars = addon.getSavedVariables(); @@ -76,6 +81,15 @@ bool AddonManager::loadAddon(const TocFile& addon) { luaEngine_.loadSavedVariables(svPath); LOG_DEBUG("AddonManager: loaded saved variables for '", addon.addonName, "'"); } + // Load per-character SavedVariables + auto savedVarsPC = addon.getSavedVariablesPerCharacter(); + if (!savedVarsPC.empty()) { + std::string svpcPath = getSavedVariablesPerCharacterPath(addon); + if (!svpcPath.empty()) { + luaEngine_.loadSavedVariables(svpcPath); + LOG_DEBUG("AddonManager: loaded per-character saved variables for '", addon.addonName, "'"); + } + } bool success = true; for (const auto& filename : addon.files) { @@ -120,6 +134,13 @@ void AddonManager::saveAllSavedVariables() { std::string svPath = getSavedVariablesPath(addon); luaEngine_.saveSavedVariables(svPath, savedVars); } + auto savedVarsPC = addon.getSavedVariablesPerCharacter(); + if (!savedVarsPC.empty()) { + std::string svpcPath = getSavedVariablesPerCharacterPath(addon); + if (!svpcPath.empty()) { + luaEngine_.saveSavedVariables(svpcPath, savedVarsPC); + } + } } } diff --git a/src/addons/toc_parser.cpp b/src/addons/toc_parser.cpp index 3b5c03ab..523a164a 100644 --- a/src/addons/toc_parser.cpp +++ b/src/addons/toc_parser.cpp @@ -19,17 +19,12 @@ bool TocFile::isLoadOnDemand() const { return (it != directives.end()) && it->second == "1"; } -std::vector TocFile::getSavedVariables() const { +static std::vector parseVarList(const std::string& val) { std::vector result; - auto it = directives.find("SavedVariables"); - if (it == directives.end()) return result; - // Parse comma-separated variable names - std::string val = it->second; size_t pos = 0; while (pos <= val.size()) { size_t comma = val.find(',', pos); std::string name = (comma != std::string::npos) ? val.substr(pos, comma - pos) : val.substr(pos); - // Trim whitespace size_t start = name.find_first_not_of(" \t"); size_t end = name.find_last_not_of(" \t"); if (start != std::string::npos) @@ -40,6 +35,16 @@ std::vector TocFile::getSavedVariables() const { return result; } +std::vector TocFile::getSavedVariables() const { + auto it = directives.find("SavedVariables"); + return (it != directives.end()) ? parseVarList(it->second) : std::vector{}; +} + +std::vector TocFile::getSavedVariablesPerCharacter() const { + auto it = directives.find("SavedVariablesPerCharacter"); + return (it != directives.end()) ? parseVarList(it->second) : std::vector{}; +} + std::optional parseTocFile(const std::string& tocPath) { std::ifstream f(tocPath); if (!f.is_open()) return std::nullopt; diff --git a/src/core/application.cpp b/src/core/application.cpp index 8b4aeeb0..91d6d619 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -5182,6 +5182,21 @@ void Application::loadOnlineWorldTerrain(uint32_t mapId, float x, float y, float // Load addons once per session on first world entry if (addonManager_ && !addonsLoaded_) { + // Set character name for per-character SavedVariables + if (gameHandler) { + const std::string& charName = gameHandler->lookupName(gameHandler->getPlayerGuid()); + if (!charName.empty()) { + addonManager_->setCharacterName(charName); + } else { + // Fallback: find name from character list + for (const auto& c : gameHandler->getCharacters()) { + if (c.guid == gameHandler->getPlayerGuid()) { + addonManager_->setCharacterName(c.name); + break; + } + } + } + } addonManager_->loadAllAddons(); addonsLoaded_ = true; addonManager_->fireEvent("VARIABLES_LOADED");