1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-26 18:35:20 +00:00

Implement saving of deleted records

This commit is contained in:
Stanislav Bas 2015-07-19 11:42:05 +03:00
parent e04e32bcff
commit 8e6a7be6f5
5 changed files with 125 additions and 123 deletions

View File

@ -100,84 +100,72 @@ int CSMDoc::WriteDialogueCollectionStage::setup()
void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& messages) void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& messages)
{ {
ESM::ESMWriter& writer = mState.getWriter();
const CSMWorld::Record<ESM::Dialogue>& topic = mTopics.getRecord (stage); const CSMWorld::Record<ESM::Dialogue>& topic = mTopics.getRecord (stage);
CSMWorld::RecordBase::State state = topic.mState; if (topic.mState == CSMWorld::RecordBase::State_Deleted)
if (state==CSMWorld::RecordBase::State_Deleted)
{ {
// if the topic is deleted, we do not need to bother with INFO records. // if the topic is deleted, we do not need to bother with INFO records.
ESM::Dialogue dialogue = topic.get();
dialogue.mIsDeleted = true;
/// \todo wrote record with delete flag writer.startRecord(dialogue.sRecordId);
dialogue.save(writer);
writer.endRecord(dialogue.sRecordId);
return; return;
} }
// Test, if we need to save anything associated info records. // Test, if we need to save anything associated info records.
bool infoModified = false; bool infoModified = false;
CSMWorld::InfoCollection::Range range = mInfos.getTopicRange (topic.get().mId); CSMWorld::InfoCollection::Range range = mInfos.getTopicRange (topic.get().mId);
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter) for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter)
{ {
CSMWorld::RecordBase::State state = iter->mState; if (topic.isModified() || iter->mState == CSMWorld::RecordBase::State_Deleted)
if (state==CSMWorld::RecordBase::State_Modified ||
state==CSMWorld::RecordBase::State_ModifiedOnly ||
state==CSMWorld::RecordBase::State_Deleted)
{ {
infoModified = true; infoModified = true;
break; break;
} }
} }
if (state==CSMWorld::RecordBase::State_Modified || if (topic.isModified() || infoModified)
state==CSMWorld::RecordBase::State_ModifiedOnly ||
infoModified)
{ {
mState.getWriter().startRecord (topic.mModified.sRecordId); ESM::Dialogue dialogue = topic.get();
mState.getWriter().writeHNCString ("NAME", topic.mModified.mId);
topic.mModified.save (mState.getWriter()); writer.startRecord (dialogue.sRecordId);
mState.getWriter().endRecord (topic.mModified.sRecordId); dialogue.save (writer);
writer.endRecord (dialogue.sRecordId);
// write modified selected info records // write modified selected info records
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter)
++iter)
{ {
CSMWorld::RecordBase::State state = iter->mState; if (iter->isModified() || iter->mState == CSMWorld::RecordBase::State_Deleted)
if (state==CSMWorld::RecordBase::State_Deleted)
{
/// \todo wrote record with delete flag
}
else if (state==CSMWorld::RecordBase::State_Modified ||
state==CSMWorld::RecordBase::State_ModifiedOnly)
{ {
ESM::DialInfo info = iter->get(); ESM::DialInfo info = iter->get();
info.mId = info.mId.substr (info.mId.find_last_of ('#')+1); info.mId = info.mId.substr (info.mId.find_last_of ('#')+1);
info.mIsDeleted = (iter->mState == CSMWorld::RecordBase::State_Deleted);
info.mPrev = "";
if (iter!=range.first) if (iter!=range.first)
{ {
CSMWorld::InfoCollection::RecordConstIterator prev = iter; CSMWorld::InfoCollection::RecordConstIterator prev = iter;
--prev; --prev;
info.mPrev = info.mPrev = prev->get().mId.substr (prev->get().mId.find_last_of ('#')+1);
prev->mModified.mId.substr (prev->mModified.mId.find_last_of ('#')+1);
} }
CSMWorld::InfoCollection::RecordConstIterator next = iter; CSMWorld::InfoCollection::RecordConstIterator next = iter;
++next; ++next;
info.mNext = "";
if (next!=range.second) if (next!=range.second)
{ {
info.mNext = info.mNext = next->get().mId.substr (next->get().mId.find_last_of ('#')+1);
next->mModified.mId.substr (next->mModified.mId.find_last_of ('#')+1);
} }
mState.getWriter().startRecord (info.sRecordId); writer.startRecord (info.sRecordId);
mState.getWriter().writeHNCString ("INAM", info.mId); info.save (writer);
info.save (mState.getWriter()); writer.endRecord (info.sRecordId);
mState.getWriter().endRecord (info.sRecordId);
} }
} }
} }
@ -269,36 +257,35 @@ int CSMDoc::WriteCellCollectionStage::setup()
void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
{ {
const CSMWorld::Record<CSMWorld::Cell>& cell = ESM::ESMWriter& writer = mState.getWriter();
mDocument.getData().getCells().getRecord (stage); const CSMWorld::Record<CSMWorld::Cell>& cell = mDocument.getData().getCells().getRecord (stage);
std::map<std::string, std::deque<int> >::const_iterator references = std::map<std::string, std::deque<int> >::const_iterator references =
mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId)); mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId));
if (cell.mState==CSMWorld::RecordBase::State_Modified || if (cell.isModified() ||
cell.mState==CSMWorld::RecordBase::State_ModifiedOnly || cell.mState == CSMWorld::RecordBase::State_Deleted ||
references!=mState.getSubRecords().end()) references!=mState.getSubRecords().end())
{ {
bool interior = cell.get().mId.substr (0, 1)!="#"; CSMWorld::Cell cellRecord = cell.get();
bool interior = cellRecord.mId.substr (0, 1)!="#";
// write cell data // write cell data
mState.getWriter().startRecord (cell.mModified.sRecordId); writer.startRecord (cellRecord.sRecordId);
mState.getWriter().writeHNOCString ("NAME", cell.get().mName);
ESM::Cell cell2 = cell.get();
if (interior) if (interior)
cell2.mData.mFlags |= ESM::Cell::Interior; cellRecord.mData.mFlags |= ESM::Cell::Interior;
else else
{ {
cell2.mData.mFlags &= ~ESM::Cell::Interior; cellRecord.mData.mFlags &= ~ESM::Cell::Interior;
std::istringstream stream (cell.get().mId.c_str()); std::istringstream stream (cellRecord.mId.c_str());
char ignore; char ignore;
stream >> ignore >> cell2.mData.mX >> cell2.mData.mY; stream >> ignore >> cellRecord.mData.mX >> cellRecord.mData.mY;
} }
cell2.save (mState.getWriter());
cellRecord.mIsDeleted = (cell.mState == CSMWorld::RecordBase::State_Deleted);
cellRecord.save (writer);
// write references // write references
if (references!=mState.getSubRecords().end()) if (references!=mState.getSubRecords().end())
@ -309,24 +296,25 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
const CSMWorld::Record<CSMWorld::CellRef>& ref = const CSMWorld::Record<CSMWorld::CellRef>& ref =
mDocument.getData().getReferences().getRecord (*iter); mDocument.getData().getReferences().getRecord (*iter);
if (ref.mState==CSMWorld::RecordBase::State_Modified || if (ref.isModified() || ref.mState == CSMWorld::RecordBase::State_Deleted)
ref.mState==CSMWorld::RecordBase::State_ModifiedOnly)
{ {
CSMWorld::CellRef refRecord = ref.get();
// recalculate the ref's cell location // recalculate the ref's cell location
std::ostringstream stream; std::ostringstream stream;
if (!interior) if (!interior)
{ {
std::pair<int, int> index = ref.get().getCellIndex(); std::pair<int, int> index = refRecord.getCellIndex();
stream << "#" << index.first << " " << index.second; stream << "#" << index.first << " " << index.second;
} }
// An empty mOriginalCell is meant to indicate that it is the same as // An empty mOriginalCell is meant to indicate that it is the same as
// the current cell. It is possible that a moved ref is moved again. // the current cell. It is possible that a moved ref is moved again.
if ((ref.get().mOriginalCell.empty() ? ref.get().mCell : ref.get().mOriginalCell) if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell)
!= stream.str() && !interior) != stream.str() && !interior)
{ {
ESM::MovedCellRef moved; ESM::MovedCellRef moved;
moved.mRefNum = ref.get().mRefNum; moved.mRefNum = refRecord.mRefNum;
// Need to fill mTarget with the ref's new position. // Need to fill mTarget with the ref's new position.
std::istringstream istream (stream.str().c_str()); std::istringstream istream (stream.str().c_str());
@ -334,24 +322,17 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
char ignore; char ignore;
istream >> ignore >> moved.mTarget[0] >> moved.mTarget[1]; istream >> ignore >> moved.mTarget[0] >> moved.mTarget[1];
ref.get().mRefNum.save (mState.getWriter(), false, "MVRF"); refRecord.mRefNum.save (writer, false, "MVRF");
mState.getWriter().writeHNT ("CNDT", moved.mTarget, 8); writer.writeHNT ("CNDT", moved.mTarget, 8);
} }
ref.get().save (mState.getWriter()); refRecord.mIsDeleted = (ref.mState == CSMWorld::RecordBase::State_Deleted);
} refRecord.save (writer);
else if (ref.mState==CSMWorld::RecordBase::State_Deleted)
{
/// \todo write record with delete flag
} }
} }
} }
mState.getWriter().endRecord (cell.mModified.sRecordId); writer.endRecord (cellRecord.sRecordId);
}
else if (cell.mState==CSMWorld::RecordBase::State_Deleted)
{
/// \todo write record with delete flag
} }
} }
@ -368,11 +349,11 @@ int CSMDoc::WritePathgridCollectionStage::setup()
void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& messages) void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& messages)
{ {
const CSMWorld::Record<CSMWorld::Pathgrid>& pathgrid = ESM::ESMWriter& writer = mState.getWriter();
const CSMWorld::Record<CSMWorld::Pathgrid>& pathgrid =
mDocument.getData().getPathgrids().getRecord (stage); mDocument.getData().getPathgrids().getRecord (stage);
if (pathgrid.mState==CSMWorld::RecordBase::State_Modified || if (pathgrid.isModified() || pathgrid.mState == CSMWorld::RecordBase::State_Deleted)
pathgrid.mState==CSMWorld::RecordBase::State_ModifiedOnly)
{ {
CSMWorld::Pathgrid record = pathgrid.get(); CSMWorld::Pathgrid record = pathgrid.get();
@ -385,15 +366,10 @@ void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& message
else else
record.mCell = record.mId; record.mCell = record.mId;
mState.getWriter().startRecord (record.sRecordId); record.mIsDeleted = (pathgrid.mState == CSMWorld::RecordBase::State_Deleted);
writer.startRecord (record.sRecordId);
record.save (mState.getWriter()); record.save (writer);
writer.endRecord (record.sRecordId);
mState.getWriter().endRecord (record.sRecordId);
}
else if (pathgrid.mState==CSMWorld::RecordBase::State_Deleted)
{
/// \todo write record with delete flag
} }
} }
@ -410,25 +386,18 @@ int CSMDoc::WriteLandCollectionStage::setup()
void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages)
{ {
const CSMWorld::Record<CSMWorld::Land>& land = ESM::ESMWriter& writer = mState.getWriter();
const CSMWorld::Record<CSMWorld::Land>& land =
mDocument.getData().getLand().getRecord (stage); mDocument.getData().getLand().getRecord (stage);
if (land.mState==CSMWorld::RecordBase::State_Modified || if (land.isModified() || land.mState == CSMWorld::RecordBase::State_Deleted)
land.mState==CSMWorld::RecordBase::State_ModifiedOnly)
{ {
CSMWorld::Land record = land.get(); CSMWorld::Land record = land.get();
mState.getWriter().startRecord (record.mLand->sRecordId); record.mLand->mIsDeleted = (land.mState == CSMWorld::RecordBase::State_Deleted);
writer.startRecord (record.mLand->sRecordId);
record.mLand->save (mState.getWriter()); record.mLand->save (writer);
if(record.mLand->mLandData) writer.endRecord (record.mLand->sRecordId);
record.mLand->mLandData->save (mState.getWriter());
mState.getWriter().endRecord (record.mLand->sRecordId);
}
else if (land.mState==CSMWorld::RecordBase::State_Deleted)
{
/// \todo write record with delete flag
} }
} }
@ -445,23 +414,18 @@ int CSMDoc::WriteLandTextureCollectionStage::setup()
void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& messages) void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& messages)
{ {
const CSMWorld::Record<CSMWorld::LandTexture>& landTexture = ESM::ESMWriter& writer = mState.getWriter();
const CSMWorld::Record<CSMWorld::LandTexture>& landTexture =
mDocument.getData().getLandTextures().getRecord (stage); mDocument.getData().getLandTextures().getRecord (stage);
if (landTexture.mState==CSMWorld::RecordBase::State_Modified || if (landTexture.isModified() || landTexture.mState == CSMWorld::RecordBase::State_Deleted)
landTexture.mState==CSMWorld::RecordBase::State_ModifiedOnly)
{ {
CSMWorld::LandTexture record = landTexture.get(); CSMWorld::LandTexture record = landTexture.get();
record.mIsDeleted = (landTexture.mState == CSMWorld::RecordBase::State_Deleted);
mState.getWriter().startRecord (record.sRecordId); writer.startRecord (record.sRecordId);
record.save (writer);
record.save (mState.getWriter()); writer.endRecord (record.sRecordId);
mState.getWriter().endRecord (record.sRecordId);
}
else if (landTexture.mState==CSMWorld::RecordBase::State_Deleted)
{
/// \todo write record with delete flag
} }
} }

