store global script state in saved game files

actorid
Marc Zinnschlag 11 years ago
parent 2a35c7d33a
commit 3590fa40bd

@ -4,6 +4,7 @@
#include <cassert>
#include <components/misc/stringops.hpp>
#include <components/esm/globalscript.hpp>
#include "../mwworld/esmstore.hpp"
@ -90,4 +91,61 @@ namespace MWScript
addScript (iter->mScript);
}
}
int GlobalScripts::countSavedGameRecords() const
{
return mScripts.size();
}
void GlobalScripts::write (ESM::ESMWriter& writer) const
{
for (std::map<std::string, std::pair<bool, Locals> >::const_iterator iter (mScripts.begin());
iter!=mScripts.end(); ++iter)
{
ESM::GlobalScript script;
script.mId = iter->first;
iter->second.second.write (script.mLocals, iter->first);
script.mRunning = iter->second.first ? 1 : 0;
writer.startRecord (ESM::REC_GSCR);
script.save (writer);
writer.endRecord (ESM::REC_GSCR);
}
}
bool GlobalScripts::readRecord (ESM::ESMReader& reader, int32_t type)
{
if (type==ESM::REC_GSCR)
{
ESM::GlobalScript script;
script.load (reader);
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
mScripts.find (script.mId);
if (iter==mScripts.end())
{
if (const ESM::Script *scriptRecord = mStore.get<ESM::Script>().search (script.mId))
{
std::pair<bool, Locals> data (false, Locals());
data.second.configure (*scriptRecord);
iter = mScripts.insert (std::make_pair (script.mId, data)).first;
}
else // script does not exist anymore
return true;
}
iter->second.first = script.mRunning!=0;
iter->second.second.read (script.mLocals, script.mId);
return true;
}
return false;
}
}

@ -4,8 +4,16 @@
#include <string>
#include <map>
#include <libs/platform/stdint.h>
#include "locals.hpp"
namespace ESM
{
class ESMWriter;
class ESMReader;
}
namespace MWWorld
{
struct ESMStore;
@ -35,6 +43,15 @@ namespace MWScript
void addStartup();
///< Add startup script
int countSavedGameRecords() const;
void write (ESM::ESMWriter& writer) const;
bool readRecord (ESM::ESMReader& reader, int32_t type);
///< Records for variables that do not exist are dropped silently.
///
/// \return Known type?
};
}

@ -1,6 +1,8 @@
#include "locals.hpp"
#include <components/esm/loadscpt.hpp>
#include <components/esm/variant.hpp>
#include <components/esm/locals.hpp>
#include <components/compiler/locals.hpp>
@ -65,4 +67,68 @@ namespace MWScript
}
return false;
}
void Locals::write (ESM::Locals& locals, const std::string& script) const
{
const Compiler::Locals& declarations =
MWBase::Environment::get().getScriptManager()->getLocals(script);
for (int i=0; i<3; ++i)
{
char type = 0;
switch (i)
{
case 0: type = 's'; break;
case 1: type = 'l'; break;
case 2: type = 'f'; break;
}
const std::vector<std::string>& names = declarations.get (type);
for (int i2=0; i2<static_cast<int> (names.size()); ++i2)
{
ESM::Variant value;
switch (i)
{
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;
}
locals.mVariables.push_back (std::make_pair (names[i2], value));
}
}
}
void Locals::read (const ESM::Locals& locals, const std::string& script)
{
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)
{
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
}
}
}
}

@ -8,6 +8,7 @@
namespace ESM
{
struct Script;
struct Locals;
}
namespace MWScript
@ -23,6 +24,9 @@ namespace MWScript
bool setVarByInt(const std::string& script, const std::string& var, int val);
int getIntVar (const std::string& script, const std::string& var); ///< if var does not exist, returns 0
void write (ESM::Locals& locals, const std::string& script) const;
void read (const ESM::Locals& locals, const std::string& script);
};
}

@ -114,6 +114,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
1 // saved game header
+MWBase::Environment::get().getJournal()->countSavedGameRecords()
+MWBase::Environment::get().getWorld()->countSavedGameRecords()
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
);
writer.save (stream);
@ -124,6 +125,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
MWBase::Environment::get().getJournal()->write (writer);
MWBase::Environment::get().getWorld()->write (writer);
MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer);
writer.close();
@ -173,6 +175,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
MWBase::Environment::get().getWorld()->readRecord (reader, n.val);
break;
case ESM::REC_GSCR:
MWBase::Environment::get().getScriptManager()->getGlobalScripts().readRecord (reader, n.val);
break;
default:
// ignore invalid records

