1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-29 04:06:40 +00:00

Partial fix for #6017. The persistence flag of the references are saved but it is not yet possible to modify it via OpenCS.

This commit is contained in:
cc9cii 2021-06-29 19:20:01 +10:00
parent df3a47187b
commit 024ad3276b
7 changed files with 109 additions and 65 deletions

View file

@ -253,70 +253,21 @@ int CSMDoc::WriteCellCollectionStage::setup()
return mDocument.getData().getCells().getSize(); return mDocument.getData().getCells().getSize();
} }
void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) int CSMDoc::WriteCellCollectionStage::writeReferences (const std::deque<int>& references, bool interior, unsigned int& newRefNum, bool temp)
{ {
ESM::ESMWriter& writer = mState.getWriter(); ESM::ESMWriter& writer = mState.getWriter();
const CSMWorld::Record<CSMWorld::Cell>& cell = mDocument.getData().getCells().getRecord (stage); size_t refCount = 0;
std::map<std::string, std::deque<int> >::const_iterator references = for (std::deque<int>::const_iterator iter (references.begin());
mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId)); iter!=references.end(); ++iter)
if (cell.isModified() ||
cell.mState == CSMWorld::RecordBase::State_Deleted ||
references!=mState.getSubRecords().end())
{
CSMWorld::Cell cellRecord = cell.get();
bool interior = cellRecord.mId.substr (0, 1)!="#";
// count new references and adjust RefNumCount accordingsly
unsigned int newRefNum = cellRecord.mRefNumCounter;
if (references!=mState.getSubRecords().end())
{
for (std::deque<int>::const_iterator iter (references->second.begin());
iter!=references->second.end(); ++iter)
{ {
const CSMWorld::Record<CSMWorld::CellRef>& ref = const CSMWorld::Record<CSMWorld::CellRef>& ref =
mDocument.getData().getReferences().getRecord (*iter); mDocument.getData().getReferences().getRecord (*iter);
CSMWorld::CellRef refRecord = ref.get(); if (temp && ref.get().mIsPersistent || !temp && !ref.get().mIsPersistent)
continue;
if (refRecord.mNew || refCount++;
(!interior && ref.mState==CSMWorld::RecordBase::State_ModifiedOnly &&
/// \todo consider worldspace
CSMWorld::CellCoordinates (refRecord.getCellIndex()).getId("") != refRecord.mCell))
++cellRecord.mRefNumCounter;
if (refRecord.mRefNum.mIndex >= newRefNum)
newRefNum = refRecord.mRefNum.mIndex + 1;
}
}
// write cell data
writer.startRecord (cellRecord.sRecordId);
if (interior)
cellRecord.mData.mFlags |= ESM::Cell::Interior;
else
{
cellRecord.mData.mFlags &= ~ESM::Cell::Interior;
std::istringstream stream (cellRecord.mId.c_str());
char ignore;
stream >> ignore >> cellRecord.mData.mX >> cellRecord.mData.mY;
}
cellRecord.save (writer, cell.mState == CSMWorld::RecordBase::State_Deleted);
// write references
if (references!=mState.getSubRecords().end())
{
for (std::deque<int>::const_iterator iter (references->second.begin());
iter!=references->second.end(); ++iter)
{
const CSMWorld::Record<CSMWorld::CellRef>& ref =
mDocument.getData().getReferences().getRecord (*iter);
if (ref.isModified() || ref.mState == CSMWorld::RecordBase::State_Deleted) if (ref.isModified() || ref.mState == CSMWorld::RecordBase::State_Deleted)
{ {
@ -362,6 +313,72 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
refRecord.save (writer, false, false, ref.mState == CSMWorld::RecordBase::State_Deleted); refRecord.save (writer, false, false, ref.mState == CSMWorld::RecordBase::State_Deleted);
} }
} }
return refCount;
}
void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
{
ESM::ESMWriter& writer = mState.getWriter();
const CSMWorld::Record<CSMWorld::Cell>& cell = mDocument.getData().getCells().getRecord (stage);
std::map<std::string, std::deque<int> >::const_iterator references =
mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId));
if (cell.isModified() ||
cell.mState == CSMWorld::RecordBase::State_Deleted ||
references!=mState.getSubRecords().end())
{
CSMWorld::Cell cellRecord = cell.get();
bool interior = cellRecord.mId.substr (0, 1)!="#";
// count new references and adjust RefNumCount accordingsly
unsigned int newRefNum = cellRecord.mRefNumCounter;
if (references!=mState.getSubRecords().end())
{
for (std::deque<int>::const_iterator iter (references->second.begin());
iter!=references->second.end(); ++iter)
{
const CSMWorld::Record<CSMWorld::CellRef>& ref =
mDocument.getData().getReferences().getRecord (*iter);
CSMWorld::CellRef refRecord = ref.get();
if (refRecord.mNew ||
(!interior && ref.mState==CSMWorld::RecordBase::State_ModifiedOnly &&
/// \todo consider worldspace
CSMWorld::CellCoordinates (refRecord.getCellIndex()).getId("") != refRecord.mCell))
++cellRecord.mRefNumCounter;
if (refRecord.mRefNum.mIndex >= newRefNum)
newRefNum = refRecord.mRefNum.mIndex + 1;
}
}
// write cell data
writer.startRecord (cellRecord.sRecordId);
if (interior)
cellRecord.mData.mFlags |= ESM::Cell::Interior;
else
{
cellRecord.mData.mFlags &= ~ESM::Cell::Interior;
std::istringstream stream (cellRecord.mId.c_str());
char ignore;
stream >> ignore >> cellRecord.mData.mX >> cellRecord.mData.mY;
}
cellRecord.save (writer, cell.mState == CSMWorld::RecordBase::State_Deleted);
// write references
if (references!=mState.getSubRecords().end())
{
int persistentRefCount = writeReferences(references->second, interior, newRefNum, false/*temp*/);
cellRecord.saveTempMarker(writer, int(references->second.size()) - persistentRefCount);
// FIXME: loops twice, inefficient
writeReferences(references->second, interior, newRefNum, true/*temp*/);
} }
writer.endRecord (cellRecord.sRecordId); writer.endRecord (cellRecord.sRecordId);

