make sure local variables are loaded when trying to access them from outside of a script (Fixes #2659)

This commit is contained in:
Marc Zinnschlag 2015-09-15 13:58:07 +02:00
parent ceada145ab
commit 2a981a5272
6 changed files with 75 additions and 32 deletions

View file

@ -198,13 +198,12 @@ namespace MWScript
if (iter==mScripts.end()) if (iter==mScripts.end())
{ {
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name)) const ESM::Script *script = mStore.get<ESM::Script>().find (name);
{
GlobalScriptDesc desc;
desc.mLocals.configure (*script);
iter = mScripts.insert (std::make_pair (name, desc)).first; GlobalScriptDesc desc;
} desc.mLocals.configure (*script);
iter = mScripts.insert (std::make_pair (name2, desc)).first;
} }
return iter->second.mLocals; return iter->second.mLocals;

View file

@ -9,13 +9,32 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/scriptmanager.hpp" #include "../mwbase/scriptmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/esmstore.hpp"
#include <iostream> #include <iostream>
namespace MWScript namespace MWScript
{ {
void Locals::configure (const ESM::Script& script) void Locals::ensure (const std::string& scriptName)
{ {
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;
const Compiler::Locals& locals = const Compiler::Locals& locals =
MWBase::Environment::get().getScriptManager()->getLocals (script.mId); MWBase::Environment::get().getScriptManager()->getLocals (script.mId);
@ -25,6 +44,9 @@ namespace MWScript
mLongs.resize (locals.get ('l').size(), 0); mLongs.resize (locals.get ('l').size(), 0);
mFloats.clear(); mFloats.clear();
mFloats.resize (locals.get ('f').size(), 0); mFloats.resize (locals.get ('f').size(), 0);
mInitialised = true;
return true;
} }
bool Locals::isEmpty() const bool Locals::isEmpty() const
@ -36,6 +58,8 @@ namespace MWScript
{ {
try try
{ {
ensure (script);
const Compiler::Locals& locals = const Compiler::Locals& locals =
MWBase::Environment::get().getScriptManager()->getLocals(script); MWBase::Environment::get().getScriptManager()->getLocals(script);
int index = locals.getIndex(var); int index = locals.getIndex(var);
@ -49,6 +73,8 @@ namespace MWScript
int Locals::getIntVar(const std::string &script, const std::string &var) int Locals::getIntVar(const std::string &script, const std::string &var)
{ {
ensure (script);
const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
int index = locals.getIndex(var); int index = locals.getIndex(var);
char type = locals.getType(var); char type = locals.getType(var);
@ -73,6 +99,8 @@ namespace MWScript
bool Locals::setVarByInt(const std::string& script, const std::string& var, int val) bool Locals::setVarByInt(const std::string& script, const std::string& var, int val)
{ {
ensure (script);
const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
int index = locals.getIndex(var); int index = locals.getIndex(var);
char type = locals.getType(var); char type = locals.getType(var);
@ -94,8 +122,11 @@ namespace MWScript
return false; return false;
} }
void Locals::write (ESM::Locals& locals, const std::string& script) const bool Locals::write (ESM::Locals& locals, const std::string& script) const
{ {
if (!mInitialised)
return false;
try try
{ {
const Compiler::Locals& declarations = const Compiler::Locals& declarations =
@ -132,10 +163,14 @@ namespace MWScript
catch (const Compiler::SourceException&) catch (const Compiler::SourceException&)
{ {
} }
return true;
} }
void Locals::read (const ESM::Locals& locals, const std::string& script) void Locals::read (const ESM::Locals& locals, const std::string& script)
{ {
ensure (script);
try try
{ {
const Compiler::Locals& declarations = const Compiler::Locals& declarations =

View file

@ -15,30 +15,50 @@ namespace MWScript
{ {
class Locals class Locals
{ {
bool mInitialised;
void ensure (const std::string& scriptName);
public: public:
std::vector<Interpreter::Type_Short> mShorts; std::vector<Interpreter::Type_Short> mShorts;
std::vector<Interpreter::Type_Integer> mLongs; std::vector<Interpreter::Type_Integer> mLongs;
std::vector<Interpreter::Type_Float> mFloats; std::vector<Interpreter::Type_Float> mFloats;
Locals();
/// Are there any locals? /// Are there any locals?
///
/// \note Will return false, if locals have not been configured yet.
bool isEmpty() const; bool isEmpty() const;
void configure (const ESM::Script& script); /// \return Did the state of *this change from uninitialised to initialised?
bool configure (const ESM::Script& script);
/// @note var needs to be in lowercase /// @note var needs to be in lowercase
///
/// \note Locals will be automatically configured first, if necessary
bool setVarByInt(const std::string& script, const std::string& var, int val); bool setVarByInt(const std::string& script, const std::string& var, int val);
/// \note Locals will be automatically configured first, if necessary
//
// \note If it can not be determined if the variable exists, the error will be
// ignored and false will be returned.
bool hasVar(const std::string& script, const std::string& var); bool hasVar(const std::string& script, const std::string& var);
/// if var does not exist, returns 0 /// if var does not exist, returns 0
/// @note var needs to be in lowercase /// @note var needs to be in lowercase
///
/// \note Locals will be automatically configured first, if necessary
int getIntVar (const std::string& script, const std::string& var); int getIntVar (const std::string& script, const std::string& var);
void write (ESM::Locals& locals, const std::string& script) const; /// \note If locals have not been configured yet, no data is written.
///
/// \return Locals written?
bool write (ESM::Locals& locals, const std::string& script) const;
/// \note Locals will be automatically configured first, if necessary
void read (const ESM::Locals& locals, const std::string& script); void read (const ESM::Locals& locals, const std::string& script);
}; };
} }
#endif #endif

View file

@ -170,7 +170,7 @@ namespace MWScript
return iter->second; return iter->second;
} }
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name2)) if (const ESM::Script *script = mStore.get<ESM::Script>().search (name2))
{ {
if (mVerbose) if (mVerbose)
std::cout std::cout

View file

@ -14,7 +14,6 @@ namespace MWWorld
{ {
mBaseNode = refData.mBaseNode; mBaseNode = refData.mBaseNode;
mLocals = refData.mLocals; mLocals = refData.mLocals;
mHasLocals = refData.mHasLocals;
mEnabled = refData.mEnabled; mEnabled = refData.mEnabled;
mCount = refData.mCount; mCount = refData.mCount;
mPosition = refData.mPosition; mPosition = refData.mPosition;
@ -34,7 +33,7 @@ namespace MWWorld
} }
RefData::RefData() RefData::RefData()
: mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) : mBaseNode(0), mDeleted(false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false)
{ {
for (int i=0; i<3; ++i) for (int i=0; i<3; ++i)
{ {
@ -45,7 +44,7 @@ namespace MWWorld
} }
RefData::RefData (const ESM::CellRef& cellRef) RefData::RefData (const ESM::CellRef& cellRef)
: mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), : mBaseNode(0), mDeleted(false), mEnabled (true),
mCount (1), mPosition (cellRef.mPos), mCount (1), mPosition (cellRef.mPos),
mCustomData (0), mCustomData (0),
mChanged(false) // Loading from ESM/ESP files -> assume unchanged mChanged(false) // Loading from ESM/ESP files -> assume unchanged
@ -56,13 +55,13 @@ namespace MWWorld
} }
RefData::RefData (const ESM::ObjectState& objectState) RefData::RefData (const ESM::ObjectState& objectState)
: mBaseNode(0), mDeleted(false), mHasLocals (false), : mBaseNode(0), mDeleted(false),
mEnabled (objectState.mEnabled != 0), mEnabled (objectState.mEnabled != 0),
mCount (objectState.mCount), mCount (objectState.mCount),
mPosition (objectState.mPosition), mPosition (objectState.mPosition),
mCustomData (0), mCustomData (0),
mChanged(true) // Loading from a savegame -> assume changed mChanged(true) // Loading from a savegame -> assume changed
{ {
for (int i=0; i<3; ++i) for (int i=0; i<3; ++i)
mLocalRotation.rot[i] = objectState.mLocalRotation[i]; mLocalRotation.rot[i] = objectState.mLocalRotation[i];
} }
@ -83,10 +82,7 @@ namespace MWWorld
void RefData::write (ESM::ObjectState& objectState, const std::string& scriptId) const void RefData::write (ESM::ObjectState& objectState, const std::string& scriptId) const
{ {
objectState.mHasLocals = mHasLocals; objectState.mHasLocals = mLocals.write (objectState.mLocals, scriptId);
if (mHasLocals)
mLocals.write (objectState.mLocals, scriptId);
objectState.mEnabled = mEnabled; objectState.mEnabled = mEnabled;
objectState.mCount = mCount; objectState.mCount = mCount;
@ -139,13 +135,8 @@ namespace MWWorld
void RefData::setLocals (const ESM::Script& script) void RefData::setLocals (const ESM::Script& script)
{ {
if (!mHasLocals) if (mLocals.configure (script) && !mLocals.isEmpty())
{ mChanged = true;
mLocals.configure (script);
mHasLocals = true;
if (!mLocals.isEmpty())
mChanged = true;
}
} }
void RefData::setCount (int count) void RefData::setCount (int count)

View file

@ -31,11 +31,9 @@ namespace MWWorld
{ {
osg::PositionAttitudeTransform* mBaseNode; osg::PositionAttitudeTransform* mBaseNode;
MWScript::Locals mLocals; // if we find the overhead of heaving a locals MWScript::Locals mLocals;
// object in the refdata of refs without a script,
// we can make this a pointer later.
bool mDeleted; // separate delete flag used for deletion by a content file bool mDeleted; // separate delete flag used for deletion by a content file
bool mHasLocals;
bool mEnabled; bool mEnabled;
int mCount; // 0: deleted int mCount; // 0: deleted