ESSImport: convert script local variables

Had to add special reading code to openmw, because the variable names are not stored.
openmw-35
scrawl 9 years ago
parent 7d76213374
commit b1bd236345

@ -23,6 +23,7 @@ set(ESSIMPORTER_FILES
convertinventory.cpp
convertcrec.cpp
convertcntc.cpp
convertscri.cpp
)
add_executable(openmw-essimporter

@ -9,6 +9,7 @@
#include "convertcrec.hpp"
#include "convertcntc.hpp"
#include "convertscri.hpp"
namespace
{
@ -29,6 +30,8 @@ namespace
objstate.mRef.mRefNum = cellref.mRefNum;
if (cellref.mDeleted)
objstate.mCount = 0;
convertSCRI(cellref.mSCRI, objstate.mLocals);
objstate.mHasLocals = !objstate.mLocals.mVariables.empty();
}
bool isIndexedRefId(const std::string& indexedRefId)

@ -0,0 +1,32 @@
#include "convertscri.hpp"
#include <iostream>
namespace
{
template <typename T, ESM::VarType VariantType>
void storeVariables(const std::vector<T>& variables, ESM::Locals& locals, const std::string& scriptname)
{
for (typename std::vector<T>::const_iterator it = variables.begin(); it != variables.end(); ++it)
{
ESM::Variant val(*it);
val.setType(VariantType);
locals.mVariables.push_back(std::make_pair(std::string(), val));
}
}
}
namespace ESSImport
{
void convertSCRI(const SCRI &scri, ESM::Locals &locals)
{
// order *is* important, as we do not have variable names available in this format
storeVariables<short, ESM::VT_Short> (scri.mShorts, locals, scri.mScript);
storeVariables<int, ESM::VT_Int> (scri.mLongs, locals, scri.mScript);
storeVariables<float, ESM::VT_Float> (scri.mFloats, locals, scri.mScript);
}
}

@ -0,0 +1,16 @@
#ifndef OPENMW_ESSIMPORT_CONVERTSCRI_H
#define OPENMW_ESSIMPORT_CONVERTSCRI_H
#include "importscri.hpp"
#include <components/esm/locals.hpp>
namespace ESSImport
{
/// Convert script variable assignments
void convertSCRI (const SCRI& scri, ESM::Locals& locals);
}
#endif

@ -237,6 +237,12 @@ namespace ESSImport
converters[recJOUR ] = boost::shared_ptr<Converter>(new ConvertJOUR());
converters[ESM::REC_SCPT] = boost::shared_ptr<Converter>(new ConvertSCPT());
// TODO:
// - REGN (weather in certain regions?)
// - VFXM
// - SPLM (active spell effects)
// - PROJ (magic projectiles in air)
std::set<unsigned int> unknownRecords;
for (std::map<unsigned int, boost::shared_ptr<Converter> >::const_iterator it = converters.begin();

@ -10,6 +10,8 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/scriptmanager.hpp"
#include <iostream>
namespace MWScript
{
void Locals::configure (const ESM::Script& script)
@ -124,27 +126,60 @@ namespace MWScript
const Compiler::Locals& declarations =
MWBase::Environment::get().getScriptManager()->getLocals(script);
for (std::vector<std::pair<std::string, ESM::Variant> >::const_iterator iter
= locals.mVariables.begin(); iter!=locals.mVariables.end(); ++iter)
int index = 0, numshorts = 0, numlongs = 0;
for (unsigned int v=0; v<locals.mVariables.size();++v)
{
char type = declarations.getType (iter->first);
char index = declarations.getIndex (iter->first);
ESM::VarType type = locals.mVariables[v].second.getType();
if (type == ESM::VT_Short)
++numshorts;
else if (type == ESM::VT_Int)
++numlongs;
}
try
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())
{
switch (type)
// no variable names available (this will happen for legacy, i.e. ESS-imported savegames only)
try
{
case 's': mShorts.at (index) = iter->second.getInteger(); break;
case 'l': mLongs.at (index) = iter->second.getInteger(); break;
case 'f': mFloats.at (index) = iter->second.getFloat(); break;
// silently ignore locals that don't exist anymore
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();
}
catch (std::exception& e)
{
std::cerr << "Failed to read local variable state for script '"
<< script << "' (legacy format): " << e.what()
<< "\nNum shorts: " << numshorts << " / " << mShorts.size()
<< " Num longs: " << numlongs << " / " << mLongs.size() << std::endl;
}
}
catch (...)
else
{
// ignore type changes
/// \todo write to log
char type = declarations.getType (iter->first);
char index = declarations.getIndex (iter->first);
try
{
switch (type)
{
case 's': mShorts.at (index) = iter->second.getInteger(); break;
case 'l': mLongs.at (index) = iter->second.getInteger(); break;
case 'f': mFloats.at (index) = iter->second.getFloat(); break;
// silently ignore locals that don't exist anymore
}
}
catch (...)
{
// ignore type changes
/// \todo write to log
}
}
}
}

