mirror of https://github.com/OpenMW/openmw.git
Merge branch 'cc9cii' into Feature-1278
Conflicts: apps/opencs/CMakeLists.txt apps/opencs/model/world/nestedcoladapterimp.cpp apps/opencs/view/render/cell.cpp apps/opencs/view/render/worldspacewidget.cpppull/1955/head
commit
9716b671f1
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} apps components)
|
||||
|
||||
if [[ $OUTPUT ]] ; then
|
||||
echo "Error: Tab characters found!"
|
||||
echo $OUTPUT
|
||||
exit 1
|
||||
fi
|
@ -0,0 +1,16 @@
|
||||
Description
|
||||
===========
|
||||
|
||||
Your pull request description should include (if applicable):
|
||||
|
||||
* A link back to the bug report or forum discussion that prompted the change
|
||||
* Summary of the changes made
|
||||
* Reasoning / motivation behind the change
|
||||
* What testing you have carried out to verify the change
|
||||
|
||||
Other notes
|
||||
===========
|
||||
|
||||
* Separate your work into multiple pull requests whenever possible. As a rule of thumb, each feature and each bugfix should go into a separate PR, unless they are closely related or dependent upon each other. Small pull requests are easier to review, and are less likely to require further changes before we can merge them. A "mega" pull request with lots of unrelated commits in it is likely to get held up in review for a long time.
|
||||
* Feel free to submit incomplete pull requests. Even if the work can not be merged yet, pull requests are a great place to collect early feedback. Just make sure to mark it as *[Incomplete]* or *[Do not merge yet]* in the title.
|
||||
* If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards).
|
@ -0,0 +1,19 @@
|
||||
set(NIFTEST
|
||||
niftest.cpp
|
||||
)
|
||||
source_group(components\\nif\\tests FILES ${NIFTEST})
|
||||
|
||||
# Main executable
|
||||
add_executable(niftest
|
||||
${NIFTEST}
|
||||
)
|
||||
|
||||
target_link_libraries(niftest
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
components
|
||||
)
|
||||
|
||||
if (BUILD_WITH_CODE_COVERAGE)
|
||||
add_definitions (--coverage)
|
||||
target_link_libraries(niftest gcov)
|
||||
endif()
|
@ -0,0 +1,165 @@
|
||||
///Program to test .nif files both on the FileSystem and in BSA archives.
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <components/nif/niffile.hpp>
|
||||
#include <components/files/constrainedfilestream.hpp>
|
||||
#include <components/vfs/manager.hpp>
|
||||
#include <components/vfs/bsaarchive.hpp>
|
||||
#include <components/vfs/filesystemarchive.hpp>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
// Create local aliases for brevity
|
||||
namespace bpo = boost::program_options;
|
||||
namespace bfs = boost::filesystem;
|
||||
|
||||
///See if the file has the named extension
|
||||
bool hasExtension(std::string filename, std::string extensionToFind)
|
||||
{
|
||||
std::string extension = filename.substr(filename.find_last_of(".")+1);
|
||||
|
||||
//Convert strings to lower case for comparison
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||
std::transform(extensionToFind.begin(), extensionToFind.end(), extensionToFind.begin(), ::tolower);
|
||||
|
||||
if(extension == extensionToFind)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
///See if the file has the "nif" extension.
|
||||
bool isNIF(std::string filename)
|
||||
{
|
||||
return hasExtension(filename,"nif");
|
||||
}
|
||||
///See if the file has the "bsa" extension.
|
||||
bool isBSA(std::string filename)
|
||||
{
|
||||
return hasExtension(filename,"bsa");
|
||||
}
|
||||
|
||||
/// Check all the nif files in a given VFS::Archive
|
||||
/// \note Takes ownership!
|
||||
/// \note Can not read a bsa file inside of a bsa file.
|
||||
void readVFS(VFS::Archive* anArchive,std::string archivePath = "")
|
||||
{
|
||||
VFS::Manager myManager(true);
|
||||
myManager.addArchive(anArchive);
|
||||
myManager.buildIndex();
|
||||
|
||||
std::map<std::string, VFS::File*> files=myManager.getIndex();
|
||||
for(std::map<std::string, VFS::File*>::const_iterator it=files.begin(); it!=files.end(); ++it)
|
||||
{
|
||||
std::string name = it->first;
|
||||
|
||||
try{
|
||||
if(isNIF(name))
|
||||
{
|
||||
// std::cout << "Decoding: " << name << std::endl;
|
||||
Nif::NIFFile temp_nif(myManager.get(name),archivePath+name);
|
||||
}
|
||||
else if(isBSA(name))
|
||||
{
|
||||
if(!archivePath.empty() && !isBSA(archivePath))
|
||||
{
|
||||
// std::cout << "Reading BSA File: " << name << std::endl;
|
||||
readVFS(new VFS::BsaArchive(archivePath+name),archivePath+name+"/");
|
||||
// std::cout << "Done with BSA File: " << name << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "ERROR, an exception has occurred: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> parseOptions (int argc, char** argv)
|
||||
{
|
||||
bpo::options_description desc("Ensure that OpenMW can use the provided NIF and BSA files\n\n"
|
||||
"Usages:\n"
|
||||
" niftool <nif files, BSA files, or directories>\n"
|
||||
" Scan the file or directories for nif errors.\n\n"
|
||||
"Allowed options");
|
||||
desc.add_options()
|
||||
("help,h", "print help message.")
|
||||
("input-file", bpo::value< std::vector<std::string> >(), "input file")
|
||||
;
|
||||
|
||||
//Default option if none provided
|
||||
bpo::positional_options_description p;
|
||||
p.add("input-file", -1);
|
||||
|
||||
bpo::variables_map variables;
|
||||
try
|
||||
{
|
||||
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv).
|
||||
options(desc).positional(p).run();
|
||||
bpo::store(valid_opts, variables);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
std::cout << "ERROR parsing arguments: " << e.what() << "\n\n"
|
||||
<< desc << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bpo::notify(variables);
|
||||
if (variables.count ("help"))
|
||||
{
|
||||
std::cout << desc << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
if (variables.count("input-file"))
|
||||
{
|
||||
return variables["input-file"].as< std::vector<std::string> >();
|
||||
}
|
||||
|
||||
std::cout << "No input files or directories specified!" << std::endl;
|
||||
std::cout << desc << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::vector<std::string> files = parseOptions (argc, argv);
|
||||
|
||||
// std::cout << "Reading Files" << std::endl;
|
||||
for(std::vector<std::string>::const_iterator it=files.begin(); it!=files.end(); ++it)
|
||||
{
|
||||
std::string name = *it;
|
||||
|
||||
try{
|
||||
if(isNIF(name))
|
||||
{
|
||||
//std::cout << "Decoding: " << name << std::endl;
|
||||
Nif::NIFFile temp_nif(Files::openConstrainedFileStream(name.c_str()),name);
|
||||
}
|
||||
else if(isBSA(name))
|
||||
{
|
||||
// std::cout << "Reading BSA File: " << name << std::endl;
|
||||
readVFS(new VFS::BsaArchive(name));
|
||||
}
|
||||
else if(bfs::is_directory(bfs::path(name)))
|
||||
{
|
||||
// std::cout << "Reading All Files in: " << name << std::endl;
|
||||
readVFS(new VFS::FileSystemArchive(name),name);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: \"" << name << "\" is not a nif file, bsa file, or directory!" << std::endl;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "ERROR, an exception has occurred: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
|
||||
#include "stage.hpp"
|
||||
|
||||
CSMDoc::Stage::~Stage() {}
|
||||
|
||||
void CSMDoc::Stage::updateUserSetting (const QString& name, const QStringList& value) {}
|
||||
|
@ -0,0 +1,133 @@
|
||||
#include "magiceffectcheck.hpp"
|
||||
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
|
||||
#include "../world/resources.hpp"
|
||||
#include "../world/data.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
void addMessageIfNotEmpty(CSMDoc::Messages &messages, const CSMWorld::UniversalId &id, const std::string text)
|
||||
{
|
||||
if (!text.empty())
|
||||
{
|
||||
messages.push_back(std::make_pair(id, text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CSMTools::MagicEffectCheckStage::isTextureExists(const std::string &texture, bool isIcon) const
|
||||
{
|
||||
const CSMWorld::Resources &textures = isIcon ? mIcons : mTextures;
|
||||
bool exists = false;
|
||||
|
||||
if (textures.searchId(texture) != -1)
|
||||
{
|
||||
exists = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string ddsTexture = texture;
|
||||
if (Misc::ResourceHelpers::changeExtensionToDds(ddsTexture) && textures.searchId(ddsTexture) != -1)
|
||||
{
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
std::string CSMTools::MagicEffectCheckStage::checkReferenceable(const std::string &id,
|
||||
const CSMWorld::UniversalId &type,
|
||||
const std::string &column) const
|
||||
{
|
||||
std::string error;
|
||||
if (!id.empty())
|
||||
{
|
||||
CSMWorld::RefIdData::LocalIndex index = mReferenceables.getDataSet().searchId(id);
|
||||
if (index.first == -1)
|
||||
{
|
||||
error = "No such " + column + " '" + id + "'";
|
||||
}
|
||||
else if (index.second != type.getType())
|
||||
{
|
||||
error = column + " is not of type " + type.getTypeName();
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
std::string CSMTools::MagicEffectCheckStage::checkSound(const std::string &id, const std::string &column) const
|
||||
{
|
||||
std::string error;
|
||||
if (!id.empty() && mSounds.searchId(id) == -1)
|
||||
{
|
||||
error = "No such " + column + " '" + id + "'";
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
CSMTools::MagicEffectCheckStage::MagicEffectCheckStage(const CSMWorld::IdCollection<ESM::MagicEffect> &effects,
|
||||
const CSMWorld::IdCollection<ESM::Sound> &sounds,
|
||||
const CSMWorld::RefIdCollection &referenceables,
|
||||
const CSMWorld::Resources &icons,
|
||||
const CSMWorld::Resources &textures)
|
||||
: mMagicEffects(effects),
|
||||
mSounds(sounds),
|
||||
mReferenceables(referenceables),
|
||||
mIcons(icons),
|
||||
mTextures(textures)
|
||||
{}
|
||||
|
||||
int CSMTools::MagicEffectCheckStage::setup()
|
||||
{
|
||||
return mMagicEffects.getSize();
|
||||
}
|
||||
|
||||
void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messages)
|
||||
{
|
||||
ESM::MagicEffect effect = mMagicEffects.getRecord(stage).get();
|
||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_MagicEffect, effect.mId);
|
||||
|
||||
if (effect.mData.mBaseCost < 0.0f)
|
||||
{
|
||||
messages.push_back(std::make_pair(id, "Base Cost is negative"));
|
||||
}
|
||||
|
||||
if (effect.mIcon.empty())
|
||||
{
|
||||
messages.push_back(std::make_pair(id, "Icon is not specified"));
|
||||
}
|
||||
else if (!isTextureExists(effect.mIcon, true))
|
||||
{
|
||||
messages.push_back(std::make_pair(id, "No such Icon '" + effect.mIcon + "'"));
|
||||
}
|
||||
|
||||
if (!effect.mParticle.empty() && !isTextureExists(effect.mParticle, false))
|
||||
{
|
||||
messages.push_back(std::make_pair(id, "No such Particle '" + effect.mParticle + "'"));
|
||||
}
|
||||
|
||||
addMessageIfNotEmpty(messages,
|
||||
id,
|
||||
checkReferenceable(effect.mCasting, CSMWorld::UniversalId::Type_Static, "Casting Object"));
|
||||
addMessageIfNotEmpty(messages,
|
||||
id,
|
||||
checkReferenceable(effect.mHit, CSMWorld::UniversalId::Type_Static, "Hit Object"));
|
||||
addMessageIfNotEmpty(messages,
|
||||
id,
|
||||
checkReferenceable(effect.mArea, CSMWorld::UniversalId::Type_Static, "Area Object"));
|
||||
addMessageIfNotEmpty(messages,
|
||||
id,
|
||||
checkReferenceable(effect.mBolt, CSMWorld::UniversalId::Type_Weapon, "Bolt Object"));
|
||||
|
||||
addMessageIfNotEmpty(messages, id, checkSound(effect.mCastSound, "Casting Sound"));
|
||||
addMessageIfNotEmpty(messages, id, checkSound(effect.mHitSound, "Hit Sound"));
|
||||
addMessageIfNotEmpty(messages, id, checkSound(effect.mAreaSound, "Area Sound"));
|
||||
addMessageIfNotEmpty(messages, id, checkSound(effect.mBoltSound, "Bolt Sound"));
|
||||
|
||||
if (effect.mDescription.empty())
|
||||
{
|
||||
messages.push_back(std::make_pair(id, "Description is empty"));
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
#ifndef CSM_TOOLS_MAGICEFFECTCHECK_HPP
|
||||
#define CSM_TOOLS_MAGICEFFECTCHECK_HPP
|
||||
|
||||
#include <components/esm/loadmgef.hpp>
|
||||
#include <components/esm/loadsoun.hpp>
|
||||
|
||||
#include "../world/idcollection.hpp"
|
||||
#include "../world/refidcollection.hpp"
|
||||
|
||||
#include "../doc/stage.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class Resources;
|
||||
}
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that magic effect records are internally consistent
|
||||
class MagicEffectCheckStage : public CSMDoc::Stage
|
||||
{
|
||||
const CSMWorld::IdCollection<ESM::MagicEffect> &mMagicEffects;
|
||||
const CSMWorld::IdCollection<ESM::Sound> &mSounds;
|
||||
const CSMWorld::RefIdCollection &mReferenceables;
|
||||
const CSMWorld::Resources &mIcons;
|
||||
const CSMWorld::Resources &mTextures;
|
||||
|
||||
private:
|
||||
bool isTextureExists(const std::string &texture, bool isIcon) const;
|
||||
|
||||
std::string checkReferenceable(const std::string &id,
|
||||
const CSMWorld::UniversalId &type,
|
||||
const std::string &column) const;
|
||||
std::string checkSound(const std::string &id, const std::string &column) const;
|
||||
|
||||
public:
|
||||
MagicEffectCheckStage(const CSMWorld::IdCollection<ESM::MagicEffect> &effects,
|
||||
const CSMWorld::IdCollection<ESM::Sound> &sounds,
|
||||
const CSMWorld::RefIdCollection &referenceables,
|
||||
const CSMWorld::Resources &icons,
|
||||
const CSMWorld::Resources &textures);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
virtual void perform (int stage, CSMDoc::Messages &messages);
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,59 @@
|
||||
|
||||
#include "mergeoperation.hpp"
|
||||
|
||||
#include "../doc/state.hpp"
|
||||
#include "../doc/document.hpp"
|
||||
|
||||
#include "mergestages.hpp"
|
||||
|
||||
CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding)
|
||||
: CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document)
|
||||
{
|
||||
appendStage (new StartMergeStage (mState));
|
||||
|
||||
appendStage (new MergeIdCollectionStage<ESM::Global> (mState, &CSMWorld::Data::getGlobals));
|
||||
appendStage (new MergeIdCollectionStage<ESM::GameSetting> (mState, &CSMWorld::Data::getGmsts));
|
||||
appendStage (new MergeIdCollectionStage<ESM::Skill> (mState, &CSMWorld::Data::getSkills));
|
||||
appendStage (new MergeIdCollectionStage<ESM::Class> (mState, &CSMWorld::Data::getClasses));
|
||||
appendStage (new MergeIdCollectionStage<ESM::Faction> (mState, &CSMWorld::Data::getFactions));
|
||||
appendStage (new MergeIdCollectionStage<ESM::Race> (mState, &CSMWorld::Data::getRaces));
|
||||
appendStage (new MergeIdCollectionStage<ESM::Sound> (mState, &CSMWorld::Data::getSounds));
|
||||
appendStage (new MergeIdCollectionStage<ESM::Script> (mState, &CSMWorld::Data::getScripts));
|
||||
appendStage (new MergeIdCollectionStage<ESM::Region> (mState, &CSMWorld::Data::getRegions));
|
||||
appendStage (new MergeIdCollectionStage<ESM::BirthSign> (mState, &CSMWorld::Data::getBirthsigns));
|
||||
appendStage (new MergeIdCollectionStage<ESM::Spell> (mState, &CSMWorld::Data::getSpells));
|
||||
appendStage (new MergeIdCollectionStage<ESM::Dialogue> (mState, &CSMWorld::Data::getTopics));
|
||||
appendStage (new MergeIdCollectionStage<ESM::Dialogue> (mState, &CSMWorld::Data::getJournals));
|
||||
appendStage (new MergeIdCollectionStage<CSMWorld::Cell> (mState, &CSMWorld::Data::getCells));
|
||||
appendStage (new MergeIdCollectionStage<ESM::Filter> (mState, &CSMWorld::Data::getFilters));
|
||||
appendStage (new MergeIdCollectionStage<ESM::Enchantment> (mState, &CSMWorld::Data::getEnchantments));
|
||||
appendStage (new MergeIdCollectionStage<ESM::BodyPart> (mState, &CSMWorld::Data::getBodyParts));
|
||||
appendStage (new MergeIdCollectionStage<ESM::DebugProfile> (mState, &CSMWorld::Data::getDebugProfiles));
|
||||
appendStage (new MergeIdCollectionStage<ESM::SoundGenerator> (mState, &CSMWorld::Data::getSoundGens));
|
||||
appendStage (new MergeIdCollectionStage<ESM::MagicEffect> (mState, &CSMWorld::Data::getMagicEffects));
|
||||
appendStage (new MergeIdCollectionStage<ESM::StartScript> (mState, &CSMWorld::Data::getStartScripts));
|
||||
appendStage (new MergeIdCollectionStage<CSMWorld::Pathgrid, CSMWorld::SubCellCollection<CSMWorld::Pathgrid> > (mState, &CSMWorld::Data::getPathgrids));
|
||||
appendStage (new MergeIdCollectionStage<CSMWorld::Info, CSMWorld::InfoCollection> (mState, &CSMWorld::Data::getTopicInfos));
|
||||
appendStage (new MergeIdCollectionStage<CSMWorld::Info, CSMWorld::InfoCollection> (mState, &CSMWorld::Data::getJournalInfos));
|
||||
appendStage (new MergeRefIdsStage (mState));
|
||||
appendStage (new MergeReferencesStage (mState));
|
||||
appendStage (new MergeReferencesStage (mState));
|
||||
appendStage (new ListLandTexturesMergeStage (mState));
|
||||
appendStage (new MergeLandTexturesStage (mState));
|
||||
appendStage (new MergeLandStage (mState));
|
||||
|
||||
appendStage (new FinishMergedDocumentStage (mState, encoding));
|
||||
}
|
||||
|
||||
void CSMTools::MergeOperation::setTarget (std::auto_ptr<CSMDoc::Document> document)
|
||||
{
|
||||
mState.mTarget = document;
|
||||
}
|
||||
|
||||
void CSMTools::MergeOperation::operationDone()
|
||||
{
|
||||
CSMDoc::Operation::operationDone();
|
||||
|
||||
if (mState.mCompleted)
|
||||
emit mergeDone (mState.mTarget.release());
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
#ifndef CSM_TOOLS_MERGEOPERATION_H
|
||||
#define CSM_TOOLS_MERGEOPERATION_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
|
||||
#include "../doc/operation.hpp"
|
||||
|
||||
#include "mergestate.hpp"
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
}
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class MergeOperation : public CSMDoc::Operation
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
MergeState mState;
|
||||
|
||||
public:
|
||||
|
||||
MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding);
|
||||
|
||||
/// \attention Do not call this function while a merge is running.
|
||||
void setTarget (std::auto_ptr<CSMDoc::Document> document);
|
||||
|
||||
protected slots:
|
||||
|
||||
virtual void operationDone();
|
||||
|
||||
signals:
|
||||
|
||||
/// \attention When this signal is emitted, *this hands over the ownership of the
|
||||
/// document. This signal must be handled to avoid a leak.
|
||||
void mergeDone (CSMDoc::Document *document);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,258 @@
|
||||
|
||||
#include "mergestages.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "mergestate.hpp"
|
||||
|
||||
#include "../doc/document.hpp"
|
||||
#include "../world/data.hpp"
|
||||
|
||||
|
||||
CSMTools::StartMergeStage::StartMergeStage (MergeState& state)
|
||||
: mState (state)
|
||||
{}
|
||||
|
||||
int CSMTools::StartMergeStage::setup()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CSMTools::StartMergeStage::perform (int stage, CSMDoc::Messages& messages)
|
||||
{
|
||||
mState.mCompleted = false;
|
||||
mState.mTextureIndices.clear();
|
||||
}
|
||||
|
||||
|
||||
CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding)
|
||||
: mState (state), mEncoder (encoding)
|
||||
{}
|
||||
|
||||
int CSMTools::FinishMergedDocumentStage::setup()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& messages)
|
||||
{
|
||||
// We know that the content file list contains at least two entries and that the first one
|
||||
// does exist on disc (otherwise it would have been impossible to initiate a merge on that
|
||||
// document).
|
||||
boost::filesystem::path path = mState.mSource.getContentFiles()[0];
|
||||
|
||||
ESM::ESMReader reader;
|
||||
reader.setEncoder (&mEncoder);
|
||||
reader.open (path.string());
|
||||
|
||||
CSMWorld::MetaData source;
|
||||
source.mId = "sys::meta";
|
||||
source.load (reader);
|
||||
|
||||
CSMWorld::MetaData target = mState.mTarget->getData().getMetaData();
|
||||
|
||||
target.mAuthor = source.mAuthor;
|
||||
target.mDescription = source.mDescription;
|
||||
|
||||
mState.mTarget->getData().setMetaData (target);
|
||||
|
||||
mState.mCompleted = true;
|
||||
}
|
||||
|
||||
|
||||
CSMTools::MergeRefIdsStage::MergeRefIdsStage (MergeState& state) : mState (state) {}
|
||||
|
||||
int CSMTools::MergeRefIdsStage::setup()
|
||||
{
|
||||
return mState.mSource.getData().getReferenceables().getSize();
|
||||
}
|
||||
|
||||
void CSMTools::MergeRefIdsStage::perform (int stage, CSMDoc::Messages& messages)
|
||||
{
|
||||
mState.mSource.getData().getReferenceables().copyTo (
|
||||
stage, mState.mTarget->getData().getReferenceables());
|
||||
}
|
||||
|
||||
|
||||
CSMTools::MergeReferencesStage::MergeReferencesStage (MergeState& state)
|
||||
: mState (state)
|
||||
{}
|
||||
|
||||
int CSMTools::MergeReferencesStage::setup()
|
||||
{
|
||||
mIndex.clear();
|
||||
return mState.mSource.getData().getReferences().getSize();
|
||||
}
|
||||
|
||||
void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messages)
|
||||
{
|
||||
const CSMWorld::Record<CSMWorld::CellRef>& record =
|
||||
mState.mSource.getData().getReferences().getRecord (stage);
|
||||
|
||||
if (!record.isDeleted())
|
||||
{
|
||||
CSMWorld::CellRef ref = record.get();
|
||||
|
||||
ref.mOriginalCell = ref.mCell;
|
||||
|
||||
ref.mRefNum.mIndex = mIndex[Misc::StringUtils::lowerCase (ref.mCell)]++;
|
||||
ref.mRefNum.mContentFile = 0;
|
||||
|
||||
CSMWorld::Record<CSMWorld::CellRef> newRecord (
|
||||
CSMWorld::RecordBase::State_ModifiedOnly, 0, &ref);
|
||||
|
||||
mState.mTarget->getData().getReferences().appendRecord (newRecord);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CSMTools::ListLandTexturesMergeStage::ListLandTexturesMergeStage (MergeState& state)
|
||||
: mState (state)
|
||||
{}
|
||||
|
||||
int CSMTools::ListLandTexturesMergeStage::setup()
|
||||
{
|
||||
return mState.mSource.getData().getLand().getSize();
|
||||
}
|
||||
|
||||
void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
|
||||
{
|
||||
const CSMWorld::Record<CSMWorld::Land>& record =
|
||||
mState.mSource.getData().getLand().getRecord (stage);
|
||||
|
||||
if (!record.isDeleted())
|
||||
{
|
||||
const CSMWorld::Land& land = record.get();
|
||||
|
||||
// make sure record is loaded
|
||||
land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
|
||||
ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM);
|
||||
|
||||
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)
|
||||
: mState (state), mNext (mState.mTextureIndices.end())
|
||||
{}
|
||||
|
||||
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)
|
||||
{
|
||||
if (stage==0)
|
||||
mNext = mState.mTextureIndices.begin();
|
||||
|
||||
bool found = false;
|
||||
|
||||
do
|
||||
{
|
||||
if (mNext==mState.mTextureIndices.end())
|
||||
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();
|
||||
|
||||
std::ostringstream stream;
|
||||
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) {}
|
||||
|
||||
int CSMTools::MergeLandStage::setup()
|
||||
{
|
||||
return mState.mSource.getData().getLand().getSize();
|
||||
}
|
||||
|
||||
void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages)
|
||||
{
|
||||
const CSMWorld::Record<CSMWorld::Land>& record =
|
||||
mState.mSource.getData().getLand().getRecord (stage);
|
||||
|
||||
if (!record.isDeleted())
|
||||
{
|
||||
const CSMWorld::Land& land = record.get();
|
||||
|
||||
land.loadData (ESM::Land::DATA_VCLR | ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
|
||||
ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM);
|
||||
|
||||
CSMWorld::Land newLand (land);
|
||||
|
||||
newLand.mEsm = 0; // avoid potential dangling pointer (ESMReader isn't needed anyway,
|
||||
// because record is already fully loaded)
|
||||
newLand.mPlugin = 0;
|
||||
|
||||
if (land.mDataTypes & ESM::Land::DATA_VTEX)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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())
|
||||
data->mTextures[i] = iter->second;
|
||||
else
|
||||
data->mTextures[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CSMWorld::Record<CSMWorld::Land> newRecord (
|
||||
CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand);
|
||||
|
||||
mState.mTarget->getData().getLand().appendRecord (newRecord);
|
||||
}
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
#ifndef CSM_TOOLS_MERGESTAGES_H
|
||||
#define CSM_TOOLS_MERGESTAGES_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
|
||||
#include "../doc/stage.hpp"
|
||||
|
||||
#include "../world/data.hpp"
|
||||
|
||||
#include "mergestate.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class StartMergeStage : public CSMDoc::Stage
|
||||
{
|
||||
MergeState& mState;
|
||||
|
||||
public:
|
||||
|
||||
StartMergeStage (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.
|
||||
};
|
||||
|
||||
class FinishMergedDocumentStage : public CSMDoc::Stage
|
||||
{
|
||||
MergeState& mState;
|
||||
ToUTF8::Utf8Encoder mEncoder;
|
||||
|
||||
public:
|
||||
|
||||
FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding);
|
||||
|
||||
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.
|
||||
};
|
||||
|
||||
template<typename RecordType, typename Collection = CSMWorld::IdCollection<RecordType> >
|
||||
class MergeIdCollectionStage : public CSMDoc::Stage
|
||||
{
|
||||
MergeState& mState;
|
||||
Collection& (CSMWorld::Data::*mAccessor)();
|
||||
|
||||
public:
|
||||
|
||||
MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)());
|
||||
|
||||
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.
|
||||
};
|
||||
|
||||
template<typename RecordType, typename Collection>
|
||||
MergeIdCollectionStage<RecordType, Collection>::MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)())
|
||||
: mState (state), mAccessor (accessor)
|
||||
{}
|
||||
|
||||
template<typename RecordType, typename Collection>
|
||||
int MergeIdCollectionStage<RecordType, Collection>::setup()
|
||||
{
|
||||
return (mState.mSource.getData().*mAccessor)().getSize();
|
||||
}
|
||||
|
||||
template<typename RecordType, typename Collection>
|
||||
void MergeIdCollectionStage<RecordType, Collection>::perform (int stage, CSMDoc::Messages& messages)
|
||||
{
|
||||
const Collection& source = (mState.mSource.getData().*mAccessor)();
|
||||
Collection& target = (mState.mTarget->getData().*mAccessor)();
|
||||
|
||||
const CSMWorld::Record<RecordType>& record = source.getRecord (stage);
|
||||
|
||||
if (!record.isDeleted())
|
||||
target.appendRecord (CSMWorld::Record<RecordType> (CSMWorld::RecordBase::State_ModifiedOnly, 0, &record.get()));
|
||||
}
|
||||
|
||||
class MergeRefIdsStage : public CSMDoc::Stage
|
||||
{
|
||||
MergeState& mState;
|
||||
|
||||
public:
|
||||
|
||||
MergeRefIdsStage (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.
|
||||
};
|
||||
|
||||
class MergeReferencesStage : public CSMDoc::Stage
|
||||
{
|
||||
MergeState& mState;
|
||||
std::map<std::string, int> mIndex;
|
||||
|
||||
public:
|
||||
|
||||
MergeReferencesStage (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.
|
||||
};
|
||||
|
||||
class ListLandTexturesMergeStage : public CSMDoc::Stage
|
||||
{
|
||||
MergeState& mState;
|
||||
|
||||
public:
|
||||
|
||||
ListLandTexturesMergeStage (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.
|
||||
};
|
||||
|
||||
class MergeLandTexturesStage : public CSMDoc::Stage
|
||||
{
|
||||
MergeState& mState;
|
||||
std::map<std::pair<uint16_t, int>, int>::iterator mNext;
|
||||
|
||||
public:
|
||||
|
||||
MergeLandTexturesStage (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.
|
||||
};
|
||||
|
||||
class MergeLandStage : public CSMDoc::Stage
|
||||
{
|
||||
MergeState& mState;
|
||||
|
||||
public:
|
||||
|
||||
MergeLandStage (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.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,24 @@
|
||||
#ifndef CSM_TOOLS_MERGESTATE_H
|
||||
#define CSM_TOOLS_MERGESTATE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
#include "../doc/document.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
struct MergeState
|
||||
{
|
||||
std::auto_ptr<CSMDoc::Document> mTarget;
|
||||
CSMDoc::Document& mSource;
|
||||
bool mCompleted;
|
||||
std::map<std::pair<uint16_t, int>, int> mTextureIndices; // (texture, content file) -> new texture
|
||||
|
||||
MergeState (CSMDoc::Document& source) : mSource (source), mCompleted (false) {}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,53 @@
|
||||
#include "soundgencheck.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "../world/refiddata.hpp"
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
CSMTools::SoundGenCheckStage::SoundGenCheckStage(const CSMWorld::IdCollection<ESM::SoundGenerator> &soundGens,
|
||||
const CSMWorld::IdCollection<ESM::Sound> &sounds,
|
||||
const CSMWorld::RefIdCollection &referenceables)
|
||||
: mSoundGens(soundGens),
|
||||
mSounds(sounds),
|
||||
mReferenceables(referenceables)
|
||||
{}
|
||||
|
||||
int CSMTools::SoundGenCheckStage::setup()
|
||||
{
|
||||
return mSoundGens.getSize();
|
||||
}
|
||||
|
||||
void CSMTools::SoundGenCheckStage::perform(int stage, CSMDoc::Messages &messages)
|
||||
{
|
||||
const CSMWorld::Record<ESM::SoundGenerator> &record = mSoundGens.getRecord(stage);
|
||||
if (record.isDeleted())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const ESM::SoundGenerator soundGen = record.get();
|
||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_SoundGen, soundGen.mId);
|
||||
|
||||
if (!soundGen.mCreature.empty())
|
||||
{
|
||||
CSMWorld::RefIdData::LocalIndex creatureIndex = mReferenceables.getDataSet().searchId(soundGen.mCreature);
|
||||
if (creatureIndex.first == -1)
|
||||
{
|
||||
messages.push_back(std::make_pair(id, "No such creature '" + soundGen.mCreature + "'"));
|
||||
}
|
||||
else if (creatureIndex.second != CSMWorld::UniversalId::Type_Creature)
|
||||
{
|
||||
messages.push_back(std::make_pair(id, "'" + soundGen.mCreature + "' is not a creature"));
|
||||
}
|
||||
}
|
||||
|
||||
if (soundGen.mSound.empty())
|
||||
{
|
||||
messages.push_back(std::make_pair(id, "Sound is not specified"));
|
||||
}
|
||||
else if (mSounds.searchId(soundGen.mSound) == -1)
|
||||
{
|
||||
messages.push_back(std::make_pair(id, "No such sound '" + soundGen.mSound + "'"));
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
#ifndef CSM_TOOLS_SOUNDGENCHECK_HPP
|
||||
#define CSM_TOOLS_SOUNDGENCHECK_HPP
|
||||
|
||||
#include "../world/data.hpp"
|
||||
|
||||
#include "../doc/stage.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that sound gen records are internally consistent
|
||||
class SoundGenCheckStage : public CSMDoc::Stage
|
||||
{
|
||||
const CSMWorld::IdCollection<ESM::SoundGenerator> &mSoundGens;
|
||||
const CSMWorld::IdCollection<ESM::Sound> &mSounds;
|
||||
const CSMWorld::RefIdCollection &mReferenceables;
|
||||
|
||||
public:
|
||||
SoundGenCheckStage(const CSMWorld::IdCollection<ESM::SoundGenerator> &soundGens,
|
||||
const CSMWorld::IdCollection<ESM::Sound> &sounds,
|
||||
const CSMWorld::RefIdCollection &referenceables);
|
||||
|
||||
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.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,28 @@
|
||||
#include "columnimp.hpp"
|
||||
|
||||
CSMWorld::BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn<ESM::BodyPart> *meshType)
|
||||
: mMeshType(meshType)
|
||||
{}
|
||||
|
||||
QVariant CSMWorld::BodyPartRaceColumn::get(const Record<ESM::BodyPart> &record) const
|
||||
{
|
||||
if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin)
|
||||
{
|
||||
return QString::fromUtf8(record.get().mRace.c_str());
|
||||
}
|
||||
return QVariant(QVariant::UserType);
|
||||
}
|
||||
|
||||
void CSMWorld::BodyPartRaceColumn::set(Record<ESM::BodyPart> &record, const QVariant &data)
|
||||
{
|
||||
ESM::BodyPart record2 = record.get();
|
||||
|
||||
record2.mRace = data.toString().toUtf8().constData();
|
||||
|
||||
record.setModified(record2);
|
||||
}
|
||||
|
||||
bool CSMWorld::BodyPartRaceColumn::isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue