From db72380ba926655354fc89f6e9cbe643d1c7babf Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Tue, 14 Dec 2021 00:51:18 +0100 Subject: [PATCH] Allow Lua scripts to handle input actions when UI is opened. Also fixes #6456. --- apps/openmw/engine.cpp | 12 ++++------- apps/openmw/mwlua/luabindings.cpp | 3 ++- apps/openmw/mwlua/luamanagerimp.cpp | 22 +++++++++++--------- apps/openmw/mwlua/luamanagerimp.hpp | 4 ++-- apps/openmw/mwlua/worldview.cpp | 3 +++ apps/openmw/mwlua/worldview.hpp | 4 ++++ files/builtin_scripts/scripts/omw/camera.lua | 2 ++ files/lua_api/openmw/core.lua | 7 ++++++- 8 files changed, 35 insertions(+), 22 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a44a02ef18..5c9e915703 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -296,7 +296,7 @@ bool OMW::Engine::frame(float frametime) // 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(mEnvironment.getWindowManager()->isGuiMode(), frametime); + mLuaManager->synchronizedUpdate(); // update game state { @@ -873,10 +873,8 @@ public: mThread = std::thread([this]{ threadBody(); }); }; - void allowUpdate(double dt) + void allowUpdate() { - mDt = dt; - mIsGuiMode = mEngine->mEnvironment.getWindowManager()->isGuiMode(); if (!mThread) return; { @@ -918,7 +916,7 @@ private: const unsigned int frameNumber = viewer->getFrameStamp()->getFrameNumber(); ScopedProfile profile(frameStart, frameNumber, *osg::Timer::instance(), *viewer->getViewerStats()); - mEngine->mLuaManager->update(mIsGuiMode, mDt); + mEngine->mLuaManager->update(); } void threadBody() @@ -943,8 +941,6 @@ private: std::condition_variable mCV; bool mUpdateRequest = false; bool mJoinRequest = false; - double mDt = 0; - bool mIsGuiMode = false; std::optional mThread; }; @@ -1057,7 +1053,7 @@ void OMW::Engine::go() mEnvironment.getWorld()->updateWindowManager(); - luaWorker.allowUpdate(dt); // if there is a separate Lua thread, it starts the update now + luaWorker.allowUpdate(); // if there is a separate Lua thread, it starts the update now mViewer->renderingTraversals(); diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index 80af77139c..57b1b17a3b 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -25,7 +25,7 @@ namespace MWLua { auto* lua = context.mLua; sol::table api(lua->sol(), sol::create); - api["API_REVISION"] = 10; + api["API_REVISION"] = 11; api["quit"] = [lua]() { Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback(); @@ -37,6 +37,7 @@ namespace MWLua }; api["getGameTimeInSeconds"] = [world=context.mWorldView]() { return world->getGameTimeInSeconds(); }; api["getGameTimeInHours"] = [world=context.mWorldView]() { return world->getGameTimeInHours(); }; + api["isWorldPaused"] = [world=context.mWorldView]() { return world->isPaused(); }; api["OBJECT_TYPE"] = definitionList(*lua, { "Activator", "Armor", "Book", "Clothing", "Creature", "Door", "Ingredient", diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index 2f3df00f7f..f134ef86dd 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -78,11 +78,12 @@ namespace MWLua mInitialized = true; } - void LuaManager::update(bool paused, float dt) + void LuaManager::update() { if (mPlayer.isEmpty()) return; // The game is not started yet. + float frameDuration = MWBase::Environment::get().getFrameDuration(); ObjectRegistry* objectRegistry = mWorldView.getObjectRegistry(); MWWorld::Ptr newPlayerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -101,9 +102,9 @@ namespace MWLua mGlobalEvents = std::vector(); mLocalEvents = std::vector(); - if (!paused) + if (!mWorldView.isPaused()) { // Update time and process timers - double seconds = mWorldView.getGameTimeInSeconds() + dt; + double seconds = mWorldView.getGameTimeInSeconds() + frameDuration; mWorldView.setGameTimeInSeconds(seconds); double hours = mWorldView.getGameTimeInHours(); @@ -146,10 +147,10 @@ namespace MWLua } mLocalEngineEvents.clear(); - if (!paused) + if (!mWorldView.isPaused()) { for (LocalScripts* scripts : mActiveLocalScripts) - scripts->update(dt); + scripts->update(frameDuration); } // Engine handlers in global scripts @@ -168,24 +169,25 @@ namespace MWLua mGlobalScripts.actorActive(GObject(id, objectRegistry)); mActorAddedEvents.clear(); - if (!paused) - mGlobalScripts.update(dt); + if (!mWorldView.isPaused()) + mGlobalScripts.update(frameDuration); } - void LuaManager::synchronizedUpdate(bool paused, float dt) + void LuaManager::synchronizedUpdate() { 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) + if (playerScripts && !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu)) { for (const auto& event : mInputEvents) playerScripts->processInputEvent(event); - playerScripts->inputUpdate(dt); } mInputEvents.clear(); + if (playerScripts && !mWorldView.isPaused()) + playerScripts->inputUpdate(MWBase::Environment::get().getFrameDuration()); MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); for (const std::string& message : mUIMessages) diff --git a/apps/openmw/mwlua/luamanagerimp.hpp b/apps/openmw/mwlua/luamanagerimp.hpp index 56d20c2720..88273de7f0 100644 --- a/apps/openmw/mwlua/luamanagerimp.hpp +++ b/apps/openmw/mwlua/luamanagerimp.hpp @@ -29,10 +29,10 @@ namespace MWLua // Called by engine.cpp every frame. For performance reasons it works in a separate // thread (in parallel with osg Cull). Can not use scene graph. - void update(bool paused, float dt); + void update(); // Called by engine.cpp from the main thread. Can use scene graph. - void synchronizedUpdate(bool paused, float dt); + void synchronizedUpdate(); // 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/worldview.cpp b/apps/openmw/mwlua/worldview.cpp index beaa2d4770..219035745a 100644 --- a/apps/openmw/mwlua/worldview.cpp +++ b/apps/openmw/mwlua/worldview.cpp @@ -4,6 +4,8 @@ #include #include +#include "../mwbase/windowmanager.hpp" + #include "../mwclass/container.hpp" #include "../mwworld/class.hpp" @@ -20,6 +22,7 @@ namespace MWLua mContainersInScene.updateList(); mDoorsInScene.updateList(); mItemsInScene.updateList(); + mPaused = MWBase::Environment::get().getWindowManager()->isGuiMode(); } void WorldView::clear() diff --git a/apps/openmw/mwlua/worldview.hpp b/apps/openmw/mwlua/worldview.hpp index ea27e0ff84..a8befd4685 100644 --- a/apps/openmw/mwlua/worldview.hpp +++ b/apps/openmw/mwlua/worldview.hpp @@ -19,6 +19,9 @@ namespace MWLua void update(); // Should be called every frame. void clear(); // Should be called every time before starting or loading a new game. + // Whether the world is paused (i.e. game time is not changing and actors don't move). + bool isPaused() const { return mPaused; } + // Returns the number of seconds passed from the beginning of the game. double getGameTimeInSeconds() const { return mGameSeconds; } void setGameTimeInSeconds(double t) { mGameSeconds = t; } @@ -74,6 +77,7 @@ namespace MWLua ObjectGroup mItemsInScene; double mGameSeconds = 0; + bool mPaused = false; }; } diff --git a/files/builtin_scripts/scripts/omw/camera.lua b/files/builtin_scripts/scripts/omw/camera.lua index 1a5d1ca730..4025f7eee4 100644 --- a/files/builtin_scripts/scripts/omw/camera.lua +++ b/files/builtin_scripts/scripts/omw/camera.lua @@ -1,4 +1,5 @@ local camera = require('openmw.camera') +local core = require('openmw.core') local input = require('openmw.input') local settings = require('openmw.settings') local util = require('openmw.util') @@ -225,6 +226,7 @@ return { onUpdate = onUpdate, onInputUpdate = onInputUpdate, onInputAction = function(action) + if core.isWorldPaused() then return end if action == input.ACTION.ZoomIn then zoom(10) elseif action == input.ACTION.ZoomOut then diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 35513bbb79..fe309a92db 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -22,7 +22,7 @@ ------------------------------------------------------------------------------- -- Game time in seconds. --- The number of seconds in the game world, passed from starting a new game. +-- The number of seconds passed in the game world since starting a new game. -- @function [parent=#core] getGameTimeInSeconds -- @return #number @@ -32,6 +32,11 @@ -- @function [parent=#core] getGameTimeInHours -- @return #number +------------------------------------------------------------------------------- +-- Whether the world is paused (onUpdate doesn't work when the world is paused). +-- @function [parent=#core] isWorldPaused +-- @return #boolean + ------------------------------------------------------------------------------- -- @type OBJECT_TYPE