mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-16 17:42:31 +00:00
Lua commands world.pause / world.unpause
This commit is contained in:
parent
91c7585c8b
commit
6c4e1f4e8f
@ -201,9 +201,6 @@ bool OMW::Engine::frame(float frametime)
|
|||||||
mSoundManager->update(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);
|
ScopedProfile<UserStatsType::LuaSyncUpdate> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
// Should be called after input manager update and before any change to the game world.
|
// 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);
|
mStateManager->update(frametime);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool guiActive = mWindowManager->isGuiMode();
|
bool paused = mWorld->getTimeManager()->isPaused();
|
||||||
|
|
||||||
{
|
{
|
||||||
ScopedProfile<UserStatsType::Script> profile(frameStart, frameNumber, *timer, *stats);
|
ScopedProfile<UserStatsType::Script> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
|
|
||||||
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
|
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
|
||||||
{
|
{
|
||||||
if (!paused)
|
if (!mWindowManager->containsMode(MWGui::GM_MainMenu))
|
||||||
{
|
{
|
||||||
if (mWorld->getScriptsEnabled())
|
if (mWorld->getScriptsEnabled())
|
||||||
{
|
{
|
||||||
@ -238,7 +235,7 @@ bool OMW::Engine::frame(float frametime)
|
|||||||
mWorld->getWorldScene().markCellAsUnchanged();
|
mWorld->getWorldScene().markCellAsUnchanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!guiActive)
|
if (!paused)
|
||||||
{
|
{
|
||||||
double hours = (frametime * mWorld->getTimeManager()->getGameTimeScale()) / 3600.0;
|
double hours = (frametime * mWorld->getTimeManager()->getGameTimeScale()) / 3600.0;
|
||||||
mWorld->advanceTime(hours, true);
|
mWorld->advanceTime(hours, true);
|
||||||
@ -253,13 +250,13 @@ bool OMW::Engine::frame(float frametime)
|
|||||||
|
|
||||||
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
|
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
|
||||||
{
|
{
|
||||||
mMechanicsManager->update(frametime, guiActive);
|
mMechanicsManager->update(frametime, paused);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mStateManager->getState() == MWBase::StateManager::State_Running)
|
if (mStateManager->getState() == MWBase::StateManager::State_Running)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = mWorld->getPlayerPtr();
|
MWWorld::Ptr player = mWorld->getPlayerPtr();
|
||||||
if (!guiActive && player.getClass().getCreatureStats(player).isDead())
|
if (!paused && player.getClass().getCreatureStats(player).isDead())
|
||||||
mStateManager->endGame();
|
mStateManager->endGame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,7 +267,7 @@ bool OMW::Engine::frame(float frametime)
|
|||||||
|
|
||||||
if (mStateManager->getState() != MWBase::StateManager::State_NoGame)
|
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)
|
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
|
// Start the main rendering loop
|
||||||
double simulationTime = 0.0;
|
MWWorld::DateTimeManager& timeManager = *mWorld->getTimeManager();
|
||||||
Misc::FrameRateLimiter frameRateLimiter = Misc::makeFrameRateLimiter(mEnvironment.getFrameRateLimit());
|
Misc::FrameRateLimiter frameRateLimiter = Misc::makeFrameRateLimiter(mEnvironment.getFrameRateLimit());
|
||||||
const std::chrono::steady_clock::duration maxSimulationInterval(std::chrono::milliseconds(200));
|
const std::chrono::steady_clock::duration maxSimulationInterval(std::chrono::milliseconds(200));
|
||||||
while (!mViewer->done() && !mStateManager->hasQuitRequest())
|
while (!mViewer->done() && !mStateManager->hasQuitRequest())
|
||||||
@ -936,21 +933,18 @@ void OMW::Engine::go()
|
|||||||
const double dt = std::chrono::duration_cast<std::chrono::duration<double>>(
|
const double dt = std::chrono::duration_cast<std::chrono::duration<double>>(
|
||||||
std::min(frameRateLimiter.getLastFrameDuration(), maxSimulationInterval))
|
std::min(frameRateLimiter.getLastFrameDuration(), maxSimulationInterval))
|
||||||
.count()
|
.count()
|
||||||
* mWorld->getTimeManager()->getSimulationTimeScale();
|
* timeManager.getSimulationTimeScale();
|
||||||
|
|
||||||
mViewer->advance(simulationTime);
|
mViewer->advance(timeManager.getSimulationTime());
|
||||||
|
|
||||||
if (!frame(dt))
|
if (!frame(dt))
|
||||||
{
|
{
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
timeManager.updateIsPaused();
|
||||||
{
|
if (!timeManager.isPaused())
|
||||||
bool guiActive = mWindowManager->isGuiMode();
|
timeManager.setSimulationTime(timeManager.getSimulationTime() + dt);
|
||||||
if (!guiActive)
|
|
||||||
simulationTime += dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stats)
|
if (stats)
|
||||||
{
|
{
|
||||||
|
@ -68,7 +68,7 @@ namespace MWLua
|
|||||||
api["getSimulationTimeScale"] = [timeManager]() { return timeManager->getSimulationTimeScale(); };
|
api["getSimulationTimeScale"] = [timeManager]() { return timeManager->getSimulationTimeScale(); };
|
||||||
api["getGameTime"] = [timeManager]() { return timeManager->getGameTime(); };
|
api["getGameTime"] = [timeManager]() { return timeManager->getGameTime(); };
|
||||||
api["getGameTimeScale"] = [timeManager]() { return timeManager->getGameTimeScale(); };
|
api["getGameTimeScale"] = [timeManager]() { return timeManager->getGameTimeScale(); };
|
||||||
api["isWorldPaused"] = [world = context.mWorldView]() { return world->isPaused(); };
|
api["isWorldPaused"] = [timeManager]() { return timeManager->isPaused(); };
|
||||||
api["getRealTime"] = []() {
|
api["getRealTime"] = []() {
|
||||||
return std::chrono::duration<double>(std::chrono::steady_clock::now().time_since_epoch()).count();
|
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); });
|
context.mLuaManager->addAction([scale, timeManager] { timeManager->setSimulationTimeScale(scale); });
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Ability to pause/resume world from Lua (needed for UI dehardcoding)
|
api["pause"]
|
||||||
// api["pause"] = []() {};
|
= [timeManager](sol::optional<std::string_view> tag) { timeManager->pause(tag.value_or("paused")); };
|
||||||
// api["resume"] = []() {};
|
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)
|
static sol::table initContentFilesBindings(sol::state_view& lua)
|
||||||
|
@ -128,8 +128,6 @@ namespace MWLua
|
|||||||
if (mPlayer.isEmpty())
|
if (mPlayer.isEmpty())
|
||||||
return; // The game is not started yet.
|
return; // The game is not started yet.
|
||||||
|
|
||||||
float frameDuration = MWBase::Environment::get().getFrameDuration();
|
|
||||||
|
|
||||||
MWWorld::Ptr newPlayerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr newPlayerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
if (!(getId(mPlayer) == getId(newPlayerPtr)))
|
if (!(getId(mPlayer) == getId(newPlayerPtr)))
|
||||||
throw std::logic_error("Player RefNum was changed unexpectedly");
|
throw std::logic_error("Player RefNum was changed unexpectedly");
|
||||||
@ -151,16 +149,12 @@ namespace MWLua
|
|||||||
|
|
||||||
mLuaEvents.finalizeEventBatch();
|
mLuaEvents.finalizeEventBatch();
|
||||||
|
|
||||||
if (!mWorldView.isPaused())
|
|
||||||
{ // Update time and process timers
|
|
||||||
MWWorld::DateTimeManager& timeManager = *MWBase::Environment::get().getWorld()->getTimeManager();
|
MWWorld::DateTimeManager& timeManager = *MWBase::Environment::get().getWorld()->getTimeManager();
|
||||||
double simulationTime = timeManager.getSimulationTime() + frameDuration;
|
if (!timeManager.isPaused())
|
||||||
timeManager.setSimulationTime(simulationTime);
|
{
|
||||||
double gameTime = timeManager.getGameTime();
|
mGlobalScripts.processTimers(timeManager.getSimulationTime(), timeManager.getGameTime());
|
||||||
|
|
||||||
mGlobalScripts.processTimers(simulationTime, gameTime);
|
|
||||||
for (LocalScripts* scripts : mActiveLocalScripts)
|
for (LocalScripts* scripts : mActiveLocalScripts)
|
||||||
scripts->processTimers(simulationTime, gameTime);
|
scripts->processTimers(timeManager.getSimulationTime(), timeManager.getGameTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run event handlers for events that were sent before `finalizeEventBatch`.
|
// Run event handlers for events that were sent before `finalizeEventBatch`.
|
||||||
@ -173,8 +167,9 @@ namespace MWLua
|
|||||||
|
|
||||||
// Run engine handlers
|
// Run engine handlers
|
||||||
mEngineEvents.callEngineHandlers();
|
mEngineEvents.callEngineHandlers();
|
||||||
if (!mWorldView.isPaused())
|
if (!timeManager.isPaused())
|
||||||
{
|
{
|
||||||
|
float frameDuration = MWBase::Environment::get().getFrameDuration();
|
||||||
for (LocalScripts* scripts : mActiveLocalScripts)
|
for (LocalScripts* scripts : mActiveLocalScripts)
|
||||||
scripts->update(frameDuration);
|
scripts->update(frameDuration);
|
||||||
mGlobalScripts.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.
|
// We apply input events in `synchronizedUpdate` rather than in `update` in order to reduce input latency.
|
||||||
mProcessingInputEvents = true;
|
mProcessingInputEvents = true;
|
||||||
PlayerScripts* playerScripts = dynamic_cast<PlayerScripts*>(mPlayer.getRefData().getLuaScripts());
|
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)
|
for (const auto& event : mInputEvents)
|
||||||
playerScripts->processInputEvent(event);
|
playerScripts->processInputEvent(event);
|
||||||
}
|
}
|
||||||
mInputEvents.clear();
|
mInputEvents.clear();
|
||||||
if (playerScripts)
|
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;
|
mProcessingInputEvents = false;
|
||||||
|
|
||||||
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);
|
||||||
mUIMessages.clear();
|
mUIMessages.clear();
|
||||||
|
@ -24,7 +24,6 @@ namespace MWLua
|
|||||||
mContainersInScene.updateList();
|
mContainersInScene.updateList();
|
||||||
mDoorsInScene.updateList();
|
mDoorsInScene.updateList();
|
||||||
mItemsInScene.updateList();
|
mItemsInScene.updateList();
|
||||||
mPaused = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldView::clear()
|
void WorldView::clear()
|
||||||
|
@ -18,9 +18,6 @@ namespace MWLua
|
|||||||
void update(); // Should be called every frame.
|
void update(); // Should be called every frame.
|
||||||
void clear(); // Should be called every time before starting or loading a new game.
|
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 getActivatorsInScene() const { return mActivatorsInScene.mList; }
|
||||||
ObjectIdList getActorsInScene() const { return mActorsInScene.mList; }
|
ObjectIdList getActorsInScene() const { return mActorsInScene.mList; }
|
||||||
ObjectIdList getContainersInScene() const { return mContainersInScene.mList; }
|
ObjectIdList getContainersInScene() const { return mContainersInScene.mList; }
|
||||||
@ -54,8 +51,6 @@ namespace MWLua
|
|||||||
ObjectGroup mDoorsInScene;
|
ObjectGroup mDoorsInScene;
|
||||||
ObjectGroup mItemsInScene;
|
ObjectGroup mItemsInScene;
|
||||||
ObjectIdList mPlayers = std::make_shared<std::vector<ObjectId>>();
|
ObjectIdList mPlayers = std::make_shared<std::vector<ObjectId>>();
|
||||||
|
|
||||||
bool mPaused = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
#include "duration.hpp"
|
#include "duration.hpp"
|
||||||
@ -57,6 +58,8 @@ namespace MWWorld
|
|||||||
mYear = globalVariables[Globals::sYear].getInteger();
|
mYear = globalVariables[Globals::sYear].getInteger();
|
||||||
mGameTimeScale = globalVariables[Globals::sTimeScale].getFloat();
|
mGameTimeScale = globalVariables[Globals::sTimeScale].getFloat();
|
||||||
setSimulationTimeScale(1.0);
|
setSimulationTimeScale(1.0);
|
||||||
|
mPaused = false;
|
||||||
|
mPausedTags.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DateTimeManager::setHour(double hour)
|
void DateTimeManager::setHour(double hour)
|
||||||
@ -250,4 +253,16 @@ namespace MWWorld
|
|||||||
mSimulationTimeScale = std::max(0.f, scale);
|
mSimulationTimeScale = std::max(0.f, scale);
|
||||||
MWBase::Environment::get().getSoundManager()->setSimulationTimeScale(mSimulationTimeScale);
|
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
|
#ifndef GAME_MWWORLD_DATETIMEMANAGER_H
|
||||||
#define GAME_MWWORLD_DATETIMEMANAGER_H
|
#define GAME_MWWORLD_DATETIMEMANAGER_H
|
||||||
|
|
||||||
|
#include <set>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include "globalvariablename.hpp"
|
#include "globalvariablename.hpp"
|
||||||
@ -34,6 +35,17 @@ namespace MWWorld
|
|||||||
float getSimulationTimeScale() const { return mSimulationTimeScale; }
|
float getSimulationTimeScale() const { return mSimulationTimeScale; }
|
||||||
void setSimulationTimeScale(float scale); // simulation time to real time ratio
|
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:
|
private:
|
||||||
friend class World;
|
friend class World;
|
||||||
void setup(Globals& globalVariables);
|
void setup(Globals& globalVariables);
|
||||||
@ -53,6 +65,8 @@ namespace MWWorld
|
|||||||
float mGameTimeScale = 0.f;
|
float mGameTimeScale = 0.f;
|
||||||
float mSimulationTimeScale = 1.0;
|
float mSimulationTimeScale = 1.0;
|
||||||
double mSimulationTime = 0.0;
|
double mSimulationTime = 0.0;
|
||||||
|
bool mPaused = false;
|
||||||
|
std::set<std::string, std::less<>> mPausedTags;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,6 +106,21 @@
|
|||||||
-- @function [parent=#world] isWorldPaused
|
-- @function [parent=#world] isWorldPaused
|
||||||
-- @return #boolean
|
-- @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.
|
-- Return an object by RefNum/FormId.
|
||||||
-- Note: the function always returns @{openmw.core#GameObject} and doesn't validate that
|
-- Note: the function always returns @{openmw.core#GameObject} and doesn't validate that
|
||||||
|
Loading…
x
Reference in New Issue
Block a user