mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-09-24 04:11:50 -04:00
Merge branch 'asynctimer' into 'master'
Add async timer that works when the game is paused See merge request OpenMW/openmw!4886
This commit is contained in:
commit
0e2b24d774
@ -83,7 +83,7 @@ add_openmw_dir (mwworld
|
|||||||
store esmstore fallback actionrepair actionsoulgem livecellref actiondoor
|
store esmstore fallback actionrepair actionsoulgem livecellref actiondoor
|
||||||
contentloader esmloader actiontrap cellreflist cellref weather projectilemanager
|
contentloader esmloader actiontrap cellreflist cellref weather projectilemanager
|
||||||
cellpreloader datetimemanager groundcoverstore magiceffects cell ptrregistry
|
cellpreloader datetimemanager groundcoverstore magiceffects cell ptrregistry
|
||||||
positioncellgrid
|
positioncellgrid asynctimer
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwphysics
|
add_openmw_dir (mwphysics
|
||||||
|
@ -69,6 +69,7 @@
|
|||||||
|
|
||||||
#include "mwworld/class.hpp"
|
#include "mwworld/class.hpp"
|
||||||
#include "mwworld/datetimemanager.hpp"
|
#include "mwworld/datetimemanager.hpp"
|
||||||
|
#include "mwworld/asynctimer.hpp"
|
||||||
#include "mwworld/worldimp.hpp"
|
#include "mwworld/worldimp.hpp"
|
||||||
|
|
||||||
#include "mwrender/vismask.hpp"
|
#include "mwrender/vismask.hpp"
|
||||||
@ -721,6 +722,9 @@ void OMW::Engine::prepareEngine()
|
|||||||
mStateManager = std::make_unique<MWState::StateManager>(mCfgMgr.getUserDataPath() / "saves", mContentFiles);
|
mStateManager = std::make_unique<MWState::StateManager>(mCfgMgr.getUserDataPath() / "saves", mContentFiles);
|
||||||
mEnvironment.setStateManager(*mStateManager);
|
mEnvironment.setStateManager(*mStateManager);
|
||||||
|
|
||||||
|
mAsyncTimer = std::make_unique<MWWorld::AsyncTimer>();
|
||||||
|
mEnvironment.setAsyncTimer(*mAsyncTimer);
|
||||||
|
|
||||||
const bool stereoEnabled = Settings::stereo().mStereoEnabled || osg::DisplaySettings::instance().get()->getStereo();
|
const bool stereoEnabled = Settings::stereo().mStereoEnabled || osg::DisplaySettings::instance().get()->getStereo();
|
||||||
mStereoManager = std::make_unique<Stereo::Manager>(
|
mStereoManager = std::make_unique<Stereo::Manager>(
|
||||||
mViewer, stereoEnabled, Settings::camera().mNearClip, Settings::camera().mViewingDistance);
|
mViewer, stereoEnabled, Settings::camera().mNearClip, Settings::camera().mViewingDistance);
|
||||||
@ -1051,6 +1055,8 @@ void OMW::Engine::go()
|
|||||||
timeManager.setRenderingSimulationTime(timeManager.getRenderingSimulationTime() + dt);
|
timeManager.setRenderingSimulationTime(timeManager.getRenderingSimulationTime() + dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mAsyncTimer->updateTimer();
|
||||||
|
|
||||||
if (stats)
|
if (stats)
|
||||||
{
|
{
|
||||||
// The delay is required because rendering happens in parallel to the main thread and stats from there is
|
// The delay is required because rendering happens in parallel to the main thread and stats from there is
|
||||||
|
@ -91,6 +91,7 @@ namespace MWSound
|
|||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class World;
|
class World;
|
||||||
|
class AsyncTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWScript
|
namespace MWScript
|
||||||
@ -139,6 +140,7 @@ namespace OMW
|
|||||||
std::unique_ptr<MWDialogue::Journal> mJournal;
|
std::unique_ptr<MWDialogue::Journal> mJournal;
|
||||||
std::unique_ptr<MWInput::InputManager> mInputManager;
|
std::unique_ptr<MWInput::InputManager> mInputManager;
|
||||||
std::unique_ptr<MWState::StateManager> mStateManager;
|
std::unique_ptr<MWState::StateManager> mStateManager;
|
||||||
|
std::unique_ptr<MWWorld::AsyncTimer> mAsyncTimer;
|
||||||
std::unique_ptr<MWLua::LuaManager> mLuaManager;
|
std::unique_ptr<MWLua::LuaManager> mLuaManager;
|
||||||
std::unique_ptr<MWLua::Worker> mLuaWorker;
|
std::unique_ptr<MWLua::Worker> mLuaWorker;
|
||||||
std::unique_ptr<L10n::Manager> mL10nManager;
|
std::unique_ptr<L10n::Manager> mL10nManager;
|
||||||
|
@ -20,6 +20,7 @@ namespace MWWorld
|
|||||||
class ESMStore;
|
class ESMStore;
|
||||||
class WorldModel;
|
class WorldModel;
|
||||||
class Scene;
|
class Scene;
|
||||||
|
class AsyncTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWBase
|
namespace MWBase
|
||||||
@ -55,6 +56,7 @@ namespace MWBase
|
|||||||
Journal* mJournal = nullptr;
|
Journal* mJournal = nullptr;
|
||||||
InputManager* mInputManager = nullptr;
|
InputManager* mInputManager = nullptr;
|
||||||
StateManager* mStateManager = nullptr;
|
StateManager* mStateManager = nullptr;
|
||||||
|
MWWorld::AsyncTimer* mAsyncTimer = nullptr;
|
||||||
LuaManager* mLuaManager = nullptr;
|
LuaManager* mLuaManager = nullptr;
|
||||||
Resource::ResourceSystem* mResourceSystem = nullptr;
|
Resource::ResourceSystem* mResourceSystem = nullptr;
|
||||||
L10n::Manager* mL10nManager = nullptr;
|
L10n::Manager* mL10nManager = nullptr;
|
||||||
@ -91,6 +93,8 @@ namespace MWBase
|
|||||||
|
|
||||||
void setStateManager(StateManager& value) { mStateManager = &value; }
|
void setStateManager(StateManager& value) { mStateManager = &value; }
|
||||||
|
|
||||||
|
void setAsyncTimer(MWWorld::AsyncTimer& value) { mAsyncTimer = &value; }
|
||||||
|
|
||||||
void setLuaManager(LuaManager& value) { mLuaManager = &value; }
|
void setLuaManager(LuaManager& value) { mLuaManager = &value; }
|
||||||
|
|
||||||
void setResourceSystem(Resource::ResourceSystem& value) { mResourceSystem = &value; }
|
void setResourceSystem(Resource::ResourceSystem& value) { mResourceSystem = &value; }
|
||||||
@ -118,6 +122,8 @@ namespace MWBase
|
|||||||
|
|
||||||
Misc::NotNullPtr<StateManager> getStateManager() const { return mStateManager; }
|
Misc::NotNullPtr<StateManager> getStateManager() const { return mStateManager; }
|
||||||
|
|
||||||
|
Misc::NotNullPtr<MWWorld::AsyncTimer> getAsyncTimer() const { return mAsyncTimer; }
|
||||||
|
|
||||||
Misc::NotNullPtr<LuaManager> getLuaManager() const { return mLuaManager; }
|
Misc::NotNullPtr<LuaManager> getLuaManager() const { return mLuaManager; }
|
||||||
|
|
||||||
Misc::NotNullPtr<Resource::ResourceSystem> getResourceSystem() const { return mResourceSystem; }
|
Misc::NotNullPtr<Resource::ResourceSystem> getResourceSystem() const { return mResourceSystem; }
|
||||||
|
53
apps/openmw/mwworld/asynctimer.cpp
Normal file
53
apps/openmw/mwworld/asynctimer.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "asynctimer.hpp"
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
AsyncTimer::AsyncTimer() = default;
|
||||||
|
|
||||||
|
AsyncTimer::~AsyncTimer() = default;
|
||||||
|
|
||||||
|
void AsyncTimer::updateTimer(){
|
||||||
|
auto time_now = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
std::vector<Callback> expired_callbacks;
|
||||||
|
|
||||||
|
while(!mTasks.empty() && mTasks.begin()->trigger_time <= time_now){
|
||||||
|
expired_callbacks.push_back(mTasks.begin()->callback);
|
||||||
|
mTasks.erase(mTasks.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& callback : expired_callbacks){
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncTimer::TaskId AsyncTimer::setTask(float delay, Callback callback){
|
||||||
|
if(delay < 0 || !callback) return -1;
|
||||||
|
|
||||||
|
auto triggerTime = std::chrono::steady_clock::now() +
|
||||||
|
std::chrono::milliseconds(static_cast<int>(delay * 1000));
|
||||||
|
|
||||||
|
AsyncTimer::TaskId new_id = mNext_id++;
|
||||||
|
|
||||||
|
mTasks.insert({triggerTime, std::move(callback), new_id});
|
||||||
|
return new_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncTimer::cancelTask(AsyncTimer::TaskId id){
|
||||||
|
if(id < 0) return;
|
||||||
|
|
||||||
|
for(auto it = mTasks.begin(); it != mTasks.end(); ++it){
|
||||||
|
if(it->id == id){
|
||||||
|
mTasks.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
apps/openmw/mwworld/asynctimer.hpp
Normal file
45
apps/openmw/mwworld/asynctimer.hpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef GAME_MWWORLD_ASYNCTIMER_H
|
||||||
|
#define GAME_MWWORLD_ASYNCTIMER_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
// @brief Async timer that works when the game is paused
|
||||||
|
class AsyncTimer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AsyncTimer();
|
||||||
|
~AsyncTimer();
|
||||||
|
|
||||||
|
using TimePoint = std::chrono::steady_clock::time_point;
|
||||||
|
using Callback = std::function<void()>;
|
||||||
|
using TaskId = uint64_t;
|
||||||
|
struct TimerTask{
|
||||||
|
TimePoint trigger_time;
|
||||||
|
Callback callback;
|
||||||
|
TaskId id;
|
||||||
|
|
||||||
|
// Comparator for ordering tasks by execution time (earliest first)
|
||||||
|
bool operator < (const TimerTask& other) const{
|
||||||
|
return trigger_time < other.trigger_time;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// @brief Updates timer state and executes due tasks
|
||||||
|
void updateTimer();
|
||||||
|
|
||||||
|
// @brief Schedules a new task for delayed execution
|
||||||
|
TaskId setTask(float delay, Callback callback);
|
||||||
|
|
||||||
|
// @brief Cancels a task by id
|
||||||
|
void cancelTask(TaskId id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::multiset<TimerTask> mTasks;
|
||||||
|
TaskId mNext_id = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif /* GAME_MWWORLD_ASYNCTIMER_H */
|
Loading…
x
Reference in New Issue
Block a user