From e56ee2c73519f26afa728860bb6bc23813a24774 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Wed, 17 Nov 2021 03:05:50 +0100 Subject: [PATCH] Apply lua handlers for user input in the main thread in order to reduce latency. --- apps/openmw/engine.cpp | 5 +++- apps/openmw/mwlua/luamanagerimp.cpp | 23 +++++++++++-------- apps/openmw/mwlua/luamanagerimp.hpp | 2 +- apps/openmw/mwlua/playerscripts.hpp | 5 +++- .../lua-scripting/engine_handlers.rst | 5 +++- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 67944e4546..70d5a26c7a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -293,6 +293,10 @@ bool OMW::Engine::frame(float frametime) // Main menu opened? Then scripts are also paused. bool paused = mEnvironment.getWindowManager()->containsMode(MWGui::GM_MainMenu); + // Should be called after input manager update and before any change to the game world. + // It applies to the game world queued changes from the previous frame. + mLuaManager->synchronizedUpdate(paused, frametime); + // update game state { ScopedProfile profile(frameStart, frameNumber, *timer, *stats); @@ -874,7 +878,6 @@ public: } else update(); - mEngine->mLuaManager->applyQueuedChanges(); }; void join() diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index dae11513b5..f55ca20f02 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -132,14 +132,6 @@ namespace MWLua mQueuedCallbacks.clear(); // Engine handlers in local scripts - PlayerScripts* playerScripts = dynamic_cast(mPlayer.getRefData().getLuaScripts()); - if (playerScripts && !paused) - { - for (const auto& event : mInputEvents) - playerScripts->processInputEvent(event); - } - mInputEvents.clear(); - for (const LocalEngineEvent& e : mLocalEngineEvents) { LObject obj(e.mDest, objectRegistry); @@ -180,8 +172,21 @@ namespace MWLua mGlobalScripts.update(dt); } - void LuaManager::applyQueuedChanges() + void LuaManager::synchronizedUpdate(bool paused, float dt) { + if (mPlayer.isEmpty()) + return; // The game is not started yet. + + // We apply input events in `synchronizedUpdate` rather than in `update` in order to reduce input latency. + PlayerScripts* playerScripts = dynamic_cast(mPlayer.getRefData().getLuaScripts()); + if (playerScripts && !paused) + { + for (const auto& event : mInputEvents) + playerScripts->processInputEvent(event); + playerScripts->inputUpdate(dt); + } + mInputEvents.clear(); + MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); for (const std::string& message : mUIMessages) windowManager->messageBox(message); diff --git a/apps/openmw/mwlua/luamanagerimp.hpp b/apps/openmw/mwlua/luamanagerimp.hpp index f5ffe9d258..56d20c2720 100644 --- a/apps/openmw/mwlua/luamanagerimp.hpp +++ b/apps/openmw/mwlua/luamanagerimp.hpp @@ -32,7 +32,7 @@ namespace MWLua void update(bool paused, float dt); // Called by engine.cpp from the main thread. Can use scene graph. - void applyQueuedChanges(); + void synchronizedUpdate(bool paused, float dt); // Available everywhere through the MWBase::LuaManager interface. // LuaManager queues these events and propagates to scripts on the next `update` call. diff --git a/apps/openmw/mwlua/playerscripts.hpp b/apps/openmw/mwlua/playerscripts.hpp index 0393a1375d..e8cdd120ac 100644 --- a/apps/openmw/mwlua/playerscripts.hpp +++ b/apps/openmw/mwlua/playerscripts.hpp @@ -17,7 +17,7 @@ namespace MWLua { registerEngineHandlers({&mKeyPressHandlers, &mKeyReleaseHandlers, &mControllerButtonPressHandlers, &mControllerButtonReleaseHandlers, - &mActionHandlers}); + &mActionHandlers, &mInputUpdateHandlers}); } void processInputEvent(const MWBase::LuaManager::InputEvent& event) @@ -43,12 +43,15 @@ namespace MWLua } } + void inputUpdate(float dt) { callEngineHandlers(mInputUpdateHandlers, dt); } + private: EngineHandlerList mKeyPressHandlers{"onKeyPress"}; EngineHandlerList mKeyReleaseHandlers{"onKeyRelease"}; EngineHandlerList mControllerButtonPressHandlers{"onControllerButtonPress"}; EngineHandlerList mControllerButtonReleaseHandlers{"onControllerButtonRelease"}; EngineHandlerList mActionHandlers{"onInputAction"}; + EngineHandlerList mInputUpdateHandlers{"onInputUpdate"}; }; } diff --git a/docs/source/reference/lua-scripting/engine_handlers.rst b/docs/source/reference/lua-scripting/engine_handlers.rst index ef74684182..4f5f99965a 100644 --- a/docs/source/reference/lua-scripting/engine_handlers.rst +++ b/docs/source/reference/lua-scripting/engine_handlers.rst @@ -10,7 +10,7 @@ Engine handler is a function defined by a script, that can be called by the engi | | | `be assigned to a script in openmw-cs (not yet implemented)`. | | | | ``onInterfaceOverride`` can be called before ``onInit``. | +----------------------------------+----------------------------------------------------------------------+ -| onUpdate(dt) | | Called every frame if game not paused. `dt` is the time | +| onUpdate(dt) | | Called every frame if the game is not paused. `dt` is the time | | | | from the last update in seconds. | +----------------------------------+----------------------------------------------------------------------+ | onSave() -> savedData | | Called when the game is saving. May be called in inactive | @@ -44,6 +44,9 @@ Engine handler is a function defined by a script, that can be called by the engi +----------------------------------+----------------------------------------------------------------------+ | **Only for local scripts attached to a player** | +----------------------------------+----------------------------------------------------------------------+ +| onInputUpdate(dt) | | Called every frame (if the game is not paused) right after | +| | | processing user input. Use it only for latency-critical stuff. | ++----------------------------------+----------------------------------------------------------------------+ | onKeyPress(key) | | `Key `_ is pressed. | | | | Usage example: ``if key.symbol == 'z' and key.withShift then ...`` | +----------------------------------+----------------------------------------------------------------------+