2013-02-03 13:27:27 +00:00
|
|
|
#include "locals.hpp"
|
2020-07-29 18:43:56 +02:00
|
|
|
#include "globalscripts.hpp"
|
2013-02-03 13:27:27 +00:00
|
|
|
|
2013-04-04 12:27:57 +02:00
|
|
|
#include <components/compiler/locals.hpp>
|
2018-08-14 23:05:43 +04:00
|
|
|
#include <components/debug/debuglog.hpp>
|
2022-01-22 15:58:41 +01:00
|
|
|
#include <components/esm3/loadscpt.hpp>
|
|
|
|
#include <components/esm3/locals.hpp>
|
2013-04-04 12:27:57 +02:00
|
|
|
#include <components/esm3/variant.hpp>
|
|
|
|
|
2013-02-03 13:27:27 +00:00
|
|
|
#include "../mwbase/environment.hpp"
|
|
|
|
#include "../mwbase/scriptmanager.hpp"
|
2015-09-15 13:58:07 +02:00
|
|
|
#include "../mwbase/world.hpp"
|
|
|
|
|
|
|
|
#include "../mwworld/esmstore.hpp"
|
2013-02-03 13:27:27 +00:00
|
|
|
|
|
|
|
namespace MWScript
|
|
|
|
{
|
2022-08-11 22:51:55 +02:00
|
|
|
void Locals::ensure(std::string_view scriptName)
|
2013-02-03 13:27:27 +00:00
|
|
|
{
|
2015-09-15 13:58:07 +02:00
|
|
|
if (!mInitialised)
|
|
|
|
{
|
|
|
|
const ESM::Script* script
|
|
|
|
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find(scriptName);
|
|
|
|
|
|
|
|
configure(*script);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Locals::Locals()
|
|
|
|
: mInitialised(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Locals::configure(const ESM::Script& script)
|
|
|
|
{
|
|
|
|
if (mInitialised)
|
|
|
|
return false;
|
|
|
|
|
2020-07-29 18:43:56 +02:00
|
|
|
const Locals* global
|
|
|
|
= MWBase::Environment::get().getScriptManager()->getGlobalScripts().getLocalsIfPresent(script.mId);
|
|
|
|
if (global)
|
|
|
|
{
|
|
|
|
mShorts = global->mShorts;
|
|
|
|
mLongs = global->mLongs;
|
|
|
|
mFloats = global->mFloats;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script.mId);
|
|
|
|
|
|
|
|
mShorts.clear();
|
|
|
|
mShorts.resize(locals.get('s').size(), 0);
|
|
|
|
mLongs.clear();
|
|
|
|
mLongs.resize(locals.get('l').size(), 0);
|
|
|
|
mFloats.clear();
|
|
|
|
mFloats.resize(locals.get('f').size(), 0);
|
|
|
|
}
|
2015-09-15 13:58:07 +02:00
|
|
|
|
|
|
|
mInitialised = true;
|
|
|
|
return true;
|
2013-02-03 13:27:27 +00:00
|
|
|
}
|
2013-03-31 13:13:46 +02:00
|
|
|
|
2014-06-26 01:21:15 +02:00
|
|
|
bool Locals::isEmpty() const
|
|
|
|
{
|
|
|
|
return (mShorts.empty() && mLongs.empty() && mFloats.empty());
|
|
|
|
}
|
|
|
|
|
2022-08-11 22:51:55 +02:00
|
|
|
bool Locals::hasVar(std::string_view script, std::string_view var)
|
2015-01-31 02:08:37 +01:00
|
|
|
{
|
2021-07-03 13:02:17 +02:00
|
|
|
ensure(script);
|
2015-09-15 13:58:07 +02:00
|
|
|
|
2021-07-03 13:02:17 +02:00
|
|
|
const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
|
|
|
|
int index = locals.getIndex(var);
|
|
|
|
return (index != -1);
|
2015-01-31 02:08:37 +01:00
|
|
|
}
|
|
|
|
|
2022-08-11 22:51:55 +02:00
|
|
|
int Locals::getIntVar(std::string_view script, std::string_view var)
|
2013-03-31 13:13:46 +02:00
|
|
|
{
|
2015-09-15 13:58:07 +02:00
|
|
|
ensure(script);
|
|
|
|
|
2014-07-25 09:26:30 +02:00
|
|
|
const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
|
2013-03-31 13:13:46 +02:00
|
|
|
int index = locals.getIndex(var);
|
|
|
|
char type = locals.getType(var);
|
|
|
|
if (index != -1)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case 's':
|
|
|
|
return mShorts.at(index);
|
|
|
|
|
|
|
|
case 'l':
|
|
|
|
return mLongs.at(index);
|
|
|
|
|
|
|
|
case 'f':
|
2015-03-08 13:07:29 +13:00
|
|
|
return static_cast<int>(mFloats.at(index));
|
2013-03-31 13:13:46 +02:00
|
|
|
default:
|
|
|
|
return 0;
|
2016-02-27 13:40:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-11 22:51:55 +02:00
|
|
|
float Locals::getFloatVar(std::string_view script, std::string_view var)
|
2016-02-27 13:40:53 +01:00
|
|
|
{
|
|
|
|
ensure(script);
|
|
|
|
|
|
|
|
const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
|
|
|
|
int index = locals.getIndex(var);
|
|
|
|
char type = locals.getType(var);
|
|
|
|
if (index != -1)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case 's':
|
|
|
|
return mShorts.at(index);
|
|
|
|
|
|
|
|
case 'l':
|
|
|
|
return mLongs.at(index);
|
|
|
|
|
|
|
|
case 'f':
|
|
|
|
return mFloats.at(index);
|
|
|
|
default:
|
|
|
|
return 0;
|
2013-03-31 13:13:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2013-04-04 12:27:57 +02:00
|
|
|
|
2022-08-11 22:51:55 +02:00
|
|
|
bool Locals::setVarByInt(std::string_view script, std::string_view var, int val)
|
2013-04-04 12:27:57 +02:00
|
|
|
{
|
2015-09-15 13:58:07 +02:00
|
|
|
ensure(script);
|
|
|
|
|
2014-07-25 09:26:30 +02:00
|
|
|
const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
|
2013-02-03 13:27:27 +00:00
|
|
|
int index = locals.getIndex(var);
|
|
|
|
char type = locals.getType(var);
|
|
|
|
if (index != -1)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case 's':
|
|
|
|
mShorts.at(index) = val;
|
|
|
|
break;
|
2013-04-04 12:27:57 +02:00
|
|
|
|
2013-02-03 13:27:27 +00:00
|
|
|
case 'l':
|
|
|
|
mLongs.at(index) = val;
|
|
|
|
break;
|
2013-04-04 12:27:57 +02:00
|
|
|
|
2013-02-03 13:27:27 +00:00
|
|
|
case 'f':
|
2015-03-08 13:07:29 +13:00
|
|
|
mFloats.at(index) = static_cast<float>(val);
|
|
|
|
break;
|
2013-02-03 13:27:27 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2013-12-15 16:16:50 +01:00
|
|
|
|
2022-08-11 22:51:55 +02:00
|
|
|
bool Locals::write(ESM::Locals& locals, std::string_view script) const
|
2013-12-15 16:16:50 +01:00
|
|
|
{
|
2015-09-15 13:58:07 +02:00
|
|
|
if (!mInitialised)
|
|
|
|
return false;
|
|
|
|
|
2021-07-03 13:02:17 +02:00
|
|
|
const Compiler::Locals& declarations = MWBase::Environment::get().getScriptManager()->getLocals(script);
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; ++i)
|
2013-12-15 16:16:50 +01:00
|
|
|
{
|
2021-07-03 13:02:17 +02:00
|
|
|
char type = 0;
|
2013-12-15 16:16:50 +01:00
|
|
|
|
2021-07-03 13:02:17 +02:00
|
|
|
switch (i)
|
2013-12-15 16:16:50 +01:00
|
|
|
{
|
2021-07-03 13:02:17 +02:00
|
|
|
case 0:
|
|
|
|
type = 's';
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
type = 'l';
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
type = 'f';
|
|
|
|
break;
|
|
|
|
}
|
2013-12-15 16:16:50 +01:00
|
|
|
|
2021-07-03 13:02:17 +02:00
|
|
|
const std::vector<std::string>& names = declarations.get(type);
|
2013-12-15 16:16:50 +01:00
|
|
|
|
2021-07-03 13:02:17 +02:00
|
|
|
for (int i2 = 0; i2 < static_cast<int>(names.size()); ++i2)
|
|
|
|
{
|
|
|
|
ESM::Variant value;
|
2014-06-29 14:45:52 +02:00
|
|
|
|
2021-07-03 13:02:17 +02:00
|
|
|
switch (i)
|
2014-06-29 14:45:52 +02:00
|
|
|
{
|
2021-07-03 13:02:17 +02:00
|
|
|
case 0:
|
|
|
|
value.setType(ESM::VT_Int);
|
|
|
|
value.setInteger(mShorts.at(i2));
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
value.setType(ESM::VT_Int);
|
|
|
|
value.setInteger(mLongs.at(i2));
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
value.setType(ESM::VT_Float);
|
|
|
|
value.setFloat(mFloats.at(i2));
|
|
|
|
break;
|
2014-06-29 14:45:52 +02:00
|
|
|
}
|
2021-07-03 13:02:17 +02:00
|
|
|
|
|
|
|
locals.mVariables.emplace_back(names[i2], value);
|
2013-12-15 16:16:50 +01:00
|
|
|
}
|
|
|
|
}
|
2015-09-15 13:58:07 +02:00
|
|
|
|
|
|
|
return true;
|
2013-12-15 16:16:50 +01:00
|
|
|
}
|
|
|
|
|
2022-08-11 22:51:55 +02:00
|
|
|
void Locals::read(const ESM::Locals& locals, std::string_view script)
|
2013-12-15 16:16:50 +01:00
|
|
|
{
|
2015-09-15 13:58:07 +02:00
|
|
|
ensure(script);
|
|
|
|
|
2021-07-03 13:02:17 +02:00
|
|
|
const Compiler::Locals& declarations = MWBase::Environment::get().getScriptManager()->getLocals(script);
|
2013-12-15 16:16:50 +01:00
|
|
|
|
2021-07-03 13:02:17 +02:00
|
|
|
int index = 0, numshorts = 0, numlongs = 0;
|
|
|
|
for (unsigned int v = 0; v < locals.mVariables.size(); ++v)
|
|
|
|
{
|
|
|
|
ESM::VarType type = locals.mVariables[v].second.getType();
|
|
|
|
if (type == ESM::VT_Short)
|
|
|
|
++numshorts;
|
|
|
|
else if (type == ESM::VT_Int)
|
|
|
|
++numlongs;
|
|
|
|
}
|
2013-12-15 16:16:50 +01:00
|
|
|
|
2021-07-03 13:02:17 +02:00
|
|
|
for (std::vector<std::pair<std::string, ESM::Variant>>::const_iterator iter = locals.mVariables.begin();
|
|
|
|
iter != locals.mVariables.end(); ++iter, ++index)
|
|
|
|
{
|
|
|
|
if (iter->first.empty())
|
2015-01-24 16:15:52 +01:00
|
|
|
{
|
2021-07-03 13:02:17 +02:00
|
|
|
// no variable names available (this will happen for legacy, i.e. ESS-imported savegames only)
|
|
|
|
try
|
2014-06-29 14:45:52 +02:00
|
|
|
{
|
2021-07-03 13:02:17 +02:00
|
|
|
if (index >= numshorts + numlongs)
|
|
|
|
mFloats.at(index - (numshorts + numlongs)) = iter->second.getFloat();
|
|
|
|
else if (index >= numshorts)
|
|
|
|
mLongs.at(index - numshorts) = iter->second.getInteger();
|
|
|
|
else
|
|
|
|
mShorts.at(index) = iter->second.getInteger();
|
2014-06-29 14:45:52 +02:00
|
|
|
}
|
2021-07-03 13:02:17 +02:00
|
|
|
catch (std::exception& e)
|
2014-06-29 14:45:52 +02:00
|
|
|
{
|
2021-07-03 13:02:17 +02:00
|
|
|
Log(Debug::Error) << "Failed to read local variable state for script '" << script
|
|
|
|
<< "' (legacy format): " << e.what() << "\nNum shorts: " << numshorts << " / "
|
|
|
|
<< mShorts.size() << " Num longs: " << numlongs << " / " << mLongs.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char type = declarations.getType(iter->first);
|
|
|
|
int index2 = declarations.getIndex(iter->first);
|
2015-01-24 16:15:52 +01:00
|
|
|
|
2021-07-03 13:02:17 +02:00
|
|
|
// silently ignore locals that don't exist anymore
|
|
|
|
if (type == ' ' || index2 == -1)
|
|
|
|
continue;
|
2018-06-25 11:21:00 +04:00
|
|
|
|
2021-07-03 13:02:17 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
switch (type)
|
2015-01-24 16:15:52 +01:00
|
|
|
{
|
2021-07-03 13:02:17 +02:00
|
|
|
case 's':
|
|
|
|
mShorts.at(index2) = iter->second.getInteger();
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
mLongs.at(index2) = iter->second.getInteger();
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
mFloats.at(index2) = iter->second.getFloat();
|
|
|
|
break;
|
2015-01-24 16:15:52 +01:00
|
|
|
}
|
2013-12-15 16:16:50 +01:00
|
|
|
}
|
2021-07-03 13:02:17 +02:00
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
// ignore type changes
|
|
|
|
/// \todo write to log
|
|
|
|
}
|
2013-12-15 16:16:50 +01:00
|
|
|
}
|
2014-06-29 14:45:52 +02:00
|
|
|
}
|
2013-12-15 16:16:50 +01:00
|
|
|
}
|
2013-02-03 13:27:27 +00:00
|
|
|
}
|