1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-03 18:09:40 +00:00

Apply lua handlers for user input in the main thread in order to reduce latency.

This commit is contained in:
Petr Mikheev 2021-11-17 03:05:50 +01:00
parent 47cbdcba15
commit e56ee2c735
5 changed files with 27 additions and 13 deletions

View file

@ -293,6 +293,10 @@ bool OMW::Engine::frame(float frametime)
// Main menu opened? Then scripts are also paused. // Main menu opened? Then scripts are also paused.
bool paused = mEnvironment.getWindowManager()->containsMode(MWGui::GM_MainMenu); 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 // update game state
{ {
ScopedProfile<UserStatsType::State> profile(frameStart, frameNumber, *timer, *stats); ScopedProfile<UserStatsType::State> profile(frameStart, frameNumber, *timer, *stats);
@ -874,7 +878,6 @@ public:
} }
else else
update(); update();
mEngine->mLuaManager->applyQueuedChanges();
}; };
void join() void join()

View file

@ -132,14 +132,6 @@ namespace MWLua
mQueuedCallbacks.clear(); mQueuedCallbacks.clear();
// Engine handlers in local scripts // Engine handlers in local scripts
PlayerScripts* playerScripts = dynamic_cast<PlayerScripts*>(mPlayer.getRefData().getLuaScripts());
if (playerScripts && !paused)
{
for (const auto& event : mInputEvents)
playerScripts->processInputEvent(event);
}
mInputEvents.clear();
for (const LocalEngineEvent& e : mLocalEngineEvents) for (const LocalEngineEvent& e : mLocalEngineEvents)
{ {
LObject obj(e.mDest, objectRegistry); LObject obj(e.mDest, objectRegistry);
@ -180,8 +172,21 @@ namespace MWLua
mGlobalScripts.update(dt); 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<PlayerScripts*>(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(); MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager();
for (const std::string& message : mUIMessages) for (const std::string& message : mUIMessages)
windowManager->messageBox(message); windowManager->messageBox(message);

View file

@ -32,7 +32,7 @@ namespace MWLua
void update(bool paused, float dt); void update(bool paused, float dt);
// Called by engine.cpp from the main thread. Can use scene graph. // 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. // Available everywhere through the MWBase::LuaManager interface.
// LuaManager queues these events and propagates to scripts on the next `update` call. // LuaManager queues these events and propagates to scripts on the next `update` call.

View file

@ -17,7 +17,7 @@ namespace MWLua
{ {
registerEngineHandlers({&mKeyPressHandlers, &mKeyReleaseHandlers, registerEngineHandlers({&mKeyPressHandlers, &mKeyReleaseHandlers,
&mControllerButtonPressHandlers, &mControllerButtonReleaseHandlers, &mControllerButtonPressHandlers, &mControllerButtonReleaseHandlers,
&mActionHandlers}); &mActionHandlers, &mInputUpdateHandlers});
} }
void processInputEvent(const MWBase::LuaManager::InputEvent& event) void processInputEvent(const MWBase::LuaManager::InputEvent& event)
@ -43,12 +43,15 @@ namespace MWLua
} }
} }
void inputUpdate(float dt) { callEngineHandlers(mInputUpdateHandlers, dt); }
private: private:
EngineHandlerList mKeyPressHandlers{"onKeyPress"}; EngineHandlerList mKeyPressHandlers{"onKeyPress"};
EngineHandlerList mKeyReleaseHandlers{"onKeyRelease"}; EngineHandlerList mKeyReleaseHandlers{"onKeyRelease"};
EngineHandlerList mControllerButtonPressHandlers{"onControllerButtonPress"}; EngineHandlerList mControllerButtonPressHandlers{"onControllerButtonPress"};
EngineHandlerList mControllerButtonReleaseHandlers{"onControllerButtonRelease"}; EngineHandlerList mControllerButtonReleaseHandlers{"onControllerButtonRelease"};
EngineHandlerList mActionHandlers{"onInputAction"}; EngineHandlerList mActionHandlers{"onInputAction"};
EngineHandlerList mInputUpdateHandlers{"onInputUpdate"};
}; };
} }

View file

@ -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)`. | | | | `be assigned to a script in openmw-cs (not yet implemented)`. |
| | | ``onInterfaceOverride`` can be called before ``onInit``. | | | | ``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. | | | | from the last update in seconds. |
+----------------------------------+----------------------------------------------------------------------+ +----------------------------------+----------------------------------------------------------------------+
| onSave() -> savedData | | Called when the game is saving. May be called in inactive | | 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** | | **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 <openmw_input.html##(KeyboardEvent)>`_ is pressed. | | onKeyPress(key) | | `Key <openmw_input.html##(KeyboardEvent)>`_ is pressed. |
| | | Usage example: ``if key.symbol == 'z' and key.withShift then ...`` | | | | Usage example: ``if key.symbol == 'z' and key.withShift then ...`` |
+----------------------------------+----------------------------------------------------------------------+ +----------------------------------+----------------------------------------------------------------------+