Merge remote-tracking branch 'aesylwinn/LLmerge'

new-script-api
Marc Zinnschlag 7 years ago
commit bdabace7e2

@ -38,9 +38,10 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr
appendStage (new MergeRefIdsStage (mState)); appendStage (new MergeRefIdsStage (mState));
appendStage (new MergeReferencesStage (mState)); appendStage (new MergeReferencesStage (mState));
appendStage (new MergeReferencesStage (mState)); appendStage (new MergeReferencesStage (mState));
appendStage (new ListLandTexturesMergeStage (mState)); appendStage (new PopulateLandTexturesMergeStage (mState));
appendStage (new MergeLandTexturesStage (mState));
appendStage (new MergeLandStage (mState)); appendStage (new MergeLandStage (mState));
appendStage (new FixLandsAndLandTexturesMergeStage (mState));
appendStage (new CleanupLandTexturesMergeStage (mState));
appendStage (new FinishMergedDocumentStage (mState, encoding)); appendStage (new FinishMergedDocumentStage (mState, encoding));
} }

@ -8,7 +8,9 @@
#include "mergestate.hpp" #include "mergestate.hpp"
#include "../doc/document.hpp" #include "../doc/document.hpp"
#include "../world/commands.hpp"
#include "../world/data.hpp" #include "../world/data.hpp"
#include "../world/idtable.hpp"
CSMTools::StartMergeStage::StartMergeStage (MergeState& state) CSMTools::StartMergeStage::StartMergeStage (MergeState& state)
@ -109,149 +111,105 @@ void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messa
} }
CSMTools::ListLandTexturesMergeStage::ListLandTexturesMergeStage (MergeState& state) CSMTools::PopulateLandTexturesMergeStage::PopulateLandTexturesMergeStage (MergeState& state)
: mState (state) : mState (state)
{} {
}
int CSMTools::ListLandTexturesMergeStage::setup() int CSMTools::PopulateLandTexturesMergeStage::setup()
{ {
return mState.mSource.getData().getLand().getSize(); return mState.mSource.getData().getLandTextures().getSize();
} }
void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) void CSMTools::PopulateLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
{ {
const CSMWorld::Record<CSMWorld::Land>& record = const CSMWorld::Record<CSMWorld::LandTexture>& record =
mState.mSource.getData().getLand().getRecord (stage); mState.mSource.getData().getLandTextures().getRecord (stage);
if (!record.isDeleted()) if (!record.isDeleted())
{ {
const CSMWorld::Land& land = record.get(); mState.mTarget->getData().getLandTextures().appendRecord(record);
// make sure record is loaded
land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX);
if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX))
{
// list texture indices
std::pair<uint16_t, int> key;
key.second = land.mPlugin;
for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i)
{
key.first = data->mTextures[i];
mState.mTextureIndices[key] = -1;
}
}
} }
} }
CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state) CSMTools::MergeLandStage::MergeLandStage (MergeState& state)
: mState (state), mNext (mState.mTextureIndices.end()) : mState (state)
{}
int CSMTools::MergeLandTexturesStage::setup()
{ {
// Should use the size of mState.mTextureIndices instead, but that is not available at this
// point. Unless there are any errors in the land and land texture records this will not
// make a difference.
return mState.mSource.getData().getLandTextures().getSize();
} }
void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages) int CSMTools::MergeLandStage::setup()
{ {
if (stage==0) return mState.mSource.getData().getLand().getSize();
mNext = mState.mTextureIndices.begin(); }
bool found = false; void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<CSMWorld::Land>& record =
mState.mSource.getData().getLand().getRecord (stage);
do if (!record.isDeleted())
{ {
if (mNext==mState.mTextureIndices.end()) mState.mTarget->getData().getLand().appendRecord (record);
return;
mNext->second = stage+1;
std::ostringstream stream;
stream << mNext->first.first-1 << "_" << mNext->first.second;
int index = mState.mSource.getData().getLandTextures().searchId (stream.str());
if (index!=-1)
{
CSMWorld::LandTexture texture =
mState.mSource.getData().getLandTextures().getRecord (index).get();
stream.clear();
stream << mNext->second-1 << "_0";
texture.mIndex = mNext->second-1;
texture.mId = stream.str();
CSMWorld::Record<CSMWorld::LandTexture> newRecord (
CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture);
mState.mTarget->getData().getLandTextures().appendRecord (newRecord);
found = true;
}
++mNext;
} }
while (!found);
} }
CSMTools::MergeLandStage::MergeLandStage (MergeState& state) : mState (state) {} CSMTools::FixLandsAndLandTexturesMergeStage::FixLandsAndLandTexturesMergeStage (MergeState& state)
: mState (state)
{
}
int CSMTools::MergeLandStage::setup() int CSMTools::FixLandsAndLandTexturesMergeStage::setup()
{ {
// We will have no more than the source
return mState.mSource.getData().getLand().getSize(); return mState.mSource.getData().getLand().getSize();
} }
void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages) void CSMTools::FixLandsAndLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
{ {
const CSMWorld::Record<CSMWorld::Land>& record = if (stage < mState.mTarget->getData().getLand().getSize())
mState.mSource.getData().getLand().getRecord (stage);
if (!record.isDeleted())
{ {
const CSMWorld::Land& land = record.get(); CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&>(
*mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_Lands));
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&>(
*mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures));
land.loadData (ESM::Land::DATA_VCLR | ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | std::string id = mState.mTarget->getData().getLand().getId(stage);
ESM::Land::DATA_VTEX);
CSMWorld::Land newLand (land); CSMWorld::TouchLandCommand cmd(landTable, ltexTable, id);
cmd.redo();
newLand.mPlugin = 0; // Get rid of base data
const CSMWorld::Record<CSMWorld::Land>& oldRecord =
mState.mTarget->getData().getLand().getRecord (stage);
if (land.mDataTypes & ESM::Land::DATA_VTEX) CSMWorld::Record<CSMWorld::Land> newRecord(CSMWorld::RecordBase::State_ModifiedOnly,
{ nullptr, &oldRecord.get());
// adjust land texture references
if (ESM::Land::LandData *data = newLand.getLandData())
{
std::pair<uint16_t, int> key;
key.second = land.mPlugin;
for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i) mState.mTarget->getData().getLand().setRecord(stage, newRecord);
{ }
key.first = data->mTextures[i]; }
std::map<std::pair<uint16_t, int>, int>::const_iterator iter =
mState.mTextureIndices.find (key);
if (iter!=mState.mTextureIndices.end()) CSMTools::CleanupLandTexturesMergeStage::CleanupLandTexturesMergeStage (MergeState& state)
data->mTextures[i] = iter->second; : mState (state)
else {
data->mTextures[i] = 0; }
}
}
}
CSMWorld::Record<CSMWorld::Land> newRecord ( int CSMTools::CleanupLandTexturesMergeStage::setup()
CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand); {
return 1;
}
mState.mTarget->getData().getLand().appendRecord (newRecord); void CSMTools::CleanupLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
{
auto& landTextures = mState.mTarget->getData().getLandTextures();
for (int i = 0; i < landTextures.getSize(); )
{
if (!landTextures.getRecord(i).isModified())
landTextures.removeRows(i, 1);
else
++i;
} }
} }

