From f2d0a702e9d08f1b1c13b74c19df01cc84009d28 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Fri, 12 Mar 2021 18:29:51 +0100 Subject: [PATCH] Add Lua timers --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwlua/asyncbindings.cpp | 55 +++++++++++++++++++++++++++++ apps/openmw/mwlua/luabindings.cpp | 2 ++ apps/openmw/mwlua/luabindings.hpp | 10 ++++++ apps/openmw/mwlua/luamanagerimp.cpp | 11 ++++++ apps/openmw/mwlua/worldview.cpp | 8 +++++ apps/openmw/mwlua/worldview.hpp | 10 ++++++ 7 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwlua/asyncbindings.cpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 1cf87388a6..555aa443c9 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -57,7 +57,7 @@ add_openmw_dir (mwscript add_openmw_dir (mwlua luamanagerimp localscripts object worldview luabindings userdataserializer - objectbindings + objectbindings asyncbindings ) add_openmw_dir (mwsound diff --git a/apps/openmw/mwlua/asyncbindings.cpp b/apps/openmw/mwlua/asyncbindings.cpp new file mode 100644 index 0000000000..83c1dbd81b --- /dev/null +++ b/apps/openmw/mwlua/asyncbindings.cpp @@ -0,0 +1,55 @@ +#include "luabindings.hpp" + +namespace sol +{ + template <> + struct is_automagical : std::false_type {}; +} + +namespace MWLua +{ + + struct TimerCallback + { + AsyncPackageId mAsyncId; + std::string mName; + }; + + sol::function getAsyncPackageInitializer(const Context& context) + { + sol::usertype api = context.mLua->sol().new_usertype("AsyncPackage"); + api["registerTimerCallback"] = [](const AsyncPackageId& asyncId, std::string_view name, sol::function callback) + { + asyncId.mContainer->registerTimerCallback(asyncId.mScript, name, std::move(callback)); + return TimerCallback{asyncId, std::string(name)}; + }; + api["newTimerInSeconds"] = [world=context.mWorldView](const AsyncPackageId&, double delay, + const TimerCallback& callback, sol::object callbackArg) + { + callback.mAsyncId.mContainer->setupSerializableTimer( + false, world->getGameTimeInSeconds() + delay, callback.mAsyncId.mScript, callback.mName, std::move(callbackArg)); + }; + api["newTimerInHours"] = [world=context.mWorldView](const AsyncPackageId&, double delay, + const TimerCallback& callback, sol::object callbackArg) + { + callback.mAsyncId.mContainer->setupSerializableTimer( + true, world->getGameTimeInHours() + delay, callback.mAsyncId.mScript, callback.mName, std::move(callbackArg)); + }; + api["newUnsavableTimerInSeconds"] = [world=context.mWorldView](const AsyncPackageId& asyncId, double delay, sol::function callback) + { + asyncId.mContainer->setupUnsavableTimer(false, world->getGameTimeInSeconds() + delay, asyncId.mScript, std::move(callback)); + }; + api["newUnsavableTimerInHours"] = [world=context.mWorldView](const AsyncPackageId& asyncId, double delay, sol::function callback) + { + asyncId.mContainer->setupUnsavableTimer(true, world->getGameTimeInHours() + delay, asyncId.mScript, std::move(callback)); + }; + + auto initializer = [](sol::table hiddenData) + { + LuaUtil::ScriptsContainer::ScriptId id = hiddenData[LuaUtil::ScriptsContainer::ScriptId::KEY]; + return AsyncPackageId{id.mContainer, id.mPath}; + }; + return sol::make_object(context.mLua->sol(), initializer); + } + +} diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index 4f6519397e..5ebb6670f8 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -15,6 +15,8 @@ namespace MWLua { context.mGlobalEventQueue->push_back({std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer)}); }; + api["getGameTimeInSeconds"] = [world=context.mWorldView]() { return world->getGameTimeInSeconds(); }; + api["getGameTimeInHours"] = [world=context.mWorldView]() { return world->getGameTimeInHours(); }; return context.mLua->makeReadOnly(api); } diff --git a/apps/openmw/mwlua/luabindings.hpp b/apps/openmw/mwlua/luabindings.hpp index 7e544b7eb4..2eae569ef0 100644 --- a/apps/openmw/mwlua/luabindings.hpp +++ b/apps/openmw/mwlua/luabindings.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "eventqueue.hpp" #include "object.hpp" @@ -30,6 +31,15 @@ namespace MWLua void initObjectBindingsForLocalScripts(const Context&); void initObjectBindingsForGlobalScripts(const Context&); + // Implemented in asyncbindings.cpp + struct AsyncPackageId + { + // TODO: add ObjectId mLocalObject; + LuaUtil::ScriptsContainer* mContainer; + std::string mScript; + }; + sol::function getAsyncPackageInitializer(const Context&); + // openmw.self package is implemented in localscripts.cpp } diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index 023e95e7b4..92e4a257e7 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -34,6 +34,7 @@ namespace MWLua initObjectBindingsForLocalScripts(localContext); LocalScripts::initializeSelfPackage(localContext); + mLua.addCommonPackage("openmw.async", getAsyncPackageInitializer(context)); mLua.addCommonPackage("openmw.util", LuaUtil::initUtilPackage(mLua.sol())); mLua.addCommonPackage("openmw.core", initCorePackage(context)); mGlobalScripts.addPackage("openmw.world", initWorldPackage(context)); @@ -62,6 +63,16 @@ namespace MWLua mGlobalEvents = std::vector(); mLocalEvents = std::vector(); + { // Update time and process timers + double seconds = mWorldView.getGameTimeInSeconds() + dt; + mWorldView.setGameTimeInSeconds(seconds); + double hours = mWorldView.getGameTimeInHours(); + + mGlobalScripts.processTimers(seconds, hours); + for (LocalScripts* scripts : mActiveLocalScripts) + scripts->processTimers(seconds, hours); + } + for (GlobalEvent& e : globalEvents) mGlobalScripts.receiveEvent(e.eventName, e.eventData); for (LocalEvent& e : localEvents) diff --git a/apps/openmw/mwlua/worldview.cpp b/apps/openmw/mwlua/worldview.cpp index e088dda252..a5b427a011 100644 --- a/apps/openmw/mwlua/worldview.cpp +++ b/apps/openmw/mwlua/worldview.cpp @@ -1,6 +1,7 @@ #include "worldview.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/timestamp.hpp" namespace MWLua { @@ -35,6 +36,13 @@ namespace MWLua removeFromGroup(mItemsInScene, ptr); } + double WorldView::getGameTimeInHours() const + { + MWBase::World* world = MWBase::Environment::get().getWorld(); + MWWorld::TimeStamp timeStamp = world->getTimeStamp(); + return static_cast(timeStamp.getDay()) * 24 + timeStamp.getHour(); + } + void WorldView::ObjectGroup::updateList() { if (mChanged) diff --git a/apps/openmw/mwlua/worldview.hpp b/apps/openmw/mwlua/worldview.hpp index fbfefccdc6..ba6c8cccec 100644 --- a/apps/openmw/mwlua/worldview.hpp +++ b/apps/openmw/mwlua/worldview.hpp @@ -13,6 +13,14 @@ namespace MWLua void update(); // Should be called every frame. void clear(); // Should be called every time before starting or loading a new game. + // Returns the number of seconds passed from the beginning of the game. + double getGameTimeInSeconds() const { return mGameSeconds; } + void setGameTimeInSeconds(double t) { mGameSeconds = t; } + + // Returns the number of game hours passed from the beginning of the game. + // Note that the number of seconds in a game hour is not fixed. + double getGameTimeInHours() const; + ObjectIdList getActorsInScene() const { return mActorsInScene.mList; } ObjectIdList getItemsInScene() const { return mItemsInScene.mList; } @@ -40,6 +48,8 @@ namespace MWLua ObjectRegistry mObjectRegistry; ObjectGroup mActorsInScene; ObjectGroup mItemsInScene; + + double mGameSeconds = 0; }; }