Lua commands world.pause / world.unpause

macos_ci_fix
Petr Mikheev 1 year ago
parent 91c7585c8b
commit 6c4e1f4e8f

@ -201,9 +201,6 @@ bool OMW::Engine::frame(float frametime)
mSoundManager->update(frametime);
}
// Main menu opened? Then scripts are also paused.
bool paused = mWindowManager->containsMode(MWGui::GM_MainMenu);
{
ScopedProfile<UserStatsType::LuaSyncUpdate> profile(frameStart, frameNumber, *timer, *stats);
// Should be called after input manager update and before any change to the game world.
@ -217,14 +214,14 @@ bool OMW::Engine::frame(float frametime)
mStateManager->update(frametime);
}
bool guiActive = mWindowManager->isGuiMode();
bool paused = mWorld->getTimeManager()->isPaused();
{
ScopedProfile<UserStatsType::Script> profile(frameStart, frameNumber, *timer, *stats);
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
{
if (!paused)
if (!mWindowManager->containsMode(MWGui::GM_MainMenu))
{
if (mWorld->getScriptsEnabled())
{
@ -238,7 +235,7 @@ bool OMW::Engine::frame(float frametime)
mWorld->getWorldScene().markCellAsUnchanged();
}
if (!guiActive)
if (!paused)
{
double hours = (frametime * mWorld->getTimeManager()->getGameTimeScale()) / 3600.0;
mWorld->advanceTime(hours, true);
@ -253,13 +250,13 @@ bool OMW::Engine::frame(float frametime)
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
{
mMechanicsManager->update(frametime, guiActive);
mMechanicsManager->update(frametime, paused);
}
if (mStateManager->getState() == MWBase::StateManager::State_Running)
{
MWWorld::Ptr player = mWorld->getPlayerPtr();
if (!guiActive && player.getClass().getCreatureStats(player).isDead())
if (!paused && player.getClass().getCreatureStats(player).isDead())
mStateManager->endGame();
}
}
@ -270,7 +267,7 @@ bool OMW::Engine::frame(float frametime)
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
{
mWorld->updatePhysics(frametime, guiActive, frameStart, frameNumber, *stats);
mWorld->updatePhysics(frametime, paused, frameStart, frameNumber, *stats);
}
}
@ -280,7 +277,7 @@ bool OMW::Engine::frame(float frametime)
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
{
mWorld->update(frametime, guiActive);
mWorld->update(frametime, paused);
}
}
@ -928,7 +925,7 @@ void OMW::Engine::go()
}
// Start the main rendering loop
double simulationTime = 0.0;
MWWorld::DateTimeManager& timeManager = *mWorld->getTimeManager();
Misc::FrameRateLimiter frameRateLimiter = Misc::makeFrameRateLimiter(mEnvironment.getFrameRateLimit());
const std::chrono::steady_clock::duration maxSimulationInterval(std::chrono::milliseconds(200));
while (!mViewer->done() && !mStateManager->hasQuitRequest())
@ -936,21 +933,18 @@ void OMW::Engine::go()
const double dt = std::chrono::duration_cast<std::chrono::duration<double>>(
std::min(frameRateLimiter.getLastFrameDuration(), maxSimulationInterval))
.count()
* mWorld->getTimeManager()->getSimulationTimeScale();
* timeManager.getSimulationTimeScale();
mViewer->advance(simulationTime);
mViewer->advance(timeManager.getSimulationTime());
if (!frame(dt))
{
std::this_thread::sleep_for(std::chrono::milliseconds(5));
continue;
}
else
{
bool guiActive = mWindowManager->isGuiMode();
if (!guiActive)
simulationTime += dt;
}
timeManager.updateIsPaused();
if (!timeManager.isPaused())
timeManager.setSimulationTime(timeManager.getSimulationTime() + dt);
if (stats)
{

@ -68,7 +68,7 @@ namespace MWLua
api["getSimulationTimeScale"] = [timeManager]() { return timeManager->getSimulationTimeScale(); };
api["getGameTime"] = [timeManager]() { return timeManager->getGameTime(); };
api["getGameTimeScale"] = [timeManager]() { return timeManager->getGameTimeScale(); };
api["isWorldPaused"] = [world = context.mWorldView]() { return world->isPaused(); };
api["isWorldPaused"] = [timeManager]() { return timeManager->isPaused(); };
api["getRealTime"] = []() {
return std::chrono::duration<double>(std::chrono::steady_clock::now().time_since_epoch()).count();
};
@ -81,9 +81,16 @@ namespace MWLua
context.mLuaManager->addAction([scale, timeManager] { timeManager->setSimulationTimeScale(scale); });
};
// TODO: Ability to pause/resume world from Lua (needed for UI dehardcoding)
// api["pause"] = []() {};
// api["resume"] = []() {};
api["pause"]
= [timeManager](sol::optional<std::string_view> tag) { timeManager->pause(tag.value_or("paused")); };
api["unpause"]
= [timeManager](sol::optional<std::string_view> tag) { timeManager->unpause(tag.value_or("paused")); };
api["getPausedTags"] = [timeManager](sol::this_state lua) {
sol::table res(lua, sol::create);
for (const std::string& tag : timeManager->getPausedTags())
res[tag] = tag;
return res;
};
}
static sol::table initContentFilesBindings(sol::state_view& lua)

