mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-28 12:39:41 +00:00
Allow menu scripts to read global sections while a game is loaded
This commit is contained in:
parent
9b54f479e8
commit
962ecc4329
8 changed files with 80 additions and 14 deletions
|
@ -54,6 +54,7 @@ namespace MWBase
|
|||
|
||||
virtual void newGameStarted() = 0;
|
||||
virtual void gameLoaded() = 0;
|
||||
virtual void gameEnded() = 0;
|
||||
virtual void objectAddedToScene(const MWWorld::Ptr& ptr) = 0;
|
||||
virtual void objectRemovedFromScene(const MWWorld::Ptr& ptr) = 0;
|
||||
virtual void objectTeleported(const MWWorld::Ptr& ptr) = 0;
|
||||
|
|
|
@ -105,11 +105,14 @@ namespace MWLua
|
|||
LuaUtil::LuaStorage::initLuaBindings(mLua.sol());
|
||||
mGlobalScripts.addPackage(
|
||||
"openmw.storage", LuaUtil::LuaStorage::initGlobalPackage(mLua.sol(), &mGlobalStorage));
|
||||
mMenuScripts.addPackage("openmw.storage", LuaUtil::LuaStorage::initMenuPackage(mLua.sol(), &mPlayerStorage));
|
||||
mMenuScripts.addPackage(
|
||||
"openmw.storage", LuaUtil::LuaStorage::initMenuPackage(mLua.sol(), &mGlobalStorage, &mPlayerStorage));
|
||||
mLocalPackages["openmw.storage"] = LuaUtil::LuaStorage::initLocalPackage(mLua.sol(), &mGlobalStorage);
|
||||
mPlayerPackages["openmw.storage"]
|
||||
= LuaUtil::LuaStorage::initPlayerPackage(mLua.sol(), &mGlobalStorage, &mPlayerStorage);
|
||||
|
||||
mPlayerStorage.setActive(true);
|
||||
|
||||
initConfiguration();
|
||||
mInitialized = true;
|
||||
mMenuScripts.addAutoStartedScripts();
|
||||
|
@ -301,6 +304,7 @@ namespace MWLua
|
|||
mPlayer = MWWorld::Ptr();
|
||||
}
|
||||
mGlobalStorage.clearTemporaryAndRemoveCallbacks();
|
||||
mGlobalStorage.setActive(false);
|
||||
mPlayerStorage.clearTemporaryAndRemoveCallbacks();
|
||||
mInputActions.clear();
|
||||
mInputTriggers.clear();
|
||||
|
@ -329,6 +333,7 @@ namespace MWLua
|
|||
|
||||
void LuaManager::newGameStarted()
|
||||
{
|
||||
mGlobalStorage.setActive(true);
|
||||
mInputEvents.clear();
|
||||
mGlobalScripts.addAutoStartedScripts();
|
||||
mGlobalScriptsStarted = true;
|
||||
|
@ -338,12 +343,20 @@ namespace MWLua
|
|||
|
||||
void LuaManager::gameLoaded()
|
||||
{
|
||||
mGlobalStorage.setActive(true);
|
||||
if (!mGlobalScriptsStarted)
|
||||
mGlobalScripts.addAutoStartedScripts();
|
||||
mGlobalScriptsStarted = true;
|
||||
mMenuScripts.stateChanged();
|
||||
}
|
||||
|
||||
void LuaManager::gameEnded()
|
||||
{
|
||||
// TODO: disable scripts and global storage when the game is actually unloaded
|
||||
// mGlobalStorage.setActive(false);
|
||||
mMenuScripts.stateChanged();
|
||||
}
|
||||
|
||||
void LuaManager::uiModeChanged(const MWWorld::Ptr& arg)
|
||||
{
|
||||
if (mPlayer.isEmpty())
|
||||
|
@ -492,6 +505,10 @@ namespace MWLua
|
|||
throw std::runtime_error("Last generated RefNum is invalid");
|
||||
MWBase::Environment::get().getWorldModel()->setLastGeneratedRefNum(lastGenerated);
|
||||
|
||||
// TODO: don't execute scripts right away, it will be necessary in multiplayer where global storage requires
|
||||
// initialization. For now just set global storage as active slightly before it would be set by gameLoaded()
|
||||
mGlobalStorage.setActive(true);
|
||||
|
||||
ESM::LuaScripts globalScripts;
|
||||
globalScripts.load(reader);
|
||||
mLuaEvents.load(mLua.sol(), reader, mContentFileMapping, mGlobalLoader.get());
|
||||
|
@ -540,29 +557,49 @@ namespace MWLua
|
|||
mInputTriggers.clear();
|
||||
initConfiguration();
|
||||
|
||||
{ // Reload global scripts
|
||||
ESM::LuaScripts globalData;
|
||||
|
||||
if (mGlobalScriptsStarted)
|
||||
{
|
||||
mGlobalScripts.setSavedDataDeserializer(mGlobalSerializer.get());
|
||||
ESM::LuaScripts data;
|
||||
mGlobalScripts.save(data);
|
||||
mGlobalScripts.save(globalData);
|
||||
mGlobalStorage.clearTemporaryAndRemoveCallbacks();
|
||||
mGlobalScripts.load(data);
|
||||
}
|
||||
|
||||
std::unordered_map<ESM::RefNum, ESM::LuaScripts> localData;
|
||||
|
||||
for (const auto& [id, ptr] : MWBase::Environment::get().getWorldModel()->getPtrRegistryView())
|
||||
{ // Reload local scripts
|
||||
{
|
||||
LocalScripts* scripts = ptr.getRefData().getLuaScripts();
|
||||
if (scripts == nullptr)
|
||||
continue;
|
||||
scripts->setSavedDataDeserializer(mLocalSerializer.get());
|
||||
ESM::LuaScripts data;
|
||||
scripts->save(data);
|
||||
scripts->load(data);
|
||||
localData[id] = data;
|
||||
}
|
||||
|
||||
mMenuScripts.removeAllScripts();
|
||||
|
||||
mPlayerStorage.clearTemporaryAndRemoveCallbacks();
|
||||
|
||||
mMenuScripts.addAutoStartedScripts();
|
||||
|
||||
for (const auto& [id, ptr] : MWBase::Environment::get().getWorldModel()->getPtrRegistryView())
|
||||
{
|
||||
LocalScripts* scripts = ptr.getRefData().getLuaScripts();
|
||||
if (scripts == nullptr)
|
||||
continue;
|
||||
scripts->load(localData[id]);
|
||||
}
|
||||
|
||||
for (LocalScripts* scripts : mActiveLocalScripts)
|
||||
scripts->setActive(true);
|
||||
|
||||
mMenuScripts.removeAllScripts();
|
||||
mMenuScripts.addAutoStartedScripts();
|
||||
if (mGlobalScriptsStarted)
|
||||
{
|
||||
mGlobalScripts.load(globalData);
|
||||
}
|
||||
}
|
||||
|
||||
void LuaManager::handleConsoleCommand(
|
||||
|
|
|
@ -68,6 +68,7 @@ namespace MWLua
|
|||
// LuaManager queues these events and propagates to scripts on the next `update` call.
|
||||
void newGameStarted() override;
|
||||
void gameLoaded() override;
|
||||
void gameEnded() override;
|
||||
void objectAddedToScene(const MWWorld::Ptr& ptr) override;
|
||||
void objectRemovedFromScene(const MWWorld::Ptr& ptr) override;
|
||||
void inputEvent(const InputEvent& event) override;
|
||||
|
|
|
@ -157,10 +157,10 @@ void MWState::StateManager::newGame(bool bypass)
|
|||
{
|
||||
Log(Debug::Info) << "Starting a new game";
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup();
|
||||
MWBase::Environment::get().getLuaManager()->newGameStarted();
|
||||
MWBase::Environment::get().getWorld()->startNewGame(bypass);
|
||||
|
||||
mState = State_Running;
|
||||
MWBase::Environment::get().getLuaManager()->newGameStarted();
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->fadeScreenOut(0);
|
||||
MWBase::Environment::get().getWindowManager()->fadeScreenIn(1);
|
||||
|
@ -184,11 +184,13 @@ void MWState::StateManager::newGame(bool bypass)
|
|||
void MWState::StateManager::endGame()
|
||||
{
|
||||
mState = State_Ended;
|
||||
MWBase::Environment::get().getLuaManager()->gameEnded();
|
||||
}
|
||||
|
||||
void MWState::StateManager::resumeGame()
|
||||
{
|
||||
mState = State_Running;
|
||||
MWBase::Environment::get().getLuaManager()->gameLoaded();
|
||||
}
|
||||
|
||||
void MWState::StateManager::saveGame(std::string_view description, const Slot* slot)
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace
|
|||
sol::state_view& mLua = luaState.sol();
|
||||
LuaUtil::LuaStorage::initLuaBindings(mLua);
|
||||
LuaUtil::LuaStorage storage(mLua);
|
||||
storage.setActive(true);
|
||||
|
||||
std::vector<std::string> callbackCalls;
|
||||
sol::table callbackHiddenData(mLua, sol::create);
|
||||
|
@ -65,6 +66,7 @@ namespace
|
|||
sol::state mLua;
|
||||
LuaUtil::LuaStorage::initLuaBindings(mLua);
|
||||
LuaUtil::LuaStorage storage(mLua);
|
||||
storage.setActive(true);
|
||||
mLua["mutable"] = storage.getMutableSection("test");
|
||||
mLua["ro"] = storage.getReadOnlySection("test");
|
||||
|
||||
|
@ -82,6 +84,7 @@ namespace
|
|||
sol::state mLua;
|
||||
LuaUtil::LuaStorage::initLuaBindings(mLua);
|
||||
LuaUtil::LuaStorage storage(mLua);
|
||||
storage.setActive(true);
|
||||
|
||||
mLua["permanent"] = storage.getMutableSection("permanent");
|
||||
mLua["temporary"] = storage.getMutableSection("temporary");
|
||||
|
@ -104,6 +107,7 @@ namespace
|
|||
mLua.safe_script("permanent:set('z', 4)");
|
||||
|
||||
LuaUtil::LuaStorage storage2(mLua);
|
||||
storage2.setActive(true);
|
||||
storage2.load(tmpFile);
|
||||
mLua["permanent"] = storage2.getMutableSection("permanent");
|
||||
mLua["temporary"] = storage2.getMutableSection("temporary");
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace LuaUtil
|
|||
|
||||
const LuaStorage::Value& LuaStorage::Section::get(std::string_view key) const
|
||||
{
|
||||
checkIfActive();
|
||||
auto it = mValues.find(key);
|
||||
if (it != mValues.end())
|
||||
return it->second;
|
||||
|
@ -72,6 +73,7 @@ namespace LuaUtil
|
|||
|
||||
void LuaStorage::Section::set(std::string_view key, const sol::object& value)
|
||||
{
|
||||
checkIfActive();
|
||||
throwIfCallbackRecursionIsTooDeep();
|
||||
if (value != sol::nil)
|
||||
mValues[std::string(key)] = Value(value);
|
||||
|
@ -88,6 +90,7 @@ namespace LuaUtil
|
|||
|
||||
void LuaStorage::Section::setAll(const sol::optional<sol::table>& values)
|
||||
{
|
||||
checkIfActive();
|
||||
throwIfCallbackRecursionIsTooDeep();
|
||||
mValues.clear();
|
||||
if (values)
|
||||
|
@ -102,6 +105,7 @@ namespace LuaUtil
|
|||
|
||||
sol::table LuaStorage::Section::asTable()
|
||||
{
|
||||
checkIfActive();
|
||||
sol::table res(mStorage->mLua, sol::create);
|
||||
for (const auto& [k, v] : mValues)
|
||||
res[k] = v.getCopy(mStorage->mLua);
|
||||
|
@ -175,12 +179,14 @@ namespace LuaUtil
|
|||
return LuaUtil::makeReadOnly(res);
|
||||
}
|
||||
|
||||
sol::table LuaStorage::initMenuPackage(lua_State* lua, LuaStorage* playerStorage)
|
||||
sol::table LuaStorage::initMenuPackage(lua_State* lua, LuaStorage* globalStorage, LuaStorage* playerStorage)
|
||||
{
|
||||
sol::table res(lua, sol::create);
|
||||
res["playerSection"] = [playerStorage](std::string_view section) {
|
||||
return playerStorage->getMutableSection(section, /*forMenuScripts=*/true);
|
||||
};
|
||||
res["globalSection"]
|
||||
= [globalStorage](std::string_view section) { return globalStorage->getReadOnlySection(section); };
|
||||
res["allPlayerSections"] = [playerStorage]() { return playerStorage->getAllSections(); };
|
||||
return LuaUtil::makeReadOnly(res);
|
||||
}
|
||||
|
@ -244,6 +250,7 @@ namespace LuaUtil
|
|||
|
||||
const std::shared_ptr<LuaStorage::Section>& LuaStorage::getSection(std::string_view sectionName)
|
||||
{
|
||||
checkIfActive();
|
||||
auto it = mData.find(sectionName);
|
||||
if (it != mData.end())
|
||||
return it->second;
|
||||
|
@ -255,12 +262,14 @@ namespace LuaUtil
|
|||
|
||||
sol::object LuaStorage::getSection(std::string_view sectionName, bool readOnly, bool forMenuScripts)
|
||||
{
|
||||
checkIfActive();
|
||||
const std::shared_ptr<Section>& section = getSection(sectionName);
|
||||
return sol::make_object<SectionView>(mLua, SectionView{ section, readOnly, forMenuScripts });
|
||||
}
|
||||
|
||||
sol::table LuaStorage::getAllSections(bool readOnly)
|
||||
{
|
||||
checkIfActive();
|
||||
sol::table res(mLua, sol::create);
|
||||
for (const auto& [sectionName, _] : mData)
|
||||
res[sectionName] = getSection(sectionName, readOnly);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <map>
|
||||
#include <sol/sol.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "asyncpackage.hpp"
|
||||
#include "serialization.hpp"
|
||||
|
@ -17,10 +18,11 @@ namespace LuaUtil
|
|||
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* playerStorage);
|
||||
static sol::table initMenuPackage(lua_State* lua, LuaStorage* globalStorage, LuaStorage* playerStorage);
|
||||
|
||||
explicit LuaStorage(lua_State* lua)
|
||||
: mLua(lua)
|
||||
, mActive(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -55,6 +57,7 @@ namespace LuaUtil
|
|||
virtual void sectionReplaced(std::string_view section, const sol::optional<sol::table>& values) const = 0;
|
||||
};
|
||||
void setListener(const Listener* listener) { mListener = listener; }
|
||||
void setActive(bool active) { mActive = active; }
|
||||
|
||||
private:
|
||||
class Value
|
||||
|
@ -95,6 +98,8 @@ namespace LuaUtil
|
|||
// remove them in clear()
|
||||
bool mPermanent = true;
|
||||
static Value sEmpty;
|
||||
|
||||
void checkIfActive() const { mStorage->checkIfActive(); }
|
||||
};
|
||||
struct SectionView
|
||||
{
|
||||
|
@ -109,6 +114,12 @@ namespace LuaUtil
|
|||
std::map<std::string_view, std::shared_ptr<Section>> mData;
|
||||
const Listener* mListener = nullptr;
|
||||
std::set<const Section*> mRunningCallbacks;
|
||||
bool mActive;
|
||||
void checkIfActive() const
|
||||
{
|
||||
if (!mActive)
|
||||
throw std::logic_error("Trying to access inactive storage");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -17,13 +17,14 @@
|
|||
|
||||
---
|
||||
-- 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.
|
||||
-- Creates the section if it doesn't exist.
|
||||
-- @function [parent=#storage] globalSection
|
||||
-- @param #string sectionName
|
||||
-- @return #StorageSection
|
||||
|
||||
---
|
||||
-- Get a section of the player storage; can be used by player scripts only.
|
||||
-- Get a section of the player storage; can only be used by player and menu scripts.
|
||||
-- Creates the section if it doesn't exist.
|
||||
-- @function [parent=#storage] playerSection
|
||||
-- @param #string sectionName
|
||||
|
@ -36,7 +37,7 @@
|
|||
-- @return #table
|
||||
|
||||
---
|
||||
-- Get all global sections as a table; can be used by player scripts only.
|
||||
-- Get all player sections as a table; can only be used by player and menu scripts.
|
||||
-- Note that adding/removing items to the returned table doesn't create or remove sections.
|
||||
-- @function [parent=#storage] allPlayerSections
|
||||
-- @return #table
|
||||
|
|
Loading…
Reference in a new issue