@ -40,7 +40,7 @@ add_component_dir (esm
loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
savedgame journalentry queststate
savedgame journalentry queststate locals globalscript
)
add_component_dir (misc

@ -15,27 +15,27 @@ namespace Compiler
{
case 's': return mShorts;
case 'l': return mLongs;
case 'f': return mFloats;
case 'f': return mFloats;
}
throw std::logic_error ("unknown variable type");
}
int Locals::searchIndex (char type, const std::string& name) const
{
const std::vector<std::string>& collection = get (type);
std::vector<std::string>::const_iterator iter =
std::find (collection.begin(), collection.end(), name);
if (iter==collection.end())
return -1;
return iter-collection.begin();
}
bool Locals::search (char type, const std::string& name) const
{
{
return searchIndex (type, name)!=-1;
}
@ -45,10 +45,10 @@ namespace Compiler
{
case 's': return mShorts;
case 'l': return mLongs;
case 'f': return mFloats;
case 'f': return mFloats;
}
throw std::logic_error ("unknown variable type");
throw std::logic_error ("unknown variable type");
}
char Locals::getType (const std::string& name) const
@ -58,35 +58,35 @@ namespace Compiler
if (search ('l', name))
return 'l';
if (search ('f', name))
return 'f';
return ' ';
}
int Locals::getIndex (const std::string& name) const
{
int index = searchIndex ('s', name);
if (index!=-1)
return index;
index = searchIndex ('l', name);
if (index!=-1)
return index;
return searchIndex ('f', name);
return searchIndex ('f', name);
}
void Locals::write (std::ostream& localFile) const
{
localFile
<< get ('s').size() << ' '
<< get ('l').size() << ' '
<< get ('f').size() << std::endl;
std::copy (get ('s').begin(), get ('s').end(),
std::ostream_iterator<std::string> (localFile, " "));
std::copy (get ('l').begin(), get ('l').end(),
@ -94,12 +94,12 @@ namespace Compiler
std::copy (get ('f').begin(), get ('f').end(),
std::ostream_iterator<std::string> (localFile, " "));
}
void Locals::declare (char type, const std::string& name)
{
get (type).push_back (name);
}
void Locals::clear()
{
get ('s').clear();

@ -8,35 +8,35 @@
namespace Compiler
{
/// \brief Local variable declarations
class Locals
{
std::vector<std::string> mShorts;
std::vector<std::string> mLongs;
std::vector<std::string> mFloats;
int searchIndex (char type, const std::string& name) const;
bool search (char type, const std::string& name) const;
std::vector<std::string>& get (char type);
std::vector<std::string>& get (char type);
public:
char getType (const std::string& name) const;
///< 's': short, 'l': long, 'f': float, ' ': does not exist.
int getIndex (const std::string& name) const;
///< return index for local variable \a name (-1: does not exist).
const std::vector<std::string>& get (char type) const;
void write (std::ostream& localFile) const;
///< write declarations to file.
void declare (char type, const std::string& name);
///< declares a variable.
void clear();
///< remove all declarations.
};

@ -87,6 +87,7 @@ enum RecNameInts
REC_SAVE = 0x45564153,
REC_JOUR = 0x524f55a4,
REC_QUES = 0x53455551,
REC_GSCR = 0x52435347,
// format 1
REC_FILT = 0x544C4946

@ -0,0 +1,25 @@
#include "globalscript.hpp"
#include "esmreader.hpp"
#include "esmwriter.hpp"
void ESM::GlobalScript::load (ESMReader &esm)
{
mId = esm.getHNString ("NAME");
mLocals.load (esm);
mRunning = 0;
esm.getHNOT (mRunning, "RUN_");
}
void ESM::GlobalScript::save (ESMWriter &esm) const
{
esm.writeHNString ("NAME", mId);
mLocals.save (esm);
if (mRunning)
esm.writeHNT ("RUN_", mRunning);
}

@ -0,0 +1,24 @@
#ifndef OPENMW_ESM_GLOBALSCRIPT_H
#define OPENMW_ESM_GLOBALSCRIPT_H
#include "locals.hpp"
namespace ESM
{
class ESMReader;
class ESMWriter;
/// \brief Storage structure for global script state (only used in saved games)
struct GlobalScript
{
std::string mId;
Locals mLocals;
int mRunning;
void load (ESMReader &esm);
void save (ESMWriter &esm) const;
};
}
#endif

@ -0,0 +1,28 @@
#include "locals.hpp"
#include "esmreader.hpp"
#include "esmwriter.hpp"
void ESM::Locals::load (ESMReader &esm)
{
while (esm.isNextSub ("LOCA"))
{
std::string id = esm.getHString();
Variant value;
value.read (esm, Variant::Format_Info);
mVariables.push_back (std::make_pair (id, value));
}
}
void ESM::Locals::save (ESMWriter &esm) const
{
for (std::vector<std::pair<std::string, Variant> >::const_iterator iter (mVariables.begin());
iter!=mVariables.end(); ++iter)
{
esm.writeHNString ("LOCA", iter->first);
iter->second.write (esm, Variant::Format_Info);
}
}

@ -0,0 +1,27 @@
#ifndef OPENMW_ESM_LOCALS_H
#define OPENMW_ESM_LOCALS_H
#include <vector>
#include <string>
#include "variant.hpp"
namespace ESM
{
class ESMReader;
class ESMWriter;
/// \brief Storage structure for local variables (only used in saved games)
///
/// \note This is not a top-level record.
struct Locals
{
std::vector<std::pair<std::string, Variant> > mVariables;
void load (ESMReader &esm);
void save (ESMWriter &esm) const;
};
}
#endif

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

Loading…
Cancel
Save