View File

@ -100,26 +100,18 @@ namespace CSMDoc
if (CSMWorld::getScopeFromId (mCollection.getRecord (stage).get().mId)!=mScope) if (CSMWorld::getScopeFromId (mCollection.getRecord (stage).get().mId)!=mScope)
return; return;
ESM::ESMWriter& writer = mState.getWriter();
CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState; CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState;
CollectionT::ESXRecord record = mCollection.getRecord (stage).get();
if (state==CSMWorld::RecordBase::State_Modified || if (state == CSMWorld::RecordBase::State_Modified ||
state==CSMWorld::RecordBase::State_ModifiedOnly) state == CSMWorld::RecordBase::State_ModifiedOnly ||
state == CSMWorld::RecordBase::State_Deleted)
{ {
// FIXME: A quick Workaround to support records which should not write CSMWorld::setRecordDeleted (record, state == CSMWorld::RecordBase::State_Deleted);
// NAME, including SKIL, MGEF and SCPT. If there are many more writer.startRecord (record.sRecordId);
// idcollection records that doesn't use NAME then a more generic record.save (writer);
// solution may be required. writer.endRecord (record.sRecordId);
uint32_t name = mCollection.getRecord (stage).mModified.sRecordId;
mState.getWriter().startRecord (name);
if(name != ESM::REC_SKIL && name != ESM::REC_MGEF && name != ESM::REC_SCPT)
mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage));
mCollection.getRecord (stage).mModified.save (mState.getWriter());
mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId);
}
else if (state==CSMWorld::RecordBase::State_Deleted)
{
/// \todo write record with delete flag
} }
} }

View File

@ -43,6 +43,12 @@ namespace CSMWorld
template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> > template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
class Collection : public CollectionBase class Collection : public CollectionBase
{ {
public:
typedef ESXRecordT ESXRecord;
private:
std::vector<Record<ESXRecordT> > mRecords; std::vector<Record<ESXRecordT> > mRecords;
std::map<std::string, int> mIndex; std::map<std::string, int> mIndex;
std::vector<Column<ESXRecordT> *> mColumns; std::vector<Column<ESXRecordT> *> mColumns;

View File

@ -43,3 +43,27 @@ bool CSMWorld::isRecordDeleted(const ESM::Skill &skill)
{ {
return false; return false;
} }
template<>
void CSMWorld::setRecordDeleted(CSMWorld::Land &land, bool isDeleted)
{
land.mLand->mIsDeleted = isDeleted;
}
template<>
void CSMWorld::setRecordDeleted(ESM::GameSetting &setting, bool isDeleted)
{
// GameSetting doesn't have a Deleted flag
}
template<>
void CSMWorld::setRecordDeleted(ESM::MagicEffect &effect, bool isDeleted)
{
// MagicEffect doesn't have a Deleted flag
}
template<>
void CSMWorld::setRecordDeleted(ESM::Skill &skill, bool isDeleted)
{
// Skill doesn't have a Deleted flag
}

View File

@ -177,6 +177,22 @@ namespace CSMWorld
bool isRecordDeleted(const ESM::MagicEffect &effect); bool isRecordDeleted(const ESM::MagicEffect &effect);
template<> template<>
bool isRecordDeleted(const ESM::Skill &skill); bool isRecordDeleted(const ESM::Skill &skill);
// ... and also a separate method for setting the deleted flag of a record
template<typename ESXRecordT>
void setRecordDeleted(ESXRecordT &record, bool isDeleted = false)
{
record.mIsDeleted = isDeleted;
}
template<>
void setRecordDeleted(Land &land, bool isDeleted);
template<>
void setRecordDeleted(ESM::GameSetting &setting, bool isDeleted);
template<>
void setRecordDeleted(ESM::MagicEffect &effect, bool isDeleted);
template<>
void setRecordDeleted(ESM::Skill &skill, bool isDeleted);
} }
#endif #endif