summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrei Kortunov <andrei.kortunov@yandex.ru>2024-02-24 15:57:11 +0400
committerAndrei Kortunov <andrei.kortunov@yandex.ru>2024-02-27 23:26:22 +0400
commitddd09456453f31bcefc18688655edd7b8165e00f (patch)
tree2e7fc4b8acce5b6602da1cda589a850340a2ec72
parent595e42ae43944bed3fd2ee91d35345cc0f40f923 (diff)
Add a storage mode to drop section on game exit
-rw-r--r--CMakeLists.txt2
-rw-r--r--apps/openmw/mwlua/luamanagerimp.cpp9
-rw-r--r--components/lua/storage.cpp46
-rw-r--r--components/lua/storage.hpp22
-rw-r--r--files/lua_api/openmw/storage.lua29
5 files changed, 83 insertions, 25 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 76aede04c9..ca25fd05ff 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -80,7 +80,7 @@ message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 49)
set(OPENMW_VERSION_RELEASE 0)
-set(OPENMW_LUA_API_REVISION 55)
+set(OPENMW_LUA_API_REVISION 56)
set(OPENMW_POSTPROCESSING_API_REVISION 1)
set(OPENMW_VERSION_COMMITHASH "")
diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp
index 4e16b396cd..256a11a0b6 100644
--- a/apps/openmw/mwlua/luamanagerimp.cpp
+++ b/apps/openmw/mwlua/luamanagerimp.cpp
@@ -112,13 +112,12 @@ namespace MWLua
mPlayerPackages.insert(mLocalPackages.begin(), mLocalPackages.end());
LuaUtil::LuaStorage::initLuaBindings(mLua.sol());
- mGlobalScripts.addPackage(
- "openmw.storage", LuaUtil::LuaStorage::initGlobalPackage(mLua.sol(), &mGlobalStorage));
+ mGlobalScripts.addPackage("openmw.storage", LuaUtil::LuaStorage::initGlobalPackage(mLua, &mGlobalStorage));
mMenuScripts.addPackage(
- "openmw.storage", LuaUtil::LuaStorage::initMenuPackage(mLua.sol(), &mGlobalStorage, &mPlayerStorage));
- mLocalPackages["openmw.storage"] = LuaUtil::LuaStorage::initLocalPackage(mLua.sol(), &mGlobalStorage);
+ "openmw.storage", LuaUtil::LuaStorage::initMenuPackage(mLua, &mGlobalStorage, &mPlayerStorage));
+ mLocalPackages["openmw.storage"] = LuaUtil::LuaStorage::initLocalPackage(mLua, &mGlobalStorage);
mPlayerPackages["openmw.storage"]
- = LuaUtil::LuaStorage::initPlayerPackage(mLua.sol(), &mGlobalStorage, &mPlayerStorage);
+ = LuaUtil::LuaStorage::initPlayerPackage(mLua, &mGlobalStorage, &mPlayerStorage);
mPlayerStorage.setActive(true);
mGlobalStorage.setActive(false);
diff --git a/components/lua/storage.cpp b/components/lua/storage.cpp
index dd53fdffcb..db81b6e172 100644
--- a/components/lua/storage.cpp
+++ b/components/lua/storage.cpp
@@ -17,6 +17,15 @@ namespace LuaUtil
{
LuaStorage::Value LuaStorage::Section::sEmpty;
+ void LuaStorage::registerLifeTime(LuaUtil::LuaState& luaState, sol::table& res)
+ {
+ res["LIFE_TIME"] = LuaUtil::makeStrictReadOnly(luaState.tableFromPairs<std::string_view, Section::LifeTime>({
+ { "Persistent", Section::LifeTime::Persistent },
+ { "GameSession", Section::LifeTime::GameSession },
+ { "Temporary", Section::LifeTime::Temporary },
+ }));
+ }
+
sol::object LuaStorage::Value::getCopy(lua_State* L) const
{
return deserialize(L, mSerializedValue);
@@ -142,7 +151,12 @@ namespace LuaUtil
sview["removeOnExit"] = [](const SectionView& section) {
if (section.mReadOnly)
throw std::runtime_error("Access to storage is read only");
- section.mSection->mPermanent = false;
+ section.mSection->mLifeTime = Section::Temporary;
+ };
+ sview["setLifeTime"] = [](const SectionView& section, Section::LifeTime lifeTime) {
+ if (section.mReadOnly)
+ throw std::runtime_error("Access to storage is read only");
+ section.mSection->mLifeTime = lifeTime;
};
sview["set"] = [](const SectionView& section, std::string_view key, const sol::object& value) {
if (section.mReadOnly)
@@ -151,26 +165,33 @@ namespace LuaUtil
};
}
- sol::table LuaStorage::initGlobalPackage(lua_State* lua, LuaStorage* globalStorage)
+ sol::table LuaStorage::initGlobalPackage(LuaUtil::LuaState& luaState, LuaStorage* globalStorage)
{
- sol::table res(lua, sol::create);
+ sol::table res(luaState.sol(), sol::create);
+ registerLifeTime(luaState, res);
+
res["globalSection"]
= [globalStorage](std::string_view section) { return globalStorage->getMutableSection(section); };
res["allGlobalSections"] = [globalStorage]() { return globalStorage->getAllSections(); };
return LuaUtil::makeReadOnly(res);
}
- sol::table LuaStorage::initLocalPackage(lua_State* lua, LuaStorage* globalStorage)
+ sol::table LuaStorage::initLocalPackage(LuaUtil::LuaState& luaState, LuaStorage* globalStorage)
{
- sol::table res(lua, sol::create);
+ sol::table res(luaState.sol(), sol::create);
+ registerLifeTime(luaState, res);
+
res["globalSection"]
= [globalStorage](std::string_view section) { return globalStorage->getReadOnlySection(section); };
return LuaUtil::makeReadOnly(res);
}
- sol::table LuaStorage::initPlayerPackage(lua_State* lua, LuaStorage* globalStorage, LuaStorage* playerStorage)
+ sol::table LuaStorage::initPlayerPackage(
+ LuaUtil::LuaState& luaState, LuaStorage* globalStorage, LuaStorage* playerStorage)
{
- sol::table res(lua, sol::create);
+ sol::table res(luaState.sol(), sol::create);
+ registerLifeTime(luaState, res);
+
res["globalSection"]
= [globalStorage](std::string_view section) { return globalStorage->getReadOnlySection(section); };
res["playerSection"]
@@ -179,9 +200,12 @@ namespace LuaUtil
return LuaUtil::makeReadOnly(res);
}
- sol::table LuaStorage::initMenuPackage(lua_State* lua, LuaStorage* globalStorage, LuaStorage* playerStorage)
+ sol::table LuaStorage::initMenuPackage(
+ LuaUtil::LuaState& luaState, LuaStorage* globalStorage, LuaStorage* playerStorage)
{
- sol::table res(lua, sol::create);
+ sol::table res(luaState.sol(), sol::create);
+ registerLifeTime(luaState, res);
+
res["playerSection"] = [playerStorage](std::string_view section) {
return playerStorage->getMutableSection(section, /*forMenuScripts=*/true);
};
@@ -199,7 +223,7 @@ namespace LuaUtil
it->second->mCallbacks.clear();
// Note that we don't clear menu callbacks for permanent sections
// because starting/loading a game doesn't reset menu scripts.
- if (!it->second->mPermanent)
+ if (it->second->mLifeTime == Section::Temporary)
{
it->second->mMenuScriptsCallbacks.clear();
it->second->mValues.clear();
@@ -238,7 +262,7 @@ namespace LuaUtil
sol::table data(mLua, sol::create);
for (const auto& [sectionName, section] : mData)
{
- if (section->mPermanent && !section->mValues.empty())
+ if (section->mLifeTime == Section::Persistent && !section->mValues.empty())
data[sectionName] = section->asTable();
}
std::string serializedData = serialize(data);
diff --git a/components/lua/storage.hpp b/components/lua/storage.hpp
index 75e0e14a16..061a5aace3 100644
--- a/components/lua/storage.hpp
+++ b/components/lua/storage.hpp
@@ -14,11 +14,13 @@ namespace LuaUtil
class LuaStorage
{
public:
- static void initLuaBindings(lua_State*);
- static sol::table initGlobalPackage(lua_State* lua, LuaStorage* globalStorage);
- static sol::table initLocalPackage(lua_State* lua, LuaStorage* globalStorage);
- static sol::table initPlayerPackage(lua_State* lua, LuaStorage* globalStorage, LuaStorage* playerStorage);
- static sol::table initMenuPackage(lua_State* lua, LuaStorage* globalStorage, LuaStorage* playerStorage);
+ static void initLuaBindings(lua_State* L);
+ static sol::table initGlobalPackage(LuaUtil::LuaState& luaState, LuaStorage* globalStorage);
+ static sol::table initLocalPackage(LuaUtil::LuaState& luaState, LuaStorage* globalStorage);
+ static sol::table initPlayerPackage(
+ LuaUtil::LuaState& luaState, LuaStorage* globalStorage, LuaStorage* playerStorage);
+ static sol::table initMenuPackage(
+ LuaUtil::LuaState& luaState, LuaStorage* globalStorage, LuaStorage* playerStorage);
explicit LuaStorage(lua_State* lua)
: mLua(lua)
@@ -78,6 +80,13 @@ namespace LuaUtil
struct Section
{
+ enum LifeTime
+ {
+ Persistent,
+ GameSession,
+ Temporary
+ };
+
explicit Section(LuaStorage* storage, std::string name)
: mStorage(storage)
, mSectionName(std::move(name))
@@ -96,7 +105,7 @@ namespace LuaUtil
std::vector<Callback> mCallbacks;
std::vector<Callback> mMenuScriptsCallbacks; // menu callbacks are in a separate vector because we don't
// remove them in clear()
- bool mPermanent = true;
+ LifeTime mLifeTime = Persistent;
static Value sEmpty;
void checkIfActive() const { mStorage->checkIfActive(); }
@@ -120,6 +129,7 @@ namespace LuaUtil
if (!mActive)
throw std::logic_error("Trying to access inactive storage");
}
+ static void registerLifeTime(LuaUtil::LuaState& luaState, sol::table& res);
};
}
diff --git a/files/lua_api/openmw/storage.lua b/files/lua_api/openmw/storage.lua
index 2335719be8..575b0f83d9 100644
--- a/files/lua_api/openmw/storage.lua
+++ b/files/lua_api/openmw/storage.lua
@@ -15,6 +15,15 @@
-- end
-- end))
+--- Possible @{#LifeTime} values
+-- @field [parent=#storage] #LifeTime LIFE_TIME
+
+--- `storage.LIFE_TIME`
+-- @type LifeTime
+-- @field #number Persistent "0" Data is stored for the whole game session and remains on disk after quitting the game
+-- @field #number GameSession "1" Data is stored for the whole game session
+-- @field #number Temporary "2" Data is stored until script context reset
+
---
-- Get a section of the global storage; can be used by any script, but only global scripts can change values.
-- Menu scripts can only access it when a game is running.
@@ -83,12 +92,28 @@
-- @param #table values (optional) New values
---
--- Make the whole section temporary: will be removed on exit or when load a save.
+-- (DEPRECATED, use `setLifeTime(openmw.storage.LIFE_TIME.Temporary)`) Make the whole section temporary: will be removed on exit or when load a save.
-- Temporary sections have the same interface to get/set values, the only difference is they will not
-- be saved to the permanent storage on exit.
--- This function can not be used for a global storage section from a local script.
+-- This function can be used for a global storage section from a global script or for a player storage section from a player or menu script.
-- @function [parent=#StorageSection] removeOnExit
-- @param self
+-- @usage
+-- local storage = require('openmw.storage')
+-- local myModData = storage.globalSection('MyModExample')
+-- myModData:removeOnExit()
+
+---
+-- Set the life time of given storage section.
+-- New sections initially have a Persistent life time.
+-- This function can be used for a global storage section from a global script or for a player storage section from a player or menu script.
+-- @function [parent=#StorageSection] setLifeTime
+-- @param self
+-- @param #LifeTime lifeTime Section life time
+-- @usage
+-- local storage = require('openmw.storage')
+-- local myModData = storage.globalSection('MyModExample')
+-- myModData:setLifeTime(storage.LIFE_TIME.Temporary)
---
-- Set value by a string key; can not be used for global storage from a local script.