You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/apps/opencs/model/world/scriptcontext.cpp

145 lines
3.6 KiB
C++

#include "scriptcontext.hpp"
#include <algorithm>
#include <sstream>
#include <type_traits>
#include <apps/opencs/model/world/columns.hpp>
#include <apps/opencs/model/world/idcollection.hpp>
#include <apps/opencs/model/world/record.hpp>
#include <apps/opencs/model/world/refidcollection.hpp>
#include <components/compiler/nullerrorhandler.hpp>
#include <components/compiler/quickfileparser.hpp>
#include <components/compiler/scanner.hpp>
#include <components/esm3/loadglob.hpp>
#include <components/esm3/loadscpt.hpp>
#include <components/esm3/variant.hpp>
#include <components/misc/strings/lower.hpp>
#include "data.hpp"
CSMWorld::ScriptContext::ScriptContext(const Data& data)
: mData(data)
, mIdsUpdated(false)
{
}
bool CSMWorld::ScriptContext::canDeclareLocals() const
{
return true;
}
char CSMWorld::ScriptContext::getGlobalType(const std::string& name) const
{
const int index = mData.getGlobals().searchId(ESM::RefId::stringRefId(name));
if (index != -1)
{
switch (mData.getGlobals().getRecord(index).get().mValue.getType())
{
case ESM::VT_Short:
return 's';
case ESM::VT_Long:
return 'l';
case ESM::VT_Float:
return 'f';
default:
return ' ';
}
}
return ' ';
}
std::pair<char, bool> CSMWorld::ScriptContext::getMemberType(const std::string& name, const ESM::RefId& id) const
{
ESM::RefId id2 = id;
int index = mData.getScripts().searchId(id2);
bool reference = false;
if (index == -1)
{
// ID is not a script ID. Search for a matching referenceable instead.
index = mData.getReferenceables().searchId(id2);
if (index != -1)
{
// Referenceable found.
int columnIndex = mData.getReferenceables().findColumnIndex(Columns::ColumnId_Script);
id2 = ESM::RefId::stringRefId(
mData.getReferenceables().getData(index, columnIndex).toString().toUtf8().constData());
if (!id2.empty())
{
// Referenceable has a script -> use it.
index = mData.getScripts().searchId(id2);
reference = true;
}
}
}
if (index == -1)
return std::make_pair(' ', false);
auto iter = mLocals.find(id2);
if (iter == mLocals.end())
{
Compiler::Locals locals;
Compiler::NullErrorHandler errorHandler;
std::istringstream stream(mData.getScripts().getRecord(index).get().mScriptText);
Compiler::QuickFileParser parser(errorHandler, *this, locals);
Compiler::Scanner scanner(errorHandler, stream, getExtensions());
scanner.scan(parser);
iter = mLocals.emplace(id2, std::move(locals)).first;
}
return std::make_pair(iter->second.getType(Misc::StringUtils::lowerCase(name)), reference);
}
bool CSMWorld::ScriptContext::isId(const ESM::RefId& name) const
{
if (!mIdsUpdated)
{
mIds = mData.getIds();
std::sort(mIds.begin(), mIds.end());
mIdsUpdated = true;
}
return std::binary_search(mIds.begin(), mIds.end(), name);
}
void CSMWorld::ScriptContext::invalidateIds()
{
mIdsUpdated = false;
}
void CSMWorld::ScriptContext::clear()
{
mIds.clear();
mIdsUpdated = false;
mLocals.clear();
}
bool CSMWorld::ScriptContext::clearLocals(const std::string& script)
{
const auto iter = mLocals.find(script);
if (iter != mLocals.end())
{
mLocals.erase(iter);
mIdsUpdated = false;
return true;
}
return false;
}