From 19b8d31da21da09298cff3df2453717887c3818d Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 21 Mar 2026 06:00:06 -0700 Subject: [PATCH] feat: display Lua addon errors as in-game UI errors Previously Lua addon errors only logged to the log file. Now they display as red UI error text to the player (same as spell errors and game warnings), helping addon developers debug issues in real-time. Add LuaErrorCallback to LuaEngine, fire it from event handler and frame OnEvent pcall error paths. Wire the callback to GameHandler's addUIError in application.cpp. --- include/addons/lua_engine.hpp | 6 ++++++ src/addons/lua_engine.cpp | 10 +++++++--- src/core/application.cpp | 4 ++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/addons/lua_engine.hpp b/include/addons/lua_engine.hpp index 4a0027bb..6302a64c 100644 --- a/include/addons/lua_engine.hpp +++ b/include/addons/lua_engine.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -47,9 +48,14 @@ public: lua_State* getState() { return L_; } bool isInitialized() const { return L_ != nullptr; } + // Optional callback for Lua errors (displayed as UI errors to the player) + using LuaErrorCallback = std::function; + void setLuaErrorCallback(LuaErrorCallback cb) { luaErrorCallback_ = std::move(cb); } + private: lua_State* L_ = nullptr; game::GameHandler* gameHandler_ = nullptr; + LuaErrorCallback luaErrorCallback_; void registerCoreAPI(); void registerEventAPI(); diff --git a/src/addons/lua_engine.cpp b/src/addons/lua_engine.cpp index 0c54d838..f64eabfb 100644 --- a/src/addons/lua_engine.cpp +++ b/src/addons/lua_engine.cpp @@ -3820,8 +3820,9 @@ void LuaEngine::fireEvent(const std::string& eventName, int nargs = 1 + static_cast(args.size()); if (lua_pcall(L_, nargs, 0, 0) != 0) { const char* err = lua_tostring(L_, -1); - LOG_ERROR("LuaEngine: event '", eventName, "' handler error: ", - err ? err : "(unknown)"); + std::string errStr = err ? err : "(unknown)"; + LOG_ERROR("LuaEngine: event '", eventName, "' handler error: ", errStr); + if (luaErrorCallback_) luaErrorCallback_(errStr); lua_pop(L_, 1); } } @@ -3847,7 +3848,10 @@ void LuaEngine::fireEvent(const std::string& eventName, for (const auto& arg : args) lua_pushstring(L_, arg.c_str()); int nargs = 2 + static_cast(args.size()); if (lua_pcall(L_, nargs, 0, 0) != 0) { - LOG_ERROR("LuaEngine: frame OnEvent error: ", lua_tostring(L_, -1)); + const char* ferr = lua_tostring(L_, -1); + std::string ferrStr = ferr ? ferr : "(unknown)"; + LOG_ERROR("LuaEngine: frame OnEvent error: ", ferrStr); + if (luaErrorCallback_) luaErrorCallback_(ferrStr); lua_pop(L_, 1); } } else { diff --git a/src/core/application.cpp b/src/core/application.cpp index ea1a2a7a..63b2c2f9 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -335,6 +335,10 @@ bool Application::initialize() { if (addonManager_->initialize(gameHandler.get())) { std::string addonsDir = assetPath + "/interface/AddOns"; addonManager_->scanAddons(addonsDir); + // Wire Lua errors to UI error display + addonManager_->getLuaEngine()->setLuaErrorCallback([gh = gameHandler.get()](const std::string& err) { + if (gh) gh->addUIError(err); + }); // Wire chat messages to addon event dispatch gameHandler->setAddonChatCallback([this](const game::MessageChatData& msg) { if (!addonManager_ || !addonsLoaded_) return;