diff --git a/include/addons/addon_manager.hpp b/include/addons/addon_manager.hpp index c0f019c8..7983749a 100644 --- a/include/addons/addon_manager.hpp +++ b/include/addons/addon_manager.hpp @@ -18,6 +18,7 @@ public: void loadAllAddons(); bool runScript(const std::string& code); void fireEvent(const std::string& event, const std::vector& args = {}); + void update(float deltaTime); void shutdown(); const std::vector& getAddons() const { return addons_; } diff --git a/include/addons/lua_engine.hpp b/include/addons/lua_engine.hpp index 73613ef9..2ee5954c 100644 --- a/include/addons/lua_engine.hpp +++ b/include/addons/lua_engine.hpp @@ -32,6 +32,9 @@ public: // Try to dispatch a slash command via SlashCmdList. Returns true if handled. bool dispatchSlashCommand(const std::string& command, const std::string& args); + // Call OnUpdate scripts on all frames that have one. + void dispatchOnUpdate(float elapsed); + lua_State* getState() { return L_; } bool isInitialized() const { return L_ != nullptr; } diff --git a/src/addons/addon_manager.cpp b/src/addons/addon_manager.cpp index 289ae15a..ad71bcec 100644 --- a/src/addons/addon_manager.cpp +++ b/src/addons/addon_manager.cpp @@ -89,6 +89,10 @@ void AddonManager::fireEvent(const std::string& event, const std::vector extern "C" { #include @@ -375,6 +376,19 @@ static int lua_Frame_SetScript(lua_State* L) { lua_pushvalue(L, 3); lua_setfield(L, -2, scriptType); lua_pop(L, 1); + + // Track frames with OnUpdate in __WoweeOnUpdateFrames + if (strcmp(scriptType, "OnUpdate") == 0) { + lua_getglobal(L, "__WoweeOnUpdateFrames"); + if (!lua_istable(L, -1)) { lua_pop(L, 1); return 0; } + if (lua_isfunction(L, 3)) { + // Add frame to the list + int len = static_cast(lua_objlen(L, -1)); + lua_pushvalue(L, 1); + lua_rawseti(L, -2, len + 1); + } + lua_pop(L, 1); + } return 0; } @@ -673,6 +687,10 @@ void LuaEngine::registerCoreAPI() { // Frame event dispatch table lua_newtable(L_); lua_setglobal(L_, "__WoweeFrameEvents"); + + // OnUpdate frame tracking table + lua_newtable(L_); + lua_setglobal(L_, "__WoweeOnUpdateFrames"); } // ---- Event System ---- @@ -820,6 +838,43 @@ void LuaEngine::fireEvent(const std::string& eventName, lua_pop(L_, 1); // pop __WoweeFrameEvents } +void LuaEngine::dispatchOnUpdate(float elapsed) { + if (!L_) return; + + lua_getglobal(L_, "__WoweeOnUpdateFrames"); + if (!lua_istable(L_, -1)) { lua_pop(L_, 1); return; } + + int count = static_cast(lua_objlen(L_, -1)); + for (int i = 1; i <= count; i++) { + lua_rawgeti(L_, -1, i); + if (!lua_istable(L_, -1)) { lua_pop(L_, 1); continue; } + + // Check if frame is visible + lua_getfield(L_, -1, "__visible"); + bool visible = lua_toboolean(L_, -1); + lua_pop(L_, 1); + if (!visible) { lua_pop(L_, 1); continue; } + + // Get OnUpdate script + lua_getfield(L_, -1, "__scripts"); + if (lua_istable(L_, -1)) { + lua_getfield(L_, -1, "OnUpdate"); + if (lua_isfunction(L_, -1)) { + lua_pushvalue(L_, -3); // self (frame) + lua_pushnumber(L_, static_cast(elapsed)); + if (lua_pcall(L_, 2, 0, 0) != 0) { + LOG_ERROR("LuaEngine: OnUpdate error: ", lua_tostring(L_, -1)); + lua_pop(L_, 1); + } + } else { + lua_pop(L_, 1); + } + } + lua_pop(L_, 2); // pop __scripts + frame + } + lua_pop(L_, 1); // pop __WoweeOnUpdateFrames +} + bool LuaEngine::dispatchSlashCommand(const std::string& command, const std::string& args) { if (!L_) return false; diff --git a/src/core/application.cpp b/src/core/application.cpp index 33b92f25..3f199678 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -1002,6 +1002,9 @@ void Application::update(float deltaTime) { gameHandler->update(deltaTime); } }); + if (addonManager_ && addonsLoaded_) { + addonManager_->update(deltaTime); + } // Always unsheath on combat engage. inGameStep = "auto-unsheathe"; updateCheckpoint = "in_game: auto-unsheathe";