1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-06 18:40:23 +00:00
OpenMW/apps/openmw/mwscript/scriptmanagerimp.cpp
florent.teppe dc21df97c8 Fixed issue with getSummonedCreature( that returned a reference to a non const static value
Fix compile, and apply review comment

Fixed greater vs more typo.

getCellname is back to a string view.

Because in most cases was used as a strong not a refId.
and there was a fundamental issue with region names used as a cellname
2022-12-27 19:16:22 +01:00

226 lines
6.5 KiB
C++

#include "scriptmanagerimp.hpp"
#include <algorithm>
#include <cassert>
#include <exception>
#include <sstream>
#include <components/debug/debuglog.hpp>
#include <components/esm/refid.hpp>
#include <components/esm3/loadscpt.hpp>
#include <components/misc/strings/lower.hpp>
#include <components/compiler/context.hpp>
#include <components/compiler/exception.hpp>
#include <components/compiler/quickfileparser.hpp>
#include <components/compiler/scanner.hpp>
#include "../mwworld/esmstore.hpp"
#include "extensions.hpp"
#include "interpretercontext.hpp"
namespace MWScript
{
ScriptManager::ScriptManager(const MWWorld::ESMStore& store, Compiler::Context& compilerContext, int warningsMode,
const std::vector<ESM::RefId>& scriptBlacklist)
: mErrorHandler()
, mStore(store)
, mCompilerContext(compilerContext)
, mParser(mErrorHandler, mCompilerContext)
, mOpcodesInstalled(false)
, mGlobalScripts(store)
{
mErrorHandler.setWarningsMode(warningsMode);
mScriptBlacklist.resize(scriptBlacklist.size());
std::sort(mScriptBlacklist.begin(), mScriptBlacklist.end());
}
bool ScriptManager::compile(const ESM::RefId& name)
{
mParser.reset();
mErrorHandler.reset();
if (const ESM::Script* script = mStore.get<ESM::Script>().find(name))
{
mErrorHandler.setContext(script->mId.getRefIdString());
bool Success = true;
try
{
std::istringstream input(script->mScriptText);
Compiler::Scanner scanner(mErrorHandler, input, mCompilerContext.getExtensions());
scanner.scan(mParser);
if (!mErrorHandler.isGood())
Success = false;
}
catch (const Compiler::SourceException&)
{
// error has already been reported via error handler
Success = false;
}
catch (const std::exception& error)
{
Log(Debug::Error) << "Error: An exception has been thrown: " << error.what();
Success = false;
}
if (!Success)
{
Log(Debug::Error) << "Error: script compiling failed: " << name;
}
if (Success)
{
std::vector<Interpreter::Type_Code> code;
mParser.getCode(code);
mScripts.emplace(name, CompiledScript(code, mParser.getLocals()));
return true;
}
}
return false;
}
bool ScriptManager::run(const ESM::RefId& name, Interpreter::Context& interpreterContext)
{
// compile script
auto iter = mScripts.find(name);
if (iter == mScripts.end())
{
if (!compile(name))
{
// failed -> ignore script from now on.
std::vector<Interpreter::Type_Code> empty;
mScripts.emplace(name, CompiledScript(empty, Compiler::Locals()));
return false;
}
iter = mScripts.find(name);
assert(iter != mScripts.end());
}
// execute script
const auto& target = interpreterContext.getTarget();
if (!iter->second.mByteCode.empty() && iter->second.mInactive.find(target) == iter->second.mInactive.end())
try
{
if (!mOpcodesInstalled)
{
installOpcodes(mInterpreter);
mOpcodesInstalled = true;
}
mInterpreter.run(&iter->second.mByteCode[0], iter->second.mByteCode.size(), interpreterContext);
return true;
}
catch (const MissingImplicitRefError& e)
{
Log(Debug::Error) << "Execution of script " << name << " failed: " << e.what();
}
catch (const std::exception& e)
{
Log(Debug::Error) << "Execution of script " << name << " failed: " << e.what();
iter->second.mInactive.insert(target); // don't execute again.
}
return false;
}
void ScriptManager::clear()
{
for (auto& script : mScripts)
{
script.second.mInactive.clear();
}
mGlobalScripts.clear();
}
std::pair<int, int> ScriptManager::compileAll()
{
int count = 0;
int success = 0;
for (auto& script : mStore.get<ESM::Script>())
{
if (!std::binary_search(mScriptBlacklist.begin(), mScriptBlacklist.end(), script.mId))
{
++count;
if (compile(script.mId))
++success;
}
}
return std::make_pair(count, success);
}
const Compiler::Locals& ScriptManager::getLocals(const ESM::RefId& name)
{
{
auto iter = mScripts.find(name);
if (iter != mScripts.end())
return iter->second.mLocals;
}
{
auto iter = mOtherLocals.find(name);
if (iter != mOtherLocals.end())
return iter->second;
}
if (const ESM::Script* script = mStore.get<ESM::Script>().search(name))
{
Compiler::Locals locals;
const Compiler::ContextOverride override(mErrorHandler, name.getRefIdString() + "[local variables]");
std::istringstream stream(script->mScriptText);
Compiler::QuickFileParser parser(mErrorHandler, mCompilerContext, locals);
Compiler::Scanner scanner(mErrorHandler, stream, mCompilerContext.getExtensions());
try
{
scanner.scan(parser);
}
catch (const Compiler::SourceException&)
{
// error has already been reported via error handler
locals.clear();
}
catch (const std::exception& error)
{
Log(Debug::Error) << "Error: An exception has been thrown: " << error.what();
locals.clear();
}
auto iter = mOtherLocals.emplace(name, locals).first;
return iter->second;
}
throw std::logic_error("script " + name.getRefIdString() + " does not exist");
}
GlobalScripts& ScriptManager::getGlobalScripts()
{
return mGlobalScripts;
}
const Compiler::Extensions& ScriptManager::getExtensions() const
{
return *mCompilerContext.getExtensions();
}
}