forked from mirror/openmw-tes3mp
store global script state in saved game files
This commit is contained in:
parent
2a35c7d33a
commit
3590fa40bd
14 changed files with 290 additions and 33 deletions
|
@ -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
|
||||||
|
|
25
components/esm/globalscript.cpp
Normal file
25
components/esm/globalscript.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
24
components/esm/globalscript.hpp
Normal file
24
components/esm/globalscript.hpp
Normal file
|
@ -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
|
28
components/esm/locals.cpp
Normal file
28
components/esm/locals.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
27
components/esm/locals.hpp
Normal file
27
components/esm/locals.hpp
Normal file
|
@ -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…
Reference in a new issue