feat: add /reload command to re-initialize addon system

Add AddonManager::reload() which saves all SavedVariables, shuts down the
Lua VM, re-initializes it, rescans .toc files, and reloads all addons.
Wire /reload, /reloadui, /rl slash commands that call reload() and fire
VARIABLES_LOADED + PLAYER_LOGIN + PLAYER_ENTERING_WORLD lifecycle events.
Essential for addon development and troubleshooting.
This commit is contained in:
Kelsi 2026-03-20 16:17:04 -07:00
parent 23ebfc7e85
commit 21ead2aa4b
3 changed files with 51 additions and 0 deletions

View file

@ -27,9 +27,14 @@ public:
void saveAllSavedVariables(); void saveAllSavedVariables();
/// Re-initialize the Lua VM and reload all addons (used by /reload).
bool reload();
private: private:
LuaEngine luaEngine_; LuaEngine luaEngine_;
std::vector<TocFile> addons_; std::vector<TocFile> addons_;
game::GameHandler* gameHandler_ = nullptr;
std::string addonsPath_;
bool loadAddon(const TocFile& addon); bool loadAddon(const TocFile& addon);
std::string getSavedVariablesPath(const TocFile& addon) const; std::string getSavedVariablesPath(const TocFile& addon) const;

View file

@ -11,12 +11,14 @@ AddonManager::AddonManager() = default;
AddonManager::~AddonManager() { shutdown(); } AddonManager::~AddonManager() { shutdown(); }
bool AddonManager::initialize(game::GameHandler* gameHandler) { bool AddonManager::initialize(game::GameHandler* gameHandler) {
gameHandler_ = gameHandler;
if (!luaEngine_.initialize()) return false; if (!luaEngine_.initialize()) return false;
luaEngine_.setGameHandler(gameHandler); luaEngine_.setGameHandler(gameHandler);
return true; return true;
} }
void AddonManager::scanAddons(const std::string& addonsPath) { void AddonManager::scanAddons(const std::string& addonsPath) {
addonsPath_ = addonsPath;
addons_.clear(); addons_.clear();
std::error_code ec; std::error_code ec;
@ -121,6 +123,26 @@ void AddonManager::saveAllSavedVariables() {
} }
} }
bool AddonManager::reload() {
LOG_INFO("AddonManager: reloading all addons...");
saveAllSavedVariables();
addons_.clear();
luaEngine_.shutdown();
if (!luaEngine_.initialize()) {
LOG_ERROR("AddonManager: failed to reinitialize Lua VM during reload");
return false;
}
luaEngine_.setGameHandler(gameHandler_);
if (!addonsPath_.empty()) {
scanAddons(addonsPath_);
loadAllAddons();
}
LOG_INFO("AddonManager: reload complete");
return true;
}
void AddonManager::shutdown() { void AddonManager::shutdown() {
saveAllSavedVariables(); saveAllSavedVariables();
addons_.clear(); addons_.clear();

View file

@ -6035,6 +6035,30 @@ void GameScreen::sendChatMessage(game::GameHandler& gameHandler) {
return; return;
} }
// /reload or /reloadui — reload all addons (save variables, re-init Lua, re-scan .toc files)
if (cmdLower == "reload" || cmdLower == "reloadui" || cmdLower == "rl") {
auto* am = core::Application::getInstance().getAddonManager();
if (am) {
am->reload();
am->fireEvent("VARIABLES_LOADED");
am->fireEvent("PLAYER_LOGIN");
am->fireEvent("PLAYER_ENTERING_WORLD");
game::MessageChatData rlMsg;
rlMsg.type = game::ChatType::SYSTEM;
rlMsg.language = game::ChatLanguage::UNIVERSAL;
rlMsg.message = "Interface reloaded.";
gameHandler.addLocalChatMessage(rlMsg);
} else {
game::MessageChatData rlMsg;
rlMsg.type = game::ChatType::SYSTEM;
rlMsg.language = game::ChatLanguage::UNIVERSAL;
rlMsg.message = "Addon system not available.";
gameHandler.addLocalChatMessage(rlMsg);
}
chatInputBuffer[0] = '\0';
return;
}
// /stopmacro [conditions] // /stopmacro [conditions]
// Halts execution of the current macro (remaining lines are skipped). // Halts execution of the current macro (remaining lines are skipped).
// With a condition block, only stops if the conditions evaluate to true. // With a condition block, only stops if the conditions evaluate to true.