@ -11,7 +11,7 @@ void ESM::Locals::load (ESMReader &esm)
std::string id = esm.getHString();
Variant value;
value.read (esm, Variant::Format_Info);
value.read (esm, Variant::Format_Local);
mVariables.push_back (std::make_pair (id, value));
}
@ -23,6 +23,6 @@ void ESM::Locals::save (ESMWriter &esm) const
iter!=mVariables.end(); ++iter)
{
esm.writeHNString ("LOCA", iter->first);
iter->second.write (esm, Variant::Format_Info);
iter->second.write (esm, Variant::Format_Local);
}
}
}

@ -13,6 +13,7 @@ namespace
const uint32_t STRV = ESM::FourCC<'S','T','R','V'>::value;
const uint32_t INTV = ESM::FourCC<'I','N','T','V'>::value;
const uint32_t FLTV = ESM::FourCC<'F','L','T','V'>::value;
const uint32_t STTV = ESM::FourCC<'S','T','T','V'>::value;
}
ESM::Variant::Variant() : mType (VT_None), mData (0) {}
@ -141,7 +142,7 @@ void ESM::Variant::read (ESMReader& esm, Format format)
esm.fail ("invalid subrecord: " + name.toString());
}
}
else // info
else if (format == Format_Info)
{
esm.getSubName();
NAME name = esm.retSubName();
@ -157,6 +158,26 @@ void ESM::Variant::read (ESMReader& esm, Format format)
else
esm.fail ("invalid subrecord: " + name.toString());
}
else if (format == Format_Local)
{
esm.getSubName();
NAME name = esm.retSubName();
if (name==INTV)
{
type = VT_Int;
}
else if (name==FLTV)
{
type = VT_Float;
}
else if (name==STTV)
{
type = VT_Short;
}
else
esm.fail ("invalid subrecord: " + name.toString());
}
setType (type);
@ -179,6 +200,9 @@ void ESM::Variant::write (ESMWriter& esm, Format format) const
if (format==Format_Info)
throw std::runtime_error ("can not serialise variant of type none to info format");
if (format==Format_Local)
throw std::runtime_error ("can not serialise variant of type none to local format");
// nothing to do here for GMST format
}
else

@ -33,7 +33,8 @@ namespace ESM
{
Format_Global,
Format_Gmst,
Format_Info // also used for local variables in saved game files
Format_Info,
Format_Local // local script variables in save game files
};
Variant();

@ -81,6 +81,9 @@ void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarTy
if (format==Variant::Format_Info)
esm.fail ("info variables of type string not supported");
if (format==Variant::Format_Local)
esm.fail ("local variables of type string not supported");
// GMST
mValue = esm.getHString();
}
@ -173,6 +176,21 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT
esm.getHT (mValue);
}
else if (format==Variant::Format_Local)
{
if (type==VT_Short)
{
short value;
esm.getHT(value);
mValue = value;
}
else if (type==VT_Int)
{
esm.getHT(mValue);
}
else
esm.fail("unsupported local variable integer type");
}
}
void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, VarType type) const
@ -204,6 +222,15 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var
esm.writeHNT ("INTV", mValue);
}
else if (format==Variant::Format_Local)
{
if (type==VT_Short)
esm.writeHNT ("STTV", (short)mValue);
else if (type == VT_Int)
esm.writeHNT ("INTV", mValue);
else
throw std::runtime_error("unsupported local variable integer type");
}
}
bool ESM::VariantIntegerData::isEqual (const VariantDataBase& value) const
@ -252,7 +279,7 @@ void ESM::VariantFloatData::read (ESMReader& esm, Variant::Format format, VarTyp
{
esm.getHNT (mValue, "FLTV");
}
else if (format==Variant::Format_Gmst || format==Variant::Format_Info)
else if (format==Variant::Format_Gmst || format==Variant::Format_Info || format==Variant::Format_Local)
{
esm.getHT (mValue);
}
@ -268,7 +295,7 @@ void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarTy
esm.writeHNString ("FNAM", "f");
esm.writeHNT ("FLTV", mValue);
}
else if (format==Variant::Format_Gmst || format==Variant::Format_Info)
else if (format==Variant::Format_Gmst || format==Variant::Format_Info || format==Variant::Format_Local)
{
esm.writeHNT ("FLTV", mValue);
}
@ -277,4 +304,4 @@ void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarTy
bool ESM::VariantFloatData::isEqual (const VariantDataBase& value) const
{
return dynamic_cast<const VariantFloatData&> (value).mValue==mValue;
}
}

Loading…
Cancel
Save