@ -116,13 +116,14 @@ namespace CSMTools
///< Messages resulting from this stage will be appended to \a messages. ///< Messages resulting from this stage will be appended to \a messages.
}; };
class ListLandTexturesMergeStage : public CSMDoc::Stage /// Adds all land texture records that could potentially be referenced when merging
class PopulateLandTexturesMergeStage : public CSMDoc::Stage
{ {
MergeState& mState; MergeState& mState;
public: public:
ListLandTexturesMergeStage (MergeState& state); PopulateLandTexturesMergeStage (MergeState& state);
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
@ -131,14 +132,13 @@ namespace CSMTools
///< Messages resulting from this stage will be appended to \a messages. ///< Messages resulting from this stage will be appended to \a messages.
}; };
class MergeLandTexturesStage : public CSMDoc::Stage class MergeLandStage : public CSMDoc::Stage
{ {
MergeState& mState; MergeState& mState;
std::map<std::pair<uint16_t, int>, int>::iterator mNext;
public: public:
MergeLandTexturesStage (MergeState& state); MergeLandStage (MergeState& state);
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
@ -147,13 +147,32 @@ namespace CSMTools
///< Messages resulting from this stage will be appended to \a messages. ///< Messages resulting from this stage will be appended to \a messages.
}; };
class MergeLandStage : public CSMDoc::Stage /// During this stage, the complex process of combining LandTextures from
/// potentially multiple plugins is undertaken.
class FixLandsAndLandTexturesMergeStage : public CSMDoc::Stage
{ {
MergeState& mState; MergeState& mState;
public: public:
MergeLandStage (MergeState& state); FixLandsAndLandTexturesMergeStage (MergeState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
/// Removes base LandTexture records. This gets rid of the base records previously
/// needed in FixLandsAndLandTexturesMergeStage.
class CleanupLandTexturesMergeStage : public CSMDoc::Stage
{
MergeState& mState;
public:
CleanupLandTexturesMergeStage (MergeState& state);
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps

@ -108,7 +108,7 @@ namespace CSMWorld
throw std::runtime_error("invalid land map LOD data"); throw std::runtime_error("invalid land map LOD data");
Land copy = record.get(); Land copy = record.get();
copy.setDataLoaded(Land::DATA_WNAM); copy.add(Land::DATA_WNAM);
for (int i = 0; i < values.size(); ++i) for (int i = 0; i < values.size(); ++i)
{ {
@ -155,7 +155,7 @@ namespace CSMWorld
throw std::runtime_error("invalid land normals data"); throw std::runtime_error("invalid land normals data");
Land copy = record.get(); Land copy = record.get();
copy.setDataLoaded(Land::DATA_VNML); copy.add(Land::DATA_VNML);
for (int i = 0; i < values.size(); ++i) for (int i = 0; i < values.size(); ++i)
{ {
@ -202,7 +202,7 @@ namespace CSMWorld
throw std::runtime_error("invalid land heights data"); throw std::runtime_error("invalid land heights data");
Land copy = record.get(); Land copy = record.get();
copy.setDataLoaded(Land::DATA_VHGT); copy.add(Land::DATA_VHGT);
for (int i = 0; i < values.size(); ++i) for (int i = 0; i < values.size(); ++i)
{ {
@ -249,7 +249,7 @@ namespace CSMWorld
throw std::runtime_error("invalid land colours data"); throw std::runtime_error("invalid land colours data");
Land copy = record.get(); Land copy = record.get();
copy.setDataLoaded(Land::DATA_VCLR); copy.add(Land::DATA_VCLR);
for (int i = 0; i < values.size(); ++i) for (int i = 0; i < values.size(); ++i)
{ {
@ -296,7 +296,7 @@ namespace CSMWorld
throw std::runtime_error("invalid land textures data"); throw std::runtime_error("invalid land textures data");
Land copy = record.get(); Land copy = record.get();
copy.setDataLoaded(Land::DATA_VTEX); copy.add(Land::DATA_VTEX);
for (int i = 0; i < values.size(); ++i) for (int i = 0; i < values.size(); ++i)
{ {

@ -44,6 +44,15 @@ namespace CSMWorld
bool mChanged; bool mChanged;
}; };
/// \brief Adds LandTexture records and modifies texture indices as needed.
///
/// LandTexture records are different from other types of records, because
/// they only effect the current plugin. Thus, when modifying or copying
/// a Land record, all of the LandTexture records referenced need to be
/// added to the current plugin. Since these newly added LandTextures could
/// have indices that conflict with pre-existing LandTextures in the current
/// plugin, the indices might have to be changed, both for the newly added
/// LandRecord and within the Land record.
class ImportLandTexturesCommand : public QUndoCommand class ImportLandTexturesCommand : public QUndoCommand
{ {
public: public:
@ -71,6 +80,9 @@ namespace CSMWorld
std::vector<std::string> mCreatedTextures; std::vector<std::string> mCreatedTextures;
}; };
/// \brief This command is used to fix LandTexture records and texture
/// indices after cloning a Land. See ImportLandTexturesCommand for
/// details.
class CopyLandTexturesCommand : public ImportLandTexturesCommand class CopyLandTexturesCommand : public ImportLandTexturesCommand
{ {
public: public:
@ -90,6 +102,9 @@ namespace CSMWorld
std::string mDestId; std::string mDestId;
}; };
/// \brief This command brings a land record into the current plugin, adding
/// LandTexture records and modifying texture indices as needed.
/// \note See ImportLandTextures for more details.
class TouchLandCommand : public ImportLandTexturesCommand class TouchLandCommand : public ImportLandTexturesCommand
{ {
public: public:

@ -336,7 +336,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import
int oldRow = idCollection()->searchId(id); int oldRow = idCollection()->searchId(id);
// If it does not exist or it is in the current plugin, it can be skipped. // If it does not exist or it is in the current plugin, it can be skipped.
if (oldRow <= 0 || plugin == 0) if (oldRow < 0 || plugin == 0)
{ {
results.recordMapping.push_back(std::make_pair(id, id)); results.recordMapping.push_back(std::make_pair(id, id));
continue; continue;

@ -315,16 +315,7 @@ namespace ESM
bool Land::isDataLoaded(int flags) const bool Land::isDataLoaded(int flags) const
{ {
return mLandData && (mLandData->mDataLoaded & flags) == (flags & mDataTypes); return mLandData && (mLandData->mDataLoaded & flags) == flags;
}
void Land::setDataLoaded(int flags)
{
if (!mLandData)
mLandData = new LandData;
mDataTypes |= flags;
mLandData->mDataLoaded |= flags;
} }
Land::Land (const Land& land) Land::Land (const Land& land)

@ -132,7 +132,6 @@ struct Land
void unloadData() const; void unloadData() const;
/// Check if given data type is loaded /// Check if given data type is loaded
/// @note We only check data types that *can* be loaded (present in mDataTypes)
bool isDataLoaded(int flags) const; bool isDataLoaded(int flags) const;
/// Sets the flags and creates a LandData if needed /// Sets the flags and creates a LandData if needed

Loading…
Cancel
Save