@ -128,8 +128,6 @@ namespace MWLua
if (mPlayer.isEmpty())
return; // The game is not started yet.
float frameDuration = MWBase::Environment::get().getFrameDuration();
MWWorld::Ptr newPlayerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr();
if (!(getId(mPlayer) == getId(newPlayerPtr)))
throw std::logic_error("Player RefNum was changed unexpectedly");
@ -151,16 +149,12 @@ namespace MWLua
mLuaEvents.finalizeEventBatch();
if (!mWorldView.isPaused())
{ // Update time and process timers
MWWorld::DateTimeManager& timeManager = *MWBase::Environment::get().getWorld()->getTimeManager();
double simulationTime = timeManager.getSimulationTime() + frameDuration;
timeManager.setSimulationTime(simulationTime);
double gameTime = timeManager.getGameTime();
mGlobalScripts.processTimers(simulationTime, gameTime);
MWWorld::DateTimeManager& timeManager = *MWBase::Environment::get().getWorld()->getTimeManager();
if (!timeManager.isPaused())
{
mGlobalScripts.processTimers(timeManager.getSimulationTime(), timeManager.getGameTime());
for (LocalScripts* scripts : mActiveLocalScripts)
scripts->processTimers(simulationTime, gameTime);
scripts->processTimers(timeManager.getSimulationTime(), timeManager.getGameTime());
}
// Run event handlers for events that were sent before `finalizeEventBatch`.
@ -173,8 +167,9 @@ namespace MWLua
// Run engine handlers
mEngineEvents.callEngineHandlers();
if (!mWorldView.isPaused())
if (!timeManager.isPaused())
{
float frameDuration = MWBase::Environment::get().getFrameDuration();
for (LocalScripts* scripts : mActiveLocalScripts)
scripts->update(frameDuration);
mGlobalScripts.update(frameDuration);
@ -222,17 +217,19 @@ namespace MWLua
// We apply input events in `synchronizedUpdate` rather than in `update` in order to reduce input latency.
mProcessingInputEvents = true;
PlayerScripts* playerScripts = dynamic_cast<PlayerScripts*>(mPlayer.getRefData().getLuaScripts());
if (playerScripts && !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu))
MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager();
if (playerScripts && !windowManager->containsMode(MWGui::GM_MainMenu))
{
for (const auto& event : mInputEvents)
playerScripts->processInputEvent(event);
}
mInputEvents.clear();
if (playerScripts)
playerScripts->onFrame(mWorldView.isPaused() ? 0.0 : MWBase::Environment::get().getFrameDuration());
playerScripts->onFrame(MWBase::Environment::get().getWorld()->getTimeManager()->isPaused()
? 0.0
: MWBase::Environment::get().getFrameDuration());
mProcessingInputEvents = false;
MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager();
for (const std::string& message : mUIMessages)
windowManager->messageBox(message);
mUIMessages.clear();

@ -24,7 +24,6 @@ namespace MWLua
mContainersInScene.updateList();
mDoorsInScene.updateList();
mItemsInScene.updateList();
mPaused = MWBase::Environment::get().getWindowManager()->isGuiMode();
}
void WorldView::clear()

