mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-28 12:09:53 +00:00
Merge branch 'time' into 'master'
Pause/resume the game in Lua scripts See merge request OpenMW/openmw!3317
This commit is contained in:
commit
e21e3a0d46
28 changed files with 242 additions and 249 deletions
|
@ -59,7 +59,7 @@ add_openmw_dir (mwscript
|
|||
)
|
||||
|
||||
add_openmw_dir (mwlua
|
||||
luamanagerimp object worldview userdataserializer luaevents engineevents objectvariant
|
||||
luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant
|
||||
context globalscripts localscripts playerscripts luabindings objectbindings cellbindings mwscriptbindings
|
||||
camerabindings uibindings inputbindings nearbybindings postprocessingbindings stats debugbindings
|
||||
types/types types/door types/item types/actor types/container types/lockable types/weapon types/npc types/creature types/player types/activator types/book types/lockpick types/probe types/apparatus types/potion types/ingredient types/misc types/repair types/armor types/light types/static types/clothing types/levelledlist types/terminal
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include "mwsound/soundmanagerimp.hpp"
|
||||
|
||||
#include "mwworld/class.hpp"
|
||||
#include "mwworld/datetimemanager.hpp"
|
||||
#include "mwworld/worldimp.hpp"
|
||||
|
||||
#include "mwrender/vismask.hpp"
|
||||
|
@ -200,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.
|
||||
|
@ -216,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())
|
||||
{
|
||||
|
@ -237,9 +235,9 @@ bool OMW::Engine::frame(float frametime)
|
|||
mWorld->getWorldScene().markCellAsUnchanged();
|
||||
}
|
||||
|
||||
if (!guiActive)
|
||||
if (!paused)
|
||||
{
|
||||
double hours = (frametime * mWorld->getTimeScaleFactor()) / 3600.0;
|
||||
double hours = (frametime * mWorld->getTimeManager()->getGameTimeScale()) / 3600.0;
|
||||
mWorld->advanceTime(hours, true);
|
||||
mWorld->rechargeItems(frametime, true);
|
||||
}
|
||||
|
@ -252,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();
|
||||
}
|
||||
}
|
||||
|
@ -269,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,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 +926,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 +934,18 @@ void OMW::Engine::go()
|
|||
const double dt = std::chrono::duration_cast<std::chrono::duration<double>>(
|
||||
std::min(frameRateLimiter.getLastFrameDuration(), maxSimulationInterval))
|
||||
.count()
|
||||
* mEnvironment.getWorld()->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)
|
||||
{
|
||||
|
|
|
@ -92,6 +92,7 @@ namespace MWWorld
|
|||
class ESMStore;
|
||||
class RefData;
|
||||
class Cell;
|
||||
class DateTimeManager;
|
||||
|
||||
typedef std::vector<std::pair<MWWorld::Ptr, MWMechanics::Movement>> PtrMovementList;
|
||||
}
|
||||
|
@ -209,15 +210,9 @@ namespace MWBase
|
|||
virtual void advanceTime(double hours, bool incremental = false) = 0;
|
||||
///< Advance in-game time.
|
||||
|
||||
virtual std::string_view getMonthName(int month = -1) const = 0;
|
||||
///< Return name of month (-1: current month)
|
||||
|
||||
virtual MWWorld::TimeStamp getTimeStamp() const = 0;
|
||||
///< Return current in-game time and number of day since new game start.
|
||||
|
||||
virtual ESM::EpochTimeStamp getEpochTimeStamp() const = 0;
|
||||
///< Return current in-game date and time.
|
||||
|
||||
virtual bool toggleSky() = 0;
|
||||
///< \return Resulting mode
|
||||
|
||||
|
@ -239,12 +234,6 @@ namespace MWBase
|
|||
|
||||
virtual void modRegion(const ESM::RefId& regionid, const std::vector<char>& chances) = 0;
|
||||
|
||||
virtual float getTimeScaleFactor() const = 0;
|
||||
|
||||
virtual float getSimulationTimeScale() const = 0;
|
||||
|
||||
virtual void setSimulationTimeScale(float scale) = 0;
|
||||
|
||||
virtual void changeToInteriorCell(
|
||||
std::string_view cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true)
|
||||
= 0;
|
||||
|
@ -612,6 +601,8 @@ namespace MWBase
|
|||
|
||||
virtual MWRender::PostProcessor* getPostProcessor() = 0;
|
||||
|
||||
virtual MWWorld::DateTimeManager* getTimeManager() = 0;
|
||||
|
||||
virtual void setActorActive(const MWWorld::Ptr& ptr, bool value) = 0;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwdialogue/keywordsearch.hpp"
|
||||
#include "../mwworld/datetimemanager.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
@ -253,8 +254,9 @@ namespace MWGui
|
|||
|
||||
std::ostringstream os;
|
||||
|
||||
os << itr->mDayOfMonth << ' ' << MWBase::Environment::get().getWorld()->getMonthName(itr->mMonth)
|
||||
<< " (" << dayStr << " " << (itr->mDay) << ')';
|
||||
os << itr->mDayOfMonth << ' '
|
||||
<< MWBase::Environment::get().getWorld()->getTimeManager()->getMonthName(itr->mMonth) << " ("
|
||||
<< dayStr << " " << (itr->mDay) << ')';
|
||||
|
||||
timestamp_buffer = os.str();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../mwbase/statemanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwworld/datetimemanager.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwstate/character.hpp"
|
||||
|
@ -422,8 +423,9 @@ namespace MWGui
|
|||
hour = 12;
|
||||
|
||||
text << mCurrentSlot->mProfile.mInGameTime.mDay << " "
|
||||
<< MWBase::Environment::get().getWorld()->getMonthName(mCurrentSlot->mProfile.mInGameTime.mMonth) << " "
|
||||
<< hour << " " << (pm ? "#{Calendar:pm}" : "#{Calendar:am}");
|
||||
<< MWBase::Environment::get().getWorld()->getTimeManager()->getMonthName(
|
||||
mCurrentSlot->mProfile.mInGameTime.mMonth)
|
||||
<< " " << hour << " " << (pm ? "#{Calendar:pm}" : "#{Calendar:am}");
|
||||
|
||||
if (Settings::Manager::getBool("timeplayed", "Saves"))
|
||||
{
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/datetimemanager.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
|
@ -154,17 +155,17 @@ namespace MWGui
|
|||
onHourSliderChangedPosition(mHourSlider, 0);
|
||||
mHourSlider->setScrollPosition(0);
|
||||
|
||||
std::string_view month = MWBase::Environment::get().getWorld()->getMonthName();
|
||||
int hour = static_cast<int>(MWBase::Environment::get().getWorld()->getTimeStamp().getHour());
|
||||
const MWWorld::DateTimeManager& timeManager = *MWBase::Environment::get().getWorld()->getTimeManager();
|
||||
std::string_view month = timeManager.getMonthName();
|
||||
int hour = static_cast<int>(timeManager.getTimeStamp().getHour());
|
||||
bool pm = hour >= 12;
|
||||
if (hour >= 13)
|
||||
hour -= 12;
|
||||
if (hour == 0)
|
||||
hour = 12;
|
||||
|
||||
ESM::EpochTimeStamp currentDate = MWBase::Environment::get().getWorld()->getEpochTimeStamp();
|
||||
std::string daysPassed = Misc::StringUtils::format(
|
||||
"(#{Calendar:day} %i)", MWBase::Environment::get().getWorld()->getTimeStamp().getDay());
|
||||
ESM::EpochTimeStamp currentDate = timeManager.getEpochTimeStamp();
|
||||
std::string daysPassed = Misc::StringUtils::format("(#{Calendar:day} %i)", timeManager.getTimeStamp().getDay());
|
||||
std::string_view formattedHour(pm ? "#{Calendar:pm}" : "#{Calendar:am}");
|
||||
std::string dateTimeText
|
||||
= Misc::StringUtils::format("%i %s %s %i %s", currentDate.mDay, month, daysPassed, hour, formattedHour);
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace MWLua
|
|||
{
|
||||
class LuaEvents;
|
||||
class LuaManager;
|
||||
class WorldView;
|
||||
class ObjectLists;
|
||||
|
||||
struct Context
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ namespace MWLua
|
|||
LuaManager* mLuaManager;
|
||||
LuaUtil::LuaState* mLua;
|
||||
LuaUtil::UserdataSerializer* mSerializer;
|
||||
WorldView* mWorldView;
|
||||
ObjectLists* mObjectLists;
|
||||
LuaEvents* mLuaEvents;
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../mwbase/statemanager.hpp"
|
||||
#include "../mwworld/action.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/datetimemanager.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/manualref.hpp"
|
||||
#include "../mwworld/store.hpp"
|
||||
|
@ -28,7 +29,7 @@
|
|||
#include "luaevents.hpp"
|
||||
#include "luamanagerimp.hpp"
|
||||
#include "mwscriptbindings.hpp"
|
||||
#include "worldview.hpp"
|
||||
#include "objectlists.hpp"
|
||||
|
||||
#include "camerabindings.hpp"
|
||||
#include "cellbindings.hpp"
|
||||
|
@ -61,13 +62,13 @@ namespace MWLua
|
|||
|
||||
static void addTimeBindings(sol::table& api, const Context& context, bool global)
|
||||
{
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
MWWorld::DateTimeManager* timeManager = MWBase::Environment::get().getWorld()->getTimeManager();
|
||||
|
||||
api["getSimulationTime"] = [world = context.mWorldView]() { return world->getSimulationTime(); };
|
||||
api["getSimulationTimeScale"] = [world]() { return world->getSimulationTimeScale(); };
|
||||
api["getGameTime"] = [world = context.mWorldView]() { return world->getGameTime(); };
|
||||
api["getGameTimeScale"] = [world = context.mWorldView]() { return world->getGameTimeScale(); };
|
||||
api["isWorldPaused"] = [world = context.mWorldView]() { return world->isPaused(); };
|
||||
api["getSimulationTime"] = [timeManager]() { return timeManager->getSimulationTime(); };
|
||||
api["getSimulationTimeScale"] = [timeManager]() { return timeManager->getSimulationTimeScale(); };
|
||||
api["getGameTime"] = [timeManager]() { return timeManager->getGameTime(); };
|
||||
api["getGameTimeScale"] = [timeManager]() { return timeManager->getGameTimeScale(); };
|
||||
api["isWorldPaused"] = [timeManager]() { return timeManager->isPaused(); };
|
||||
api["getRealTime"] = []() {
|
||||
return std::chrono::duration<double>(std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||
};
|
||||
|
@ -75,15 +76,21 @@ namespace MWLua
|
|||
if (!global)
|
||||
return;
|
||||
|
||||
api["setGameTimeScale"] = [world = context.mWorldView](double scale) { world->setGameTimeScale(scale); };
|
||||
|
||||
api["setSimulationTimeScale"] = [context, world](float scale) {
|
||||
context.mLuaManager->addAction([scale, world] { world->setSimulationTimeScale(scale); });
|
||||
api["setGameTimeScale"] = [timeManager](double scale) { timeManager->setGameTimeScale(scale); };
|
||||
api["setSimulationTimeScale"] = [context, timeManager](float scale) {
|
||||
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)
|
||||
|
@ -228,12 +235,12 @@ namespace MWLua
|
|||
static sol::table initWorldPackage(const Context& context)
|
||||
{
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
WorldView* worldView = context.mWorldView;
|
||||
ObjectLists* objectLists = context.mObjectLists;
|
||||
addTimeBindings(api, context, true);
|
||||
addCellGetters(api, context);
|
||||
api["mwscript"] = initMWScriptBindings(context);
|
||||
api["activeActors"] = GObjectList{ worldView->getActorsInScene() };
|
||||
api["players"] = GObjectList{ worldView->getPlayers() };
|
||||
api["activeActors"] = GObjectList{ objectLists->getActorsInScene() };
|
||||
api["players"] = GObjectList{ objectLists->getPlayers() };
|
||||
api["createObject"] = [](std::string_view recordId, sol::optional<int> count) -> GObject {
|
||||
MWWorld::ManualRef mref(*MWBase::Environment::get().getESMStore(), ESM::RefId::deserializeText(recordId));
|
||||
const MWWorld::Ptr& ptr = mref.getPtr();
|
||||
|
@ -291,11 +298,11 @@ namespace MWLua
|
|||
std::map<std::string, sol::object> initCommonPackages(const Context& context)
|
||||
{
|
||||
sol::state_view lua = context.mLua->sol();
|
||||
WorldView* w = context.mWorldView;
|
||||
MWWorld::DateTimeManager* tm = MWBase::Environment::get().getWorld()->getTimeManager();
|
||||
return {
|
||||
{ "openmw.async",
|
||||
LuaUtil::getAsyncPackageInitializer(
|
||||
lua, [w] { return w->getSimulationTime(); }, [w] { return w->getGameTime(); }) },
|
||||
lua, [tm] { return tm->getSimulationTime(); }, [tm] { return tm->getGameTime(); }) },
|
||||
{ "openmw.core", initCorePackage(context) },
|
||||
{ "openmw.types", initTypesPackage(context) },
|
||||
{ "openmw.util", LuaUtil::initUtilPackage(lua) },
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "../mwrender/postprocessor.hpp"
|
||||
|
||||
#include "../mwworld/datetimemanager.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/scene.hpp"
|
||||
|
@ -75,7 +76,7 @@ namespace MWLua
|
|||
context.mIsGlobal = true;
|
||||
context.mLuaManager = this;
|
||||
context.mLua = &mLua;
|
||||
context.mWorldView = &mWorldView;
|
||||
context.mObjectLists = &mObjectLists;
|
||||
context.mLuaEvents = &mLuaEvents;
|
||||
context.mSerializer = mGlobalSerializer.get();
|
||||
|
||||
|
@ -127,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");
|
||||
|
@ -138,7 +137,7 @@ namespace MWLua
|
|||
MWBase::Environment::get().getWorldModel()->registerPtr(mPlayer);
|
||||
}
|
||||
|
||||
mWorldView.update();
|
||||
mObjectLists.update();
|
||||
|
||||
std::erase_if(mActiveLocalScripts, [](const LocalScripts* l) {
|
||||
return l->getPtrOrEmpty().isEmpty() || l->getPtrOrEmpty().getRefData().isDeleted();
|
||||
|
@ -150,15 +149,12 @@ namespace MWLua
|
|||
|
||||
mLuaEvents.finalizeEventBatch();
|
||||
|
||||
if (!mWorldView.isPaused())
|
||||
{ // Update time and process timers
|
||||
double simulationTime = mWorldView.getSimulationTime() + frameDuration;
|
||||
mWorldView.setSimulationTime(simulationTime);
|
||||
double gameTime = mWorldView.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`.
|
||||
|
@ -171,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);
|
||||
|
@ -220,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();
|
||||
|
@ -262,7 +261,7 @@ namespace MWLua
|
|||
mLuaEvents.clear();
|
||||
mEngineEvents.clear();
|
||||
mInputEvents.clear();
|
||||
mWorldView.clear();
|
||||
mObjectLists.clear();
|
||||
mGlobalScripts.removeAllScripts();
|
||||
mGlobalScriptsStarted = false;
|
||||
mNewGameStarted = false;
|
||||
|
@ -284,8 +283,8 @@ namespace MWLua
|
|||
return;
|
||||
if (!mPlayer.isEmpty())
|
||||
throw std::logic_error("Player is initialized twice");
|
||||
mWorldView.objectAddedToScene(ptr);
|
||||
mWorldView.setPlayer(ptr);
|
||||
mObjectLists.objectAddedToScene(ptr);
|
||||
mObjectLists.setPlayer(ptr);
|
||||
mPlayer = ptr;
|
||||
LocalScripts* localScripts = ptr.getRefData().getLuaScripts();
|
||||
if (!localScripts)
|
||||
|
@ -314,7 +313,7 @@ namespace MWLua
|
|||
|
||||
void LuaManager::objectAddedToScene(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
mWorldView.objectAddedToScene(ptr); // assigns generated RefNum if it is not set yet.
|
||||
mObjectLists.objectAddedToScene(ptr); // assigns generated RefNum if it is not set yet.
|
||||
mEngineEvents.addToQueue(EngineEvents::OnActive{ getId(ptr) });
|
||||
|
||||
LocalScripts* localScripts = ptr.getRefData().getLuaScripts();
|
||||
|
@ -334,7 +333,7 @@ namespace MWLua
|
|||
|
||||
void LuaManager::objectRemovedFromScene(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
mWorldView.objectRemovedFromScene(ptr);
|
||||
mObjectLists.objectRemovedFromScene(ptr);
|
||||
LocalScripts* localScripts = ptr.getRefData().getLuaScripts();
|
||||
if (localScripts)
|
||||
{
|
||||
|
@ -400,7 +399,8 @@ namespace MWLua
|
|||
{
|
||||
writer.startRecord(ESM::REC_LUAM);
|
||||
|
||||
mWorldView.save(writer);
|
||||
writer.writeHNT<double>("LUAW", MWBase::Environment::get().getWorld()->getTimeManager()->getSimulationTime());
|
||||
writer.writeFormId(MWBase::Environment::get().getWorldModel()->getLastGeneratedRefNum(), true);
|
||||
ESM::LuaScripts globalScripts;
|
||||
mGlobalScripts.save(globalScripts);
|
||||
globalScripts.save(writer);
|
||||
|
@ -414,7 +414,14 @@ namespace MWLua
|
|||
if (type != ESM::REC_LUAM)
|
||||
throw std::runtime_error("ESM::REC_LUAM is expected");
|
||||
|
||||
mWorldView.load(reader);
|
||||
double simulationTime;
|
||||
reader.getHNT(simulationTime, "LUAW");
|
||||
MWBase::Environment::get().getWorld()->getTimeManager()->setSimulationTime(simulationTime);
|
||||
ESM::FormId lastGenerated = reader.getFormId(true);
|
||||
if (lastGenerated.hasContentFile())
|
||||
throw std::runtime_error("Last generated RefNum is invalid");
|
||||
MWBase::Environment::get().getWorldModel()->setLastGeneratedRefNum(lastGenerated);
|
||||
|
||||
ESM::LuaScripts globalScripts;
|
||||
globalScripts.load(reader);
|
||||
mLuaEvents.load(mLua.sol(), reader, mContentFileMapping, mGlobalLoader.get());
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <osg/Stats>
|
||||
#include <set>
|
||||
|
||||
#include <components/lua/luastate.hpp>
|
||||
|
@ -17,7 +18,7 @@
|
|||
#include "localscripts.hpp"
|
||||
#include "luaevents.hpp"
|
||||
#include "object.hpp"
|
||||
#include "worldview.hpp"
|
||||
#include "objectlists.hpp"
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
|
@ -156,7 +157,7 @@ namespace MWLua
|
|||
|
||||
GlobalScripts mGlobalScripts{ &mLua };
|
||||
std::set<LocalScripts*> mActiveLocalScripts;
|
||||
WorldView mWorldView;
|
||||
ObjectLists mObjectLists;
|
||||
|
||||
MWWorld::Ptr mPlayer;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "../mwphysics/raycasting.hpp"
|
||||
|
||||
#include "luamanagerimp.hpp"
|
||||
#include "worldview.hpp"
|
||||
#include "objectlists.hpp"
|
||||
|
||||
namespace sol
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ namespace MWLua
|
|||
sol::table initNearbyPackage(const Context& context)
|
||||
{
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
WorldView* worldView = context.mWorldView;
|
||||
ObjectLists* objectLists = context.mObjectLists;
|
||||
|
||||
sol::usertype<MWPhysics::RayCastingResult> rayResult
|
||||
= context.mLua->sol().new_usertype<MWPhysics::RayCastingResult>("RayCastingResult");
|
||||
|
@ -131,12 +131,12 @@ namespace MWLua
|
|||
return LObject(refId.getIf<ESM::FormIdRefId>()->getValue());
|
||||
};
|
||||
|
||||
api["activators"] = LObjectList{ worldView->getActivatorsInScene() };
|
||||
api["actors"] = LObjectList{ worldView->getActorsInScene() };
|
||||
api["containers"] = LObjectList{ worldView->getContainersInScene() };
|
||||
api["doors"] = LObjectList{ worldView->getDoorsInScene() };
|
||||
api["items"] = LObjectList{ worldView->getItemsInScene() };
|
||||
api["players"] = LObjectList{ worldView->getPlayers() };
|
||||
api["activators"] = LObjectList{ objectLists->getActivatorsInScene() };
|
||||
api["actors"] = LObjectList{ objectLists->getActorsInScene() };
|
||||
api["containers"] = LObjectList{ objectLists->getContainersInScene() };
|
||||
api["doors"] = LObjectList{ objectLists->getDoorsInScene() };
|
||||
api["items"] = LObjectList{ objectLists->getItemsInScene() };
|
||||
api["players"] = LObjectList{ objectLists->getPlayers() };
|
||||
|
||||
api["NAVIGATOR_FLAGS"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, DetourNavigator::Flag>({
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "worldview.hpp"
|
||||
#include "objectlists.hpp"
|
||||
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <components/esm3/esmwriter.hpp>
|
||||
|
@ -6,28 +6,27 @@
|
|||
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwclass/container.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/timestamp.hpp"
|
||||
#include "../mwworld/worldmodel.hpp"
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
|
||||
void WorldView::update()
|
||||
void ObjectLists::update()
|
||||
{
|
||||
mActivatorsInScene.updateList();
|
||||
mActorsInScene.updateList();
|
||||
mContainersInScene.updateList();
|
||||
mDoorsInScene.updateList();
|
||||
mItemsInScene.updateList();
|
||||
mPaused = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||
}
|
||||
|
||||
void WorldView::clear()
|
||||
void ObjectLists::clear()
|
||||
{
|
||||
mActivatorsInScene.clear();
|
||||
mActorsInScene.clear();
|
||||
|
@ -36,7 +35,7 @@ namespace MWLua
|
|||
mItemsInScene.clear();
|
||||
}
|
||||
|
||||
WorldView::ObjectGroup* WorldView::chooseGroup(const MWWorld::Ptr& ptr)
|
||||
ObjectLists::ObjectGroup* ObjectLists::chooseGroup(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
// It is important to check `isMarker` first.
|
||||
// For example "prisonmarker" has class "Door" despite that it is only an invisible marker.
|
||||
|
@ -56,7 +55,7 @@ namespace MWLua
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void WorldView::objectAddedToScene(const MWWorld::Ptr& ptr)
|
||||
void ObjectLists::objectAddedToScene(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
MWBase::Environment::get().getWorldModel()->registerPtr(ptr);
|
||||
ObjectGroup* group = chooseGroup(ptr);
|
||||
|
@ -64,36 +63,14 @@ namespace MWLua
|
|||
addToGroup(*group, ptr);
|
||||
}
|
||||
|
||||
void WorldView::objectRemovedFromScene(const MWWorld::Ptr& ptr)
|
||||
void ObjectLists::objectRemovedFromScene(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
ObjectGroup* group = chooseGroup(ptr);
|
||||
if (group)
|
||||
removeFromGroup(*group, ptr);
|
||||
}
|
||||
|
||||
double WorldView::getGameTime() const
|
||||
{
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
MWWorld::TimeStamp timeStamp = world->getTimeStamp();
|
||||
return (static_cast<double>(timeStamp.getDay()) * 24 + timeStamp.getHour()) * 3600.0;
|
||||
}
|
||||
|
||||
void WorldView::load(ESM::ESMReader& esm)
|
||||
{
|
||||
esm.getHNT(mSimulationTime, "LUAW");
|
||||
ESM::FormId lastGenerated = esm.getFormId(true);
|
||||
if (lastGenerated.hasContentFile())
|
||||
throw std::runtime_error("Last generated RefNum is invalid");
|
||||
MWBase::Environment::get().getWorldModel()->setLastGeneratedRefNum(lastGenerated);
|
||||
}
|
||||
|
||||
void WorldView::save(ESM::ESMWriter& esm) const
|
||||
{
|
||||
esm.writeHNT("LUAW", mSimulationTime);
|
||||
esm.writeFormId(MWBase::Environment::get().getWorldModel()->getLastGeneratedRefNum(), true);
|
||||
}
|
||||
|
||||
void WorldView::ObjectGroup::updateList()
|
||||
void ObjectLists::ObjectGroup::updateList()
|
||||
{
|
||||
if (mChanged)
|
||||
{
|
||||
|
@ -104,20 +81,20 @@ namespace MWLua
|
|||
}
|
||||
}
|
||||
|
||||
void WorldView::ObjectGroup::clear()
|
||||
void ObjectLists::ObjectGroup::clear()
|
||||
{
|
||||
mChanged = false;
|
||||
mList->clear();
|
||||
mSet.clear();
|
||||
}
|
||||
|
||||
void WorldView::addToGroup(ObjectGroup& group, const MWWorld::Ptr& ptr)
|
||||
void ObjectLists::addToGroup(ObjectGroup& group, const MWWorld::Ptr& ptr)
|
||||
{
|
||||
group.mSet.insert(getId(ptr));
|
||||
group.mChanged = true;
|
||||
}
|
||||
|
||||
void WorldView::removeFromGroup(ObjectGroup& group, const MWWorld::Ptr& ptr)
|
||||
void ObjectLists::removeFromGroup(ObjectGroup& group, const MWWorld::Ptr& ptr)
|
||||
{
|
||||
group.mSet.erase(getId(ptr));
|
||||
group.mChanged = true;
|
|
@ -1,51 +1,20 @@
|
|||
#ifndef MWLUA_WORLDVIEW_H
|
||||
#define MWLUA_WORLDVIEW_H
|
||||
|
||||
#include "object.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwworld/globals.hpp"
|
||||
#ifndef MWLUA_OBJECTLISTS_H
|
||||
#define MWLUA_OBJECTLISTS_H
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMWriter;
|
||||
class ESMReader;
|
||||
}
|
||||
#include "object.hpp"
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
|
||||
// WorldView is a kind of an extension to mwworld. It was created on initial stage of
|
||||
// OpenMW Lua development in order to minimize the risk of merge conflicts.
|
||||
// TODO: Move get*InScene functions to mwworld/scene
|
||||
// TODO: Move time-related stuff to mwworld; maybe create a new class TimeManager.
|
||||
// TODO: Remove WorldView.
|
||||
class WorldView
|
||||
// ObjectLists is used to track lists of game objects like nearby.items, nearby.actors, etc.
|
||||
class ObjectLists
|
||||
{
|
||||
public:
|
||||
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; }
|
||||
|
||||
// The number of seconds passed from the beginning of the game.
|
||||
double getSimulationTime() const { return mSimulationTime; }
|
||||
void setSimulationTime(double t) { mSimulationTime = t; }
|
||||
|
||||
// The game time (in game seconds) passed from the beginning of the game.
|
||||
// Note that game time generally goes faster than the simulation time.
|
||||
double getGameTime() const;
|
||||
double getGameTimeScale() const { return MWBase::Environment::get().getWorld()->getTimeScaleFactor(); }
|
||||
void setGameTimeScale(double s)
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->setGlobalFloat(MWWorld::Globals::sTimeScale, s);
|
||||
}
|
||||
|
||||
ObjectIdList getActivatorsInScene() const { return mActivatorsInScene.mList; }
|
||||
ObjectIdList getActorsInScene() const { return mActorsInScene.mList; }
|
||||
ObjectIdList getContainersInScene() const { return mContainersInScene.mList; }
|
||||
|
@ -58,9 +27,6 @@ namespace MWLua
|
|||
|
||||
void setPlayer(const MWWorld::Ptr& player) { *mPlayers = { getId(player) }; }
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
void save(ESM::ESMWriter& esm) const;
|
||||
|
||||
private:
|
||||
struct ObjectGroup
|
||||
{
|
||||
|
@ -82,11 +48,8 @@ namespace MWLua
|
|||
ObjectGroup mDoorsInScene;
|
||||
ObjectGroup mItemsInScene;
|
||||
ObjectIdList mPlayers = std::make_shared<std::vector<ObjectId>>();
|
||||
|
||||
double mSimulationTime = 0;
|
||||
bool mPaused = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MWLUA_WORLDVIEW_H
|
||||
#endif // MWLUA_OBJECTLISTS_H
|
|
@ -1,6 +1,7 @@
|
|||
#include "postprocessingbindings.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwrender/postprocessor.hpp"
|
||||
|
||||
#include "luamanagerimp.hpp"
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "localscripts.hpp"
|
||||
#include "luamanagerimp.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "context.hpp"
|
||||
#include "luamanagerimp.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
namespace MWLua
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/datetimemanager.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
@ -837,7 +838,7 @@ namespace MWMechanics
|
|||
// Take a maximum remaining duration of Stunted Magicka effects (-1 is a constant one) in game hours.
|
||||
if (remainingTime > 0)
|
||||
{
|
||||
double timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor();
|
||||
double timeScale = MWBase::Environment::get().getWorld()->getTimeManager()->getGameTimeScale();
|
||||
if (timeScale == 0.0)
|
||||
timeScale = 1;
|
||||
|
||||
|
@ -1864,7 +1865,7 @@ namespace MWMechanics
|
|||
void Actors::rest(double hours, bool sleep) const
|
||||
{
|
||||
float duration = hours * 3600.f;
|
||||
const float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor();
|
||||
const float timeScale = MWBase::Environment::get().getWorld()->getTimeManager()->getGameTimeScale();
|
||||
if (timeScale != 0.f)
|
||||
duration /= timeScale;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/datetimemanager.hpp"
|
||||
|
||||
#include "character.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
|
@ -72,7 +73,8 @@ namespace MWMechanics
|
|||
// and the duration is not infinite, the package is complete.
|
||||
if (mDuration > 0)
|
||||
{
|
||||
mRemainingDuration -= ((duration * MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600);
|
||||
mRemainingDuration
|
||||
-= ((duration * MWBase::Environment::get().getWorld()->getTimeManager()->getGameTimeScale()) / 3600);
|
||||
if (mRemainingDuration <= 0)
|
||||
{
|
||||
mRemainingDuration = mDuration;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/datetimemanager.hpp"
|
||||
|
||||
#include "character.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
|
@ -156,7 +157,9 @@ namespace MWMechanics
|
|||
// Check if we've run out of time
|
||||
if (mDuration > 0)
|
||||
{
|
||||
mRemainingDuration -= ((duration * MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600);
|
||||
mRemainingDuration
|
||||
-= ((duration * MWBase::Environment::get().getWorld()->getTimeManager()->getGameTimeScale())
|
||||
/ 3600);
|
||||
if (mRemainingDuration <= 0)
|
||||
{
|
||||
mRemainingDuration = mDuration;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/datetimemanager.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwphysics/raycasting.hpp"
|
||||
|
@ -200,7 +201,8 @@ namespace MWMechanics
|
|||
// get or create temporary storage
|
||||
AiWanderStorage& storage = state.get<AiWanderStorage>();
|
||||
|
||||
mRemainingDuration -= ((duration * MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600);
|
||||
mRemainingDuration
|
||||
-= ((duration * MWBase::Environment::get().getWorld()->getTimeManager()->getGameTimeScale()) / 3600);
|
||||
|
||||
cStats.setDrawState(DrawState::Nothing);
|
||||
cStats.setMovementFlag(CreatureStats::Flag_Run, false);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <components/nifosg/particle.hpp>
|
||||
|
||||
#include "../mwworld/datetimemanager.hpp"
|
||||
#include "../mwworld/weather.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -559,7 +560,7 @@ namespace MWRender
|
|||
}
|
||||
|
||||
// rotate the stars by 360 degrees every 4 days
|
||||
mAtmosphereNightRoll += MWBase::Environment::get().getWorld()->getTimeScaleFactor() * duration
|
||||
mAtmosphereNightRoll += MWBase::Environment::get().getWorld()->getTimeManager()->getGameTimeScale() * duration
|
||||
* osg::DegreesToRadians(360.f) / (3600 * 96.f);
|
||||
if (mAtmosphereNightNode->getNodeMask() != 0)
|
||||
mAtmosphereNightNode->setAttitude(osg::Quat(mAtmosphereNightRoll, osg::Vec3f(0, 0, 1)));
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/datetimemanager.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/globals.hpp"
|
||||
#include "../mwworld/scene.hpp"
|
||||
|
@ -227,7 +228,7 @@ void MWState::StateManager::saveGame(std::string_view description, const Slot* s
|
|||
profile.mPlayerClassId = classId;
|
||||
|
||||
profile.mPlayerCellName = world.getCellName();
|
||||
profile.mInGameTime = world.getEpochTimeStamp();
|
||||
profile.mInGameTime = world.getTimeManager()->getEpochTimeStamp();
|
||||
profile.mTimePlayed = mTimePlayed;
|
||||
profile.mDescription = description;
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
#include <components/l10n/manager.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "duration.hpp"
|
||||
#include "globals.hpp"
|
||||
|
@ -53,7 +56,10 @@ namespace MWWorld
|
|||
mDay = globalVariables[Globals::sDay].getInteger();
|
||||
mMonth = globalVariables[Globals::sMonth].getInteger();
|
||||
mYear = globalVariables[Globals::sYear].getInteger();
|
||||
mTimeScale = globalVariables[Globals::sTimeScale].getFloat();
|
||||
mGameTimeScale = globalVariables[Globals::sTimeScale].getFloat();
|
||||
setSimulationTimeScale(1.0);
|
||||
mPaused = false;
|
||||
mPausedTags.clear();
|
||||
}
|
||||
|
||||
void DateTimeManager::setHour(double hour)
|
||||
|
@ -103,9 +109,9 @@ namespace MWWorld
|
|||
return TimeStamp(mGameHour, mDaysPassed);
|
||||
}
|
||||
|
||||
float DateTimeManager::getTimeScaleFactor() const
|
||||
void DateTimeManager::setGameTimeScale(float scale)
|
||||
{
|
||||
return mTimeScale;
|
||||
MWBase::Environment::get().getWorld()->setGlobalFloat(MWWorld::Globals::sTimeScale, scale);
|
||||
}
|
||||
|
||||
ESM::EpochTimeStamp DateTimeManager::getEpochTimeStamp() const
|
||||
|
@ -199,7 +205,7 @@ namespace MWWorld
|
|||
}
|
||||
else if (name == Globals::sTimeScale)
|
||||
{
|
||||
mTimeScale = value;
|
||||
mGameTimeScale = value;
|
||||
}
|
||||
else if (name == Globals::sDaysPassed)
|
||||
{
|
||||
|
@ -232,7 +238,7 @@ namespace MWWorld
|
|||
}
|
||||
else if (name == Globals::sTimeScale)
|
||||
{
|
||||
mTimeScale = static_cast<float>(value);
|
||||
mGameTimeScale = static_cast<float>(value);
|
||||
}
|
||||
else if (name == Globals::sDaysPassed)
|
||||
{
|
||||
|
@ -241,4 +247,22 @@ namespace MWWorld
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DateTimeManager::setSimulationTimeScale(float scale)
|
||||
{
|
||||
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"
|
||||
|
@ -14,31 +15,58 @@ namespace MWWorld
|
|||
{
|
||||
class Globals;
|
||||
class TimeStamp;
|
||||
class World;
|
||||
|
||||
class DateTimeManager
|
||||
{
|
||||
int mDaysPassed = 0;
|
||||
int mDay = 0;
|
||||
int mMonth = 0;
|
||||
int mYear = 0;
|
||||
float mGameHour = 0.f;
|
||||
float mTimeScale = 0.f;
|
||||
public:
|
||||
// Game time.
|
||||
// Note that game time generally goes faster than the simulation time.
|
||||
std::string_view getMonthName(int month = -1) const; // -1: current month
|
||||
TimeStamp getTimeStamp() const;
|
||||
ESM::EpochTimeStamp getEpochTimeStamp() const;
|
||||
double getGameTime() const { return (static_cast<double>(mDaysPassed) * 24 + mGameHour) * 3600.0; }
|
||||
float getGameTimeScale() const { return mGameTimeScale; }
|
||||
void setGameTimeScale(float scale); // game time to simulation time ratio
|
||||
|
||||
// Simulation time (the number of seconds passed from the beginning of the game).
|
||||
double getSimulationTime() const { return mSimulationTime; }
|
||||
void setSimulationTime(double t) { mSimulationTime = t; }
|
||||
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);
|
||||
bool updateGlobalInt(GlobalVariableName name, int value);
|
||||
bool updateGlobalFloat(GlobalVariableName name, float value);
|
||||
void advanceTime(double hours, Globals& globalVariables);
|
||||
|
||||
void setHour(double hour);
|
||||
void setDay(int day);
|
||||
void setMonth(int month);
|
||||
|
||||
public:
|
||||
std::string_view getMonthName(int month) const;
|
||||
TimeStamp getTimeStamp() const;
|
||||
ESM::EpochTimeStamp getEpochTimeStamp() const;
|
||||
float getTimeScaleFactor() const;
|
||||
|
||||
void advanceTime(double hours, Globals& globalVariables);
|
||||
|
||||
void setup(Globals& globalVariables);
|
||||
bool updateGlobalInt(GlobalVariableName name, int value);
|
||||
bool updateGlobalFloat(GlobalVariableName name, float value);
|
||||
int mDaysPassed = 0;
|
||||
int mDay = 0;
|
||||
int mMonth = 0;
|
||||
int mYear = 0;
|
||||
float mGameHour = 0.f;
|
||||
float mGameTimeScale = 0.f;
|
||||
float mSimulationTimeScale = 1.0;
|
||||
double mSimulationTime = 0.0;
|
||||
bool mPaused = false;
|
||||
std::set<std::string, std::less<>> mPausedTags;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -249,7 +249,7 @@ namespace MWWorld
|
|||
: mResourceSystem(resourceSystem)
|
||||
, mLocalScripts(mStore)
|
||||
, mWorldModel(mStore, mReaders)
|
||||
, mCurrentDate(std::make_unique<DateTimeManager>())
|
||||
, mTimeManager(std::make_unique<DateTimeManager>())
|
||||
, mSky(true)
|
||||
, mGodMode(false)
|
||||
, mScriptsEnabled(true)
|
||||
|
@ -319,7 +319,7 @@ namespace MWWorld
|
|||
void World::fillGlobalVariables()
|
||||
{
|
||||
mGlobalVariables.fill(mStore);
|
||||
mCurrentDate->setup(mGlobalVariables);
|
||||
mTimeManager->setup(mGlobalVariables);
|
||||
}
|
||||
|
||||
void World::startNewGame(bool bypass)
|
||||
|
@ -399,7 +399,7 @@ namespace MWWorld
|
|||
mPhysics->toggleCollisionMode();
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->updatePlayer();
|
||||
mCurrentDate->setup(mGlobalVariables);
|
||||
mTimeManager->setup(mGlobalVariables);
|
||||
|
||||
// Initial seed.
|
||||
mPrng.seed(mRandomSeed);
|
||||
|
@ -615,7 +615,7 @@ namespace MWWorld
|
|||
|
||||
void World::setGlobalInt(GlobalVariableName name, int value)
|
||||
{
|
||||
bool dateUpdated = mCurrentDate->updateGlobalInt(name, value);
|
||||
bool dateUpdated = mTimeManager->updateGlobalInt(name, value);
|
||||
if (dateUpdated)
|
||||
updateSkyDate();
|
||||
|
||||
|
@ -624,7 +624,7 @@ namespace MWWorld
|
|||
|
||||
void World::setGlobalFloat(GlobalVariableName name, float value)
|
||||
{
|
||||
bool dateUpdated = mCurrentDate->updateGlobalFloat(name, value);
|
||||
bool dateUpdated = mTimeManager->updateGlobalFloat(name, value);
|
||||
if (dateUpdated)
|
||||
updateSkyDate();
|
||||
|
||||
|
@ -646,11 +646,6 @@ namespace MWWorld
|
|||
return mGlobalVariables.getType(name);
|
||||
}
|
||||
|
||||
std::string_view World::getMonthName(int month) const
|
||||
{
|
||||
return mCurrentDate->getMonthName(month);
|
||||
}
|
||||
|
||||
std::string_view World::getCellName(const MWWorld::CellStore* cell) const
|
||||
{
|
||||
if (!cell)
|
||||
|
@ -893,7 +888,7 @@ namespace MWWorld
|
|||
// When we fast-forward time, we should recharge magic items
|
||||
// in all loaded cells, using game world time
|
||||
float duration = hours * 3600;
|
||||
const float timeScaleFactor = getTimeScaleFactor();
|
||||
const float timeScaleFactor = mTimeManager->getGameTimeScale();
|
||||
if (timeScaleFactor != 0.0f)
|
||||
duration /= timeScaleFactor;
|
||||
|
||||
|
@ -901,7 +896,7 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
mWeatherManager->advanceTime(hours, incremental);
|
||||
mCurrentDate->advanceTime(hours, mGlobalVariables);
|
||||
mTimeManager->advanceTime(hours, mGlobalVariables);
|
||||
updateSkyDate();
|
||||
|
||||
if (!incremental)
|
||||
|
@ -912,25 +907,9 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
|
||||
float World::getTimeScaleFactor() const
|
||||
{
|
||||
return mCurrentDate->getTimeScaleFactor();
|
||||
}
|
||||
|
||||
void World::setSimulationTimeScale(float scale)
|
||||
{
|
||||
mSimulationTimeScale = std::max(0.f, scale);
|
||||
MWBase::Environment::get().getSoundManager()->setSimulationTimeScale(mSimulationTimeScale);
|
||||
}
|
||||
|
||||
TimeStamp World::getTimeStamp() const
|
||||
{
|
||||
return mCurrentDate->getTimeStamp();
|
||||
}
|
||||
|
||||
ESM::EpochTimeStamp World::getEpochTimeStamp() const
|
||||
{
|
||||
return mCurrentDate->getEpochTimeStamp();
|
||||
return mTimeManager->getTimeStamp();
|
||||
}
|
||||
|
||||
bool World::toggleSky()
|
||||
|
@ -2314,7 +2293,7 @@ namespace MWWorld
|
|||
{
|
||||
mStore.rebuildIdsIndex();
|
||||
mStore.validateDynamic();
|
||||
mCurrentDate->setup(mGlobalVariables);
|
||||
mTimeManager->setup(mGlobalVariables);
|
||||
}
|
||||
|
||||
void World::setupPlayer()
|
||||
|
@ -3864,7 +3843,7 @@ namespace MWWorld
|
|||
|
||||
void World::updateSkyDate()
|
||||
{
|
||||
ESM::EpochTimeStamp currentDate = mCurrentDate->getEpochTimeStamp();
|
||||
ESM::EpochTimeStamp currentDate = mTimeManager->getEpochTimeStamp();
|
||||
mRendering->skySetDate(currentDate.mDay, currentDate.mMonth);
|
||||
}
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ namespace MWWorld
|
|||
std::unique_ptr<MWRender::RenderingManager> mRendering;
|
||||
std::unique_ptr<MWWorld::Scene> mWorldScene;
|
||||
std::unique_ptr<MWWorld::WeatherManager> mWeatherManager;
|
||||
std::unique_ptr<MWWorld::DateTimeManager> mCurrentDate;
|
||||
std::unique_ptr<MWWorld::DateTimeManager> mTimeManager;
|
||||
std::unique_ptr<ProjectileManager> mProjectileManager;
|
||||
|
||||
bool mSky;
|
||||
|
@ -135,8 +135,6 @@ namespace MWWorld
|
|||
|
||||
uint32_t mRandomSeed{};
|
||||
|
||||
float mSimulationTimeScale = 1.0;
|
||||
|
||||
// not implemented
|
||||
World(const World&);
|
||||
World& operator=(const World&);
|
||||
|
@ -309,15 +307,9 @@ namespace MWWorld
|
|||
void advanceTime(double hours, bool incremental = false) override;
|
||||
///< Advance in-game time.
|
||||
|
||||
std::string_view getMonthName(int month = -1) const override;
|
||||
///< Return name of month (-1: current month)
|
||||
|
||||
TimeStamp getTimeStamp() const override;
|
||||
///< Return current in-game time and number of day since new game start.
|
||||
|
||||
ESM::EpochTimeStamp getEpochTimeStamp() const override;
|
||||
///< Return current in-game date and time.
|
||||
|
||||
bool toggleSky() override;
|
||||
///< \return Resulting mode
|
||||
|
||||
|
@ -339,12 +331,6 @@ namespace MWWorld
|
|||
|
||||
void modRegion(const ESM::RefId& regionid, const std::vector<char>& chances) override;
|
||||
|
||||
float getTimeScaleFactor() const override;
|
||||
|
||||
float getSimulationTimeScale() const override { return mSimulationTimeScale; }
|
||||
|
||||
void setSimulationTimeScale(float scale) override;
|
||||
|
||||
void changeToInteriorCell(const std::string_view cellName, const ESM::Position& position, bool adjustPlayerPos,
|
||||
bool changeEvent = true) override;
|
||||
///< Move to interior cell.
|
||||
|
@ -690,6 +676,8 @@ namespace MWWorld
|
|||
|
||||
MWRender::PostProcessor* getPostProcessor() override;
|
||||
|
||||
DateTimeManager* getTimeManager() override { return mTimeManager.get(); }
|
||||
|
||||
void setActorActive(const MWWorld::Ptr& ptr, bool value) override;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//
|
||||
// Subrecords:
|
||||
// LUAF - LuaScriptCfg::mFlags and ESM::RecNameInts list
|
||||
// LUAW - Start of MWLua::WorldView data
|
||||
// LUAW - Simulation time and last generated RefNum
|
||||
// LUAE - Start of MWLua::LocalEvent or MWLua::GlobalEvent (eventName)
|
||||
// LUAS - VFS path to a Lua script
|
||||
// LUAD - Serialized Lua variable
|
||||
|
|
|
@ -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…
Reference in a new issue