View file

@ -171,6 +171,8 @@ namespace CSMDoc
Document& mDocument; Document& mDocument;
SavingState& mState; SavingState& mState;
int writeReferences (const std::deque<int>& references, bool interior, unsigned int& newRefNum, bool temp);
public: public:
WriteCellCollectionStage (Document& document, SavingState& state); WriteCellCollectionStage (Document& document, SavingState& state);

View file

@ -19,8 +19,9 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
ESM::MovedCellRef mref; ESM::MovedCellRef mref;
mref.mRefNum.mIndex = 0; mref.mRefNum.mIndex = 0;
bool isDeleted = false; bool isDeleted = false;
int tempRefCount = cell.get().mRefNumCounter; // if initially non-zero, all refs in cell are temp
while (ESM::Cell::getNextRef(reader, ref, isDeleted, true, &mref)) while (ESM::Cell::getNextRef(reader, ref, isDeleted, &tempRefCount, true, &mref))
{ {
// Keep mOriginalCell empty when in modified (as an indicator that the // Keep mOriginalCell empty when in modified (as an indicator that the
// original cell will always be equal the current cell). // original cell will always be equal the current cell).
@ -59,6 +60,8 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
else else
ref.mCell = cell2.mId; ref.mCell = cell2.mId;
// TODO: update cell.get().mRefNumCounter with tempRefCount?
mref.mRefNum.mIndex = 0; mref.mRefNum.mIndex = 0;
// ignore content file number // ignore content file number

View file

@ -31,10 +31,10 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const
} }
void ESM::CellRef::load (ESMReader& esm, bool &isDeleted, bool wideRefNum) void ESM::CellRef::load (ESMReader& esm, bool &isDeleted, int *tempRefCount, bool wideRefNum)
{ {
loadId(esm, wideRefNum); loadId(esm, wideRefNum);
loadData(esm, isDeleted); loadData(esm, isDeleted, tempRefCount);
} }
void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum) void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum)
@ -57,9 +57,11 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum)
} }
} }
void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted) void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted, int *tempRefCount)
{ {
isDeleted = false; isDeleted = false;
mIsPersistent = !tempRefCount // default to persistent
|| (tempRefCount && *tempRefCount == -1);
bool isLoaded = false; bool isLoaded = false;
while (!isLoaded && esm.hasMoreSubs()) while (!isLoaded && esm.hasMoreSubs())
@ -121,8 +123,17 @@ void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted)
esm.getHT(mPos, 24); esm.getHT(mPos, 24);
break; break;
case ESM::FourCC<'N','A','M','0'>::value: case ESM::FourCC<'N','A','M','0'>::value:
{
if (tempRefCount && *tempRefCount == -1)
{
esm.getHT(*tempRefCount);
// TODO: check that there are no more subs following this sub
}
else
esm.skipHSub(); esm.skipHSub();
break; break;
}
case ESM::SREC_DELE: case ESM::SREC_DELE:
esm.skipHSub(); esm.skipHSub();
isDeleted = true; isDeleted = true;
@ -236,4 +247,6 @@ void ESM::CellRef::blank()
mPos.pos[i] = 0; mPos.pos[i] = 0;
mPos.rot[i] = 0; mPos.rot[i] = 0;
} }
mIsPersistent = false;
} }

View file

@ -106,13 +106,15 @@ namespace ESM
// Position and rotation of this object within the cell // Position and rotation of this object within the cell
Position mPos; Position mPos;
bool mIsPersistent;
/// Calls loadId and loadData /// Calls loadId and loadData
void load (ESMReader& esm, bool &isDeleted, bool wideRefNum = false); void load (ESMReader& esm, bool &isDeleted, int *tempRefCount, bool wideRefNum = false);
void loadId (ESMReader& esm, bool wideRefNum = false); void loadId (ESMReader& esm, bool wideRefNum = false);
/// Implicitly called by load /// Implicitly called by load
void loadData (ESMReader& esm, bool &isDeleted); void loadData (ESMReader& esm, bool &isDeleted, int *tempRefCount = nullptr);
void save (ESMWriter &esm, bool wideRefNum = false, bool inInventory = false, bool isDeleted = false) const; void save (ESMWriter &esm, bool wideRefNum = false, bool inInventory = false, bool isDeleted = false) const;

View file

@ -197,9 +197,12 @@ namespace ESM
if (mMapColor != 0) if (mMapColor != 0)
esm.writeHNT("NAM5", mMapColor); esm.writeHNT("NAM5", mMapColor);
} }
}
if (mRefNumCounter != 0) void Cell::saveTempMarker(ESMWriter &esm, int tempCount) const
esm.writeHNT("NAM0", mRefNumCounter); {
if (tempCount != 0)
esm.writeHNT("NAM0", tempCount);
} }
void Cell::restore(ESMReader &esm, int iCtx) const void Cell::restore(ESMReader &esm, int iCtx) const
@ -221,7 +224,7 @@ namespace ESM
return region + ' ' + cellGrid; return region + ' ' + cellGrid;
} }
bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool &isDeleted, bool ignoreMoves, MovedCellRef *mref) bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool &isDeleted, int *tempRefCount, bool ignoreMoves, MovedCellRef *mref)
{ {
isDeleted = false; isDeleted = false;
@ -249,7 +252,9 @@ namespace ESM
if (esm.peekNextSub("FRMR")) if (esm.peekNextSub("FRMR"))
{ {
ref.load (esm, isDeleted); ref.load (esm, isDeleted, tempRefCount);
// TODO: should count the number of temp refs and validate the number
// Identify references belonging to a parent file and adapt the ID accordingly. // Identify references belonging to a parent file and adapt the ID accordingly.
adjustRefNum (ref.mRefNum, esm); adjustRefNum (ref.mRefNum, esm);
@ -275,7 +280,7 @@ namespace ESM
mWater = 0; mWater = 0;
mWaterInt = false; mWaterInt = false;
mMapColor = 0; mMapColor = 0;
mRefNumCounter = 0; mRefNumCounter = -1;
mData.mFlags = 0; mData.mFlags = 0;
mData.mX = 0; mData.mX = 0;

View file

@ -94,7 +94,7 @@ struct Cell
mWater(0), mWater(0),
mWaterInt(false), mWaterInt(false),
mMapColor(0), mMapColor(0),
mRefNumCounter(0) mRefNumCounter(-1)
{} {}
// Interior cells are indexed by this (it's the 'id'), for exterior // Interior cells are indexed by this (it's the 'id'), for exterior
@ -133,6 +133,7 @@ struct Cell
void loadCell(ESMReader &esm, bool saveContext = true); // Load everything, except NAME, DATAstruct and references void loadCell(ESMReader &esm, bool saveContext = true); // Load everything, except NAME, DATAstruct and references
void save(ESMWriter &esm, bool isDeleted = false) const; void save(ESMWriter &esm, bool isDeleted = false) const;
void saveTempMarker(ESMWriter &esm, int tempCount) const;
bool isExterior() const bool isExterior() const
{ {
@ -184,6 +185,7 @@ struct Cell
static bool getNextRef(ESMReader &esm, static bool getNextRef(ESMReader &esm,
CellRef &ref, CellRef &ref,
bool &isDeleted, bool &isDeleted,
int *tempRefCount = nullptr,
bool ignoreMoves = false, bool ignoreMoves = false,
MovedCellRef *mref = nullptr); MovedCellRef *mref = nullptr);