1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-03 19:39:41 +00:00

Don't require the object type id for reading references from savegames

This is redundant, since we can look it up from the RefID.
This commit is contained in:
scrawl 2015-01-19 23:29:06 +01:00
parent 8e1eeccbe1
commit 9014dc48ee
13 changed files with 123 additions and 39 deletions

View file

@ -816,6 +816,9 @@ namespace MWClass
void Creature::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) void Creature::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
const const
{ {
if (!state.mHasCustomState)
return;
const ESM::CreatureState& state2 = dynamic_cast<const ESM::CreatureState&> (state); const ESM::CreatureState& state2 = dynamic_cast<const ESM::CreatureState&> (state);
ensureCustomData(ptr); ensureCustomData(ptr);
@ -844,7 +847,6 @@ namespace MWClass
customData.mContainerStore->readState (state2.mInventory); customData.mContainerStore->readState (state2.mInventory);
customData.mCreatureStats.readState (state2.mCreatureStats); customData.mCreatureStats.readState (state2.mCreatureStats);
} }
void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
@ -852,6 +854,12 @@ namespace MWClass
{ {
ESM::CreatureState& state2 = dynamic_cast<ESM::CreatureState&> (state); ESM::CreatureState& state2 = dynamic_cast<ESM::CreatureState&> (state);
if (!ptr.getRefData().getCustomData())
{
state.mHasCustomState = false;
return;
}
ensureCustomData (ptr); ensureCustomData (ptr);
CreatureCustomData& customData = dynamic_cast<CreatureCustomData&> (*ptr.getRefData().getCustomData()); CreatureCustomData& customData = dynamic_cast<CreatureCustomData&> (*ptr.getRefData().getCustomData());

View file

@ -1275,6 +1275,9 @@ namespace MWClass
void Npc::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) void Npc::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
const const
{ {
if (!state.mHasCustomState)
return;
const ESM::NpcState& state2 = dynamic_cast<const ESM::NpcState&> (state); const ESM::NpcState& state2 = dynamic_cast<const ESM::NpcState&> (state);
ensureCustomData(ptr); ensureCustomData(ptr);
@ -1302,6 +1305,12 @@ namespace MWClass
{ {
ESM::NpcState& state2 = dynamic_cast<ESM::NpcState&> (state); ESM::NpcState& state2 = dynamic_cast<ESM::NpcState&> (state);
if (!ptr.getRefData().getCustomData())
{
state.mHasCustomState = false;
return;
}
ensureCustomData (ptr); ensureCustomData (ptr);
NpcCustomData& customData = dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData()); NpcCustomData& customData = dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData());

View file

@ -85,7 +85,9 @@ namespace
RecordType state; RecordType state;
iter->save (state); iter->save (state);
// recordId currently unused
writer.writeHNT ("OBJE", collection.mList.front().mBase->sRecordId); writer.writeHNT ("OBJE", collection.mList.front().mBase->sRecordId);
state.save (writer); state.save (writer);
} }
} }
@ -93,12 +95,13 @@ namespace
template<typename RecordType, typename T> template<typename RecordType, typename T>
void readReferenceCollection (ESM::ESMReader& reader, void readReferenceCollection (ESM::ESMReader& reader,
MWWorld::CellRefList<T>& collection, const std::map<int, int>& contentFileMap) MWWorld::CellRefList<T>& collection, const ESM::CellRef& cref, const std::map<int, int>& contentFileMap)
{ {
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
RecordType state; RecordType state;
state.load (reader); state.mRef = cref;
state.load(reader);
// If the reference came from a content file, make sure this content file is loaded // If the reference came from a content file, make sure this content file is loaded
if (state.mRef.mRefNum.hasContentFile()) if (state.mRef.mRefNum.hasContentFile())
@ -640,109 +643,121 @@ namespace MWWorld
while (reader.isNextSub ("OBJE")) while (reader.isNextSub ("OBJE"))
{ {
unsigned int id = 0; unsigned int unused;
reader.getHT (id); reader.getHT (unused);
switch (id) // load the RefID first so we know what type of object it is
ESM::CellRef cref;
cref.loadId(reader, true);
int type = MWBase::Environment::get().getWorld()->getStore().find(cref.mRefID);
if (type == 0)
{
std::cerr << "Dropping reference to '" << cref.mRefID << "' (object no longer exists)" << std::endl;
reader.skipHSubUntil("OBJE");
continue;
}
switch (type)
{ {
case ESM::REC_ACTI: case ESM::REC_ACTI:
readReferenceCollection<ESM::ObjectState> (reader, mActivators, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mActivators, cref, contentFileMap);
break; break;
case ESM::REC_ALCH: case ESM::REC_ALCH:
readReferenceCollection<ESM::ObjectState> (reader, mPotions, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mPotions, cref, contentFileMap);
break; break;
case ESM::REC_APPA: case ESM::REC_APPA:
readReferenceCollection<ESM::ObjectState> (reader, mAppas, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mAppas, cref, contentFileMap);
break; break;
case ESM::REC_ARMO: case ESM::REC_ARMO:
readReferenceCollection<ESM::ObjectState> (reader, mArmors, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mArmors, cref, contentFileMap);
break; break;
case ESM::REC_BOOK: case ESM::REC_BOOK:
readReferenceCollection<ESM::ObjectState> (reader, mBooks, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mBooks, cref, contentFileMap);
break; break;
case ESM::REC_CLOT: case ESM::REC_CLOT:
readReferenceCollection<ESM::ObjectState> (reader, mClothes, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mClothes, cref, contentFileMap);
break; break;
case ESM::REC_CONT: case ESM::REC_CONT:
readReferenceCollection<ESM::ContainerState> (reader, mContainers, contentFileMap); readReferenceCollection<ESM::ContainerState> (reader, mContainers, cref, contentFileMap);
break; break;
case ESM::REC_CREA: case ESM::REC_CREA:
readReferenceCollection<ESM::CreatureState> (reader, mCreatures, contentFileMap); readReferenceCollection<ESM::CreatureState> (reader, mCreatures, cref, contentFileMap);
break; break;
case ESM::REC_DOOR: case ESM::REC_DOOR:
readReferenceCollection<ESM::DoorState> (reader, mDoors, contentFileMap); readReferenceCollection<ESM::DoorState> (reader, mDoors, cref, contentFileMap);
break; break;
case ESM::REC_INGR: case ESM::REC_INGR:
readReferenceCollection<ESM::ObjectState> (reader, mIngreds, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mIngreds, cref, contentFileMap);
break; break;
case ESM::REC_LEVC: case ESM::REC_LEVC:
readReferenceCollection<ESM::CreatureLevListState> (reader, mCreatureLists, contentFileMap); readReferenceCollection<ESM::CreatureLevListState> (reader, mCreatureLists, cref, contentFileMap);
break; break;
case ESM::REC_LEVI: case ESM::REC_LEVI:
readReferenceCollection<ESM::ObjectState> (reader, mItemLists, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mItemLists, cref, contentFileMap);
break; break;
case ESM::REC_LIGH: case ESM::REC_LIGH:
readReferenceCollection<ESM::ObjectState> (reader, mLights, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mLights, cref, contentFileMap);
break; break;
case ESM::REC_LOCK: case ESM::REC_LOCK:
readReferenceCollection<ESM::ObjectState> (reader, mLockpicks, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mLockpicks, cref, contentFileMap);
break; break;
case ESM::REC_MISC: case ESM::REC_MISC:
readReferenceCollection<ESM::ObjectState> (reader, mMiscItems, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mMiscItems, cref, contentFileMap);
break; break;
case ESM::REC_NPC_: case ESM::REC_NPC_:
readReferenceCollection<ESM::NpcState> (reader, mNpcs, contentFileMap); readReferenceCollection<ESM::NpcState> (reader, mNpcs, cref, contentFileMap);
break; break;
case ESM::REC_PROB: case ESM::REC_PROB:
readReferenceCollection<ESM::ObjectState> (reader, mProbes, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mProbes, cref, contentFileMap);
break; break;
case ESM::REC_REPA: case ESM::REC_REPA:
readReferenceCollection<ESM::ObjectState> (reader, mRepairs, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mRepairs, cref, contentFileMap);
break; break;
case ESM::REC_STAT: case ESM::REC_STAT:
readReferenceCollection<ESM::ObjectState> (reader, mStatics, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mStatics, cref, contentFileMap);
break; break;
case ESM::REC_WEAP: case ESM::REC_WEAP:
readReferenceCollection<ESM::ObjectState> (reader, mWeapons, contentFileMap); readReferenceCollection<ESM::ObjectState> (reader, mWeapons, cref, contentFileMap);
break; break;
default: default:

View file

@ -5,6 +5,12 @@
#include "esmwriter.hpp" #include "esmwriter.hpp"
void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) void ESM::CellRef::load (ESMReader& esm, bool wideRefNum)
{
loadId(esm, wideRefNum);
loadData(esm);
}
void ESM::CellRef::loadId(ESMReader &esm, bool wideRefNum)
{ {
// According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that // According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that
// the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system. // the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system.
@ -19,8 +25,6 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum)
esm.getHNT (mRefNum.mIndex, "FRMR"); esm.getHNT (mRefNum.mIndex, "FRMR");
mRefID = esm.getHNString ("NAME"); mRefID = esm.getHNString ("NAME");
loadData(esm);
} }
void ESM::CellRef::loadData(ESMReader &esm) void ESM::CellRef::loadData(ESMReader &esm)

View file

@ -89,8 +89,11 @@ namespace ESM
// Position and rotation of this object within the cell // Position and rotation of this object within the cell
Position mPos; Position mPos;
/// Calls loadId and loadData
void load (ESMReader& esm, bool wideRefNum = false); void load (ESMReader& esm, bool wideRefNum = false);
void loadId (ESMReader& esm, bool wideRefNum = false);
/// Implicitly called by load /// Implicitly called by load
void loadData (ESMReader& esm); void loadData (ESMReader& esm);

View file

@ -5,18 +5,24 @@ void ESM::CreatureState::load (ESMReader &esm)
{ {
ObjectState::load (esm); ObjectState::load (esm);
if (mHasCustomState)
{
mInventory.load (esm); mInventory.load (esm);
mCreatureStats.load (esm); mCreatureStats.load (esm);
}
} }
void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const
{ {
ObjectState::save (esm, inInventory); ObjectState::save (esm, inInventory);
if (mHasCustomState)
{
mInventory.save (esm); mInventory.save (esm);
mCreatureStats.save (esm); mCreatureStats.save (esm);
}
} }
void ESM::CreatureState::blank() void ESM::CreatureState::blank()

View file

@ -210,6 +210,17 @@ void ESMReader::skipHSubSize(int size)
fail("skipHSubSize() mismatch"); fail("skipHSubSize() mismatch");
} }
void ESMReader::skipHSubUntil(const char *name)
{
while (hasMoreSubs() && !isNextSub(name))
{
mCtx.subCached = false;
skipHSub();
}
if (hasMoreSubs())
mCtx.subCached = true;
}
void ESMReader::getSubHeader() void ESMReader::getSubHeader()
{ {
if (mCtx.leftRec < 4) if (mCtx.leftRec < 4)

View file

@ -195,6 +195,9 @@ public:
// Skip sub record and check its size // Skip sub record and check its size
void skipHSubSize(int size); void skipHSubSize(int size);
// Skip all subrecords until the given subrecord or no more subrecords remaining
void skipHSubUntil(const char* name);
/* Sub-record header. This updates leftRec beyond the current /* Sub-record header. This updates leftRec beyond the current
sub-record as well. leftSub contains size of current sub-record. sub-record as well. leftSub contains size of current sub-record.
*/ */

View file

@ -11,6 +11,7 @@ namespace
slot = -1; slot = -1;
esm.getHNOT (slot, "SLOT"); esm.getHNOT (slot, "SLOT");
state.mRef.loadId(esm, true);
state.load (esm); state.load (esm);
} }

View file

@ -5,22 +5,28 @@ void ESM::NpcState::load (ESMReader &esm)
{ {
ObjectState::load (esm); ObjectState::load (esm);
if (mHasCustomState)
{
mInventory.load (esm); mInventory.load (esm);
mNpcStats.load (esm); mNpcStats.load (esm);
mCreatureStats.load (esm); mCreatureStats.load (esm);
}
} }
void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const
{ {
ObjectState::save (esm, inInventory); ObjectState::save (esm, inInventory);
if (mHasCustomState)
{
mInventory.save (esm); mInventory.save (esm);
mNpcStats.save (esm); mNpcStats.save (esm);
mCreatureStats.save (esm); mCreatureStats.save (esm);
}
} }
void ESM::NpcState::blank() void ESM::NpcState::blank()
@ -28,4 +34,5 @@ void ESM::NpcState::blank()
ObjectState::blank(); ObjectState::blank();
mNpcStats.blank(); mNpcStats.blank();
mCreatureStats.blank(); mCreatureStats.blank();
mHasCustomState = true;
} }

