diff --git a/api/lua/definition/poptracker.lua b/api/lua/definition/poptracker.lua index dda9a733..d4fd0a84 100644 --- a/api/lua/definition/poptracker.lua +++ b/api/lua/definition/poptracker.lua @@ -148,12 +148,14 @@ function ScriptHost:RemoveVariableWatch(name) end function ScriptHost:CreateLuaItem() end ---Add a handler/callback that runs on every frame. +---Available since 0.25.9. ---@param name string identifier/name of this callback ----@param callback fun():nil called every frame +---@param callback fun(elapsedSeconds:number):nil called every frame, argument is elapsed time in seconds since last call ---@return string reference for RemoveOnFrameHandler function ScriptHost:AddOnFrameHandler(name, callback) end ---Remove a handler/callback added by AddOnFrameHandler(name). +---Available since 0.25.9. ---@param name string identifier/name of the handler to remove ---@return boolean true on success function ScriptHost:RemoveOnFrameHandler(name) end diff --git a/doc/PACKS.md b/doc/PACKS.md index a50e3168..3ae317aa 100644 --- a/doc/PACKS.md +++ b/doc/PACKS.md @@ -125,6 +125,8 @@ The following interfaces are provided: * `ref :AddWatchForCode(name,code,callback)`: callback(code) will be called whenever an item changed state that canProvide(code). Only available in PopTracker, since 0.11.0, will return a reference (name) to the watch since 0.18.2. Use "*" to trigger for all codes since 0.25.5. * `bool :RemoveWatchForCode(name)`: remove watch by name * `LuaItem :CreateLuaItem()`: create a LuaItem (custom item) instance +* `ref :AddOnFrameHandler(name,callback)`: callback(elapsed) will be called every frame, available since 0.25.9 +* `bool :RemoveOnFrameHandler(name)`: remove a frame callback ### global AutoTracker diff --git a/src/core/scripthost.cpp b/src/core/scripthost.cpp index 345b6801..00cda651 100644 --- a/src/core/scripthost.cpp +++ b/src/core/scripthost.cpp @@ -362,16 +362,16 @@ std::string ScriptHost::AddOnFrameHandler(const std::string& name, LuaRef callba RemoveOnFrameHandler(name); if (!callback.valid()) luaL_error(_L, "Invalid callback"); - _onFrameCallbacks.push_back({name, callback}); + _onFrameHandlers.push_back(OnFrameHandler{callback.ref, name, Ui::getMicroTicks()}); return name; } bool ScriptHost::RemoveOnFrameHandler(const std::string& name) { - for (auto it = _onFrameCallbacks.begin(); it != _onFrameCallbacks.end(); it++) { - if (it->first == name) { - luaL_unref(_L, LUA_REGISTRYINDEX, it->second.ref); - _onFrameCallbacks.erase(it); + for (auto it = _onFrameHandlers.begin(); it != _onFrameHandlers.end(); it++) { + if (it->name == name) { + luaL_unref(_L, LUA_REGISTRYINDEX, it->callback); + _onFrameHandlers.erase(it); return true; } } @@ -396,15 +396,22 @@ bool ScriptHost::onFrame() { bool res = autoTrack(); - for (size_t i=0; i<_onFrameCallbacks.size(); i++) { - auto name = _onFrameCallbacks[i].first; + for (size_t i=0; i<_onFrameHandlers.size(); i++) { + auto name = _onFrameHandlers[i].name; + auto now = Ui::getMicroTicks(); + auto elapsedUs = now - _onFrameHandlers[i].lastTimestamp; + double elapsed = (double)elapsedUs / 1000000.0; + _onFrameHandlers[i].lastTimestamp = now; // For now we use the same exec limit as in Tracker, which is 3-4ms for pure Lua on a fast PC. - runLuaFunction(_onFrameCallbacks[i].second.ref, name, nullptr, Tracker::getExecLimit()); + runLuaFunction(_onFrameHandlers[i].callback, name, [elapsed](lua_State *L) { + Lua(L).Push(elapsed); + return 1; + }, Tracker::getExecLimit()); - if (_onFrameCallbacks.size() <= i) + if (_onFrameHandlers.size() <= i) break; // callback does not exist anymore - if (_onFrameCallbacks[i].first != name) + if (_onFrameHandlers[i].name != name) i--; // callback was modified in callback } diff --git a/src/core/scripthost.h b/src/core/scripthost.h index b57ebabe..1fa7a396 100644 --- a/src/core/scripthost.h +++ b/src/core/scripthost.h @@ -10,6 +10,7 @@ #include "luaitem.h" #include #include // TODO: replace by new[] uint8_t? +#include "../uilib/timer.h" class ScriptHost; @@ -59,7 +60,14 @@ class ScriptHost : public LuaInterface { int callback; std::set names; }; - + + struct OnFrameHandler + { + int callback; + std::string name; + Ui::microtick_t lastTimestamp; + }; + protected: lua_State *_L; Pack *_pack; @@ -67,7 +75,7 @@ class ScriptHost : public LuaInterface { std::vector _memoryWatches; std::vector > _codeWatches; std::vector > _varWatches; - std::vector > _onFrameCallbacks; + std::vector _onFrameHandlers; AutoTracker *_autoTracker = nullptr; private: