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:
parent
df3a47187b
commit
024ad3276b
7 changed files with 109 additions and 65 deletions
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue