1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-26 09:35:28 +00:00
OpenMW/apps/openmw/mwscript/globalscripts.cpp
fteppe 125b21de20 Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type
The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID

Slowly going through all the changes to make, still hundreds of errors

a lot of functions/structures use std::string or stringview to designate an ID. So it takes time

Continues slowly replacing ids. There are technically more and more compilation errors

I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type

Continue moving forward, changes to the stores

slowly moving along

Starting to see the fruit of those changes.

still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type.

More replacements. Things are starting to get easier

I can see more and more often the issue is that the function is awaiting a RefId, but is given a string
there is less need to go down functions and to fix a long list of them.

Still moving forward, and for the first time error count is going down!

Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably

Cells are back to using string for the name, haven't fixed everything yet. Many other changes

Under the bar of 400 compilation errors.

more good progress <100 compile errors!

More progress

Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string

some more progress on other fronts

Mostly game settings clean

one error opened a lot of other errors. Down to 18, but more will prbably appear

only link errors left??

Fixed link errors

OpenMW compiles, and launches, with some issues, but still!
2022-12-27 19:15:54 +01:00

330 lines
9.7 KiB
C++

#include "globalscripts.hpp"
#include <components/debug/debuglog.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/esm3/globalscript.hpp>
#include <components/esm3/loadscpt.hpp>
#include <components/esm3/loadsscr.hpp>
#include <components/misc/strings/lower.hpp>
#include "../mwworld/esmstore.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/scriptmanager.hpp"
#include "../mwbase/world.hpp"
#include "interpretercontext.hpp"
namespace
{
struct ScriptCreatingVisitor
{
ESM::GlobalScript operator()(const MWWorld::Ptr& ptr) const
{
ESM::GlobalScript script;
script.mTargetRef.unset();
script.mRunning = false;
if (!ptr.isEmpty())
{
if (ptr.getCellRef().hasContentFile())
{
script.mTargetId = ptr.getCellRef().getRefId();
script.mTargetRef = ptr.getCellRef().getRefNum();
}
else if (MWBase::Environment::get().getWorld()->getPlayerPtr() == ptr)
script.mTargetId = ptr.getCellRef().getRefId();
}
return script;
}
ESM::GlobalScript operator()(const std::pair<ESM::RefNum, ESM::RefId>& pair) const
{
ESM::GlobalScript script;
script.mTargetId = pair.second;
script.mTargetRef = pair.first;
script.mRunning = false;
return script;
}
};
struct PtrGettingVisitor
{
const MWWorld::Ptr* operator()(const MWWorld::Ptr& ptr) const { return &ptr; }
const MWWorld::Ptr* operator()(const std::pair<ESM::RefNum, ESM::RefId>& pair) const { return nullptr; }
};
struct PtrResolvingVisitor
{
MWWorld::Ptr operator()(const MWWorld::Ptr& ptr) const { return ptr; }
MWWorld::Ptr operator()(const std::pair<ESM::RefNum, ESM::RefId>& pair) const
{
if (pair.second.empty())
return MWWorld::Ptr();
else if (pair.first.hasContentFile())
return MWBase::Environment::get().getWorld()->searchPtrViaRefNum(pair.second, pair.first);
return MWBase::Environment::get().getWorld()->searchPtr(pair.second, false);
}
};
class MatchPtrVisitor
{
const MWWorld::Ptr& mPtr;
public:
MatchPtrVisitor(const MWWorld::Ptr& ptr)
: mPtr(ptr)
{
}
bool operator()(const MWWorld::Ptr& ptr) const { return ptr == mPtr; }
bool operator()(const std::pair<ESM::RefNum, ESM::RefId>& pair) const { return false; }
};
struct IdGettingVisitor
{
const ESM::RefId& operator()(const MWWorld::Ptr& ptr) const
{
if (ptr.isEmpty())
return ESM::RefId::sEmpty;
return ptr.mRef->mRef.getRefId();
}
const ESM::RefId& operator()(const std::pair<ESM::RefNum, ESM::RefId>& pair) const { return pair.second; }
};
}
namespace MWScript
{
GlobalScriptDesc::GlobalScriptDesc()
: mRunning(false)
{
}
const MWWorld::Ptr* GlobalScriptDesc::getPtrIfPresent() const
{
return std::visit(PtrGettingVisitor(), mTarget);
}
MWWorld::Ptr GlobalScriptDesc::getPtr()
{
MWWorld::Ptr ptr = std::visit(PtrResolvingVisitor{}, mTarget);
mTarget = ptr;
return ptr;
}
const ESM::RefId& GlobalScriptDesc::getId() const
{
return std::visit(IdGettingVisitor{}, mTarget);
}
GlobalScripts::GlobalScripts(const MWWorld::ESMStore& store)
: mStore(store)
{
}
void GlobalScripts::addScript(const ESM::RefId& name, const MWWorld::Ptr& target)
{
const auto iter = mScripts.find(name);
if (iter == mScripts.end())
{
if (const ESM::Script* script = mStore.get<ESM::Script>().search(name))
{
auto desc = std::make_shared<GlobalScriptDesc>();
MWWorld::Ptr ptr = target;
desc->mTarget = ptr;
desc->mRunning = true;
desc->mLocals.configure(*script);
mScripts.insert(std::make_pair(name, desc));
}
else
{
Log(Debug::Error) << "Failed to add global script " << name << ": script record not found";
}
}
else if (!iter->second->mRunning)
{
iter->second->mRunning = true;
MWWorld::Ptr ptr = target;
iter->second->mTarget = ptr;
}
}
void GlobalScripts::removeScript(const ESM::RefId& name)
{
const auto iter = mScripts.find(name);
if (iter != mScripts.end())
iter->second->mRunning = false;
}
bool GlobalScripts::isRunning(const ESM::RefId& name) const
{
const auto iter = mScripts.find(name);
if (iter == mScripts.end())
return false;
return iter->second->mRunning;
}
void GlobalScripts::run()
{
for (const auto& script : mScripts)
{
if (script.second->mRunning)
{
MWScript::InterpreterContext context(script.second);
if (!MWBase::Environment::get().getScriptManager()->run(script.first, context))
script.second->mRunning = false;
}
}
}
void GlobalScripts::clear()
{
mScripts.clear();
}
void GlobalScripts::addStartup()
{
// make list of global scripts to be added
std::vector<ESM::RefId> scripts;
scripts.emplace_back(ESM::RefId::stringRefId("main"));
for (MWWorld::Store<ESM::StartScript>::iterator iter = mStore.get<ESM::StartScript>().begin();
iter != mStore.get<ESM::StartScript>().end(); ++iter)
{
scripts.push_back(iter->mId);
}
// add scripts
for (auto iter(scripts.begin()); iter != scripts.end(); ++iter)
{
try
{
addScript(*iter);
}
catch (const std::exception& exception)
{
Log(Debug::Error) << "Failed to add start script " << *iter << " because an exception has "
<< "been thrown: " << exception.what();
}
}
}
int GlobalScripts::countSavedGameRecords() const
{
return mScripts.size();
}
void GlobalScripts::write(ESM::ESMWriter& writer, Loading::Listener& progress) const
{
for (const auto& [id, desc] : mScripts)
{
ESM::GlobalScript script = std::visit(ScriptCreatingVisitor{}, desc->mTarget);
script.mId = id;
desc->mLocals.write(script.mLocals, id);
script.mRunning = desc->mRunning ? 1 : 0;
writer.startRecord(ESM::REC_GSCR);
script.save(writer);
writer.endRecord(ESM::REC_GSCR);
}
}
bool GlobalScripts::readRecord(ESM::ESMReader& reader, uint32_t type, const std::map<int, int>& contentFileMap)
{
if (type == ESM::REC_GSCR)
{
ESM::GlobalScript script;
script.load(reader);
if (script.mTargetRef.hasContentFile())
{
auto iter = contentFileMap.find(script.mTargetRef.mContentFile);
if (iter != contentFileMap.end())
script.mTargetRef.mContentFile = iter->second;
}
auto iter = mScripts.find(script.mId);
if (iter == mScripts.end())
{
if (const ESM::Script* scriptRecord = mStore.get<ESM::Script>().search(script.mId))
{
try
{
auto desc = std::make_shared<GlobalScriptDesc>();
if (!script.mTargetId.empty())
{
desc->mTarget = std::make_pair(script.mTargetRef, script.mTargetId);
}
desc->mLocals.configure(*scriptRecord);
iter = mScripts.insert(std::make_pair(script.mId, desc)).first;
}
catch (const std::exception& exception)
{
Log(Debug::Error) << "Failed to add start script " << script.mId
<< " because an exception has been thrown: " << exception.what();
return true;
}
}
else // script does not exist anymore
return true;
}
iter->second->mRunning = script.mRunning != 0;
iter->second->mLocals.read(script.mLocals, script.mId);
return true;
}
return false;
}
Locals& GlobalScripts::getLocals(const ESM::RefId& name)
{
auto iter = mScripts.find(name);
if (iter == mScripts.end())
{
const ESM::Script* script = mStore.get<ESM::Script>().find(name);
auto desc = std::make_shared<GlobalScriptDesc>();
desc->mLocals.configure(*script);
iter = mScripts.emplace(name, desc).first;
}
return iter->second->mLocals;
}
const Locals* GlobalScripts::getLocalsIfPresent(const ESM::RefId& name) const
{
auto iter = mScripts.find(name);
if (iter == mScripts.end())
return nullptr;
return &iter->second->mLocals;
}
void GlobalScripts::updatePtrs(const MWWorld::Ptr& base, const MWWorld::Ptr& updated)
{
MatchPtrVisitor visitor(base);
for (const auto& script : mScripts)
{
if (std::visit(visitor, script.second->mTarget))
script.second->mTarget = updated;
}
}
}