View file

@ -6,7 +6,7 @@
void ESM::ObjectState::load (ESMReader &esm) void ESM::ObjectState::load (ESMReader &esm)
{ {
mRef.load (esm, true); mRef.loadData(esm);
mHasLocals = 0; mHasLocals = 0;
esm.getHNOT (mHasLocals, "HLOC"); esm.getHNOT (mHasLocals, "HLOC");
@ -27,6 +27,10 @@ void ESM::ObjectState::load (ESMReader &esm)
// used for lights only // used for lights only
mTime = 0; mTime = 0;
esm.getHNOT (mTime, "LTIM"); esm.getHNOT (mTime, "LTIM");
// FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files
mHasCustomState = true;
esm.getHNOT (mHasCustomState, "HCUS");
} }
void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const
@ -53,6 +57,9 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const
if (mTime) if (mTime)
esm.writeHNT ("LTIM", mTime); esm.writeHNT ("LTIM", mTime);
if (!mHasCustomState)
esm.writeHNT ("HCUS", false);
} }
void ESM::ObjectState::blank() void ESM::ObjectState::blank()
@ -68,6 +75,7 @@ void ESM::ObjectState::blank()
mLocalRotation[i] = 0; mLocalRotation[i] = 0;
} }
mTime = 0; mTime = 0;
mHasCustomState = true;
} }
ESM::ObjectState::~ObjectState() {} ESM::ObjectState::~ObjectState() {}

View file

@ -28,7 +28,15 @@ namespace ESM
float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either
// Is there any class-specific state following the ObjectState
bool mHasCustomState;
ObjectState() : mHasCustomState(true)
{}
/// @note Does not load the CellRef ID, it should already be loaded before calling this method
virtual void load (ESMReader &esm); virtual void load (ESMReader &esm);
virtual void save (ESMWriter &esm, bool inInventory = false) const; virtual void save (ESMWriter &esm, bool inInventory = false) const;
/// Initialize to default state /// Initialize to default state

View file

@ -6,6 +6,7 @@
void ESM::Player::load (ESMReader &esm) void ESM::Player::load (ESMReader &esm)
{ {
mObject.mRef.loadId(esm, true);
mObject.load (esm); mObject.load (esm);
mCellId.load (esm); mCellId.load (esm);