@ -18,9 +18,6 @@ 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; }
ObjectIdList getActivatorsInScene() const { return mActivatorsInScene.mList; }
ObjectIdList getActorsInScene() const { return mActorsInScene.mList; }
ObjectIdList getContainersInScene() const { return mContainersInScene.mList; }
@ -54,8 +51,6 @@ namespace MWLua
ObjectGroup mDoorsInScene;
ObjectGroup mItemsInScene;
ObjectIdList mPlayers = std::make_shared<std::vector<ObjectId>>();
bool mPaused = false;
};
}

@ -4,6 +4,7 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "duration.hpp"
@ -57,6 +58,8 @@ namespace MWWorld
mYear = globalVariables[Globals::sYear].getInteger();
mGameTimeScale = globalVariables[Globals::sTimeScale].getFloat();
setSimulationTimeScale(1.0);
mPaused = false;
mPausedTags.clear();
}
void DateTimeManager::setHour(double hour)
@ -250,4 +253,16 @@ namespace MWWorld
mSimulationTimeScale = std::max(0.f, scale);
MWBase::Environment::get().getSoundManager()->setSimulationTimeScale(mSimulationTimeScale);
}
void DateTimeManager::unpause(std::string_view tag)
{
auto it = mPausedTags.find(tag);
if (it != mPausedTags.end())
mPausedTags.erase(it);
}
void DateTimeManager::updateIsPaused()
{
mPaused = !mPausedTags.empty() || MWBase::Environment::get().getWindowManager()->isGuiMode();
}
}

@ -1,6 +1,7 @@
#ifndef GAME_MWWORLD_DATETIMEMANAGER_H
#define GAME_MWWORLD_DATETIMEMANAGER_H
#include <set>
#include <string_view>
#include "globalvariablename.hpp"
@ -34,6 +35,17 @@ namespace MWWorld
float getSimulationTimeScale() const { return mSimulationTimeScale; }
void setSimulationTimeScale(float scale); // simulation time to real time ratio
// Whether the game is paused in the current frame.
bool isPaused() const { return mPaused; }
// Pauses the game starting from the next frame until `unpause` is called with the same tag.
void pause(std::string_view tag) { mPausedTags.emplace(tag); }
void unpause(std::string_view tag);
const std::set<std::string, std::less<>>& getPausedTags() const { return mPausedTags; }
// Updates mPaused; should be called once a frame.
void updateIsPaused();
private:
friend class World;
void setup(Globals& globalVariables);
@ -53,6 +65,8 @@ namespace MWWorld
float mGameTimeScale = 0.f;
float mSimulationTimeScale = 1.0;
double mSimulationTime = 0.0;
bool mPaused = false;
std::set<std::string, std::less<>> mPausedTags;
};
}

@ -106,6 +106,21 @@
-- @function [parent=#world] isWorldPaused
-- @return #boolean
---
-- Pause the game starting from the next frame.
-- @function [parent=#world] pause
-- @param #string tag (optional) The game will be paused until `unpause` is called with the same tag.
---
-- Remove given tag from the list of pause tags. Resume the game starting from the next frame if the list became empty.
-- @function [parent=#world] unpause
-- @param #string tag (optional) Needed to undo `pause` called with this tag.
---
-- The tags that are currently pausing the game.
-- @function [parent=#world] getPausedTags
-- @return #table
---
-- Return an object by RefNum/FormId.
-- Note: the function always returns @{openmw.core#GameObject} and doesn't validate that

Loading…
Cancel
Save