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 <cassert>
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include <components/esm/globalscript.hpp>
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
@ -90,4 +91,61 @@ namespace MWScript
addScript (iter->mScript); 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 <string>
#include <map> #include <map>
#include <libs/platform/stdint.h>
#include "locals.hpp" #include "locals.hpp"
namespace ESM
{
class ESMWriter;
class ESMReader;
}
namespace MWWorld namespace MWWorld
{ {
struct ESMStore; struct ESMStore;
@ -35,6 +43,15 @@ namespace MWScript
void addStartup(); void addStartup();
///< Add startup script ///< 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 "locals.hpp"
#include <components/esm/loadscpt.hpp> #include <components/esm/loadscpt.hpp>
#include <components/esm/variant.hpp>
#include <components/esm/locals.hpp>
#include <components/compiler/locals.hpp> #include <components/compiler/locals.hpp>
@ -65,4 +67,68 @@ namespace MWScript
} }
return false; 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 namespace ESM
{ {
struct Script; struct Script;
struct Locals;
} }
namespace MWScript namespace MWScript
@ -23,6 +24,9 @@ namespace MWScript
bool setVarByInt(const std::string& script, const std::string& var, int val); 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 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 1 // saved game header
+MWBase::Environment::get().getJournal()->countSavedGameRecords() +MWBase::Environment::get().getJournal()->countSavedGameRecords()
+MWBase::Environment::get().getWorld()->countSavedGameRecords() +MWBase::Environment::get().getWorld()->countSavedGameRecords()
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
); );
writer.save (stream); 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().getJournal()->write (writer);
MWBase::Environment::get().getWorld()->write (writer); MWBase::Environment::get().getWorld()->write (writer);
MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer);
writer.close(); writer.close();
@ -173,6 +175,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
MWBase::Environment::get().getWorld()->readRecord (reader, n.val); MWBase::Environment::get().getWorld()->readRecord (reader, n.val);
break; break;
case ESM::REC_GSCR:
MWBase::Environment::get().getScriptManager()->getGlobalScripts().readRecord (reader, n.val);
break;
default: default:
// ignore invalid records // ignore invalid records

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

@ -87,6 +87,7 @@ enum RecNameInts
REC_SAVE = 0x45564153, REC_SAVE = 0x45564153,
REC_JOUR = 0x524f55a4, REC_JOUR = 0x524f55a4,
REC_QUES = 0x53455551, REC_QUES = 0x53455551,
REC_GSCR = 0x52435347,
// format 1 // format 1
REC_FILT = 0x544C4946 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_Global,
Format_Gmst, Format_Gmst,
Format_Info Format_Info // also used for local variables in saved game files
}; };
Variant(); Variant();

Loading…
Cancel
Save