mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-27 12:35:46 +00:00
Apply clang-format to code base
This commit is contained in:
parent
f37d0be806
commit
ddb0522bbf
@ -56,11 +56,16 @@ namespace
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return AreaType_null;
|
||||
case 1: return AreaType_water;
|
||||
case 2: return AreaType_door;
|
||||
case 3: return AreaType_pathgrid;
|
||||
case 4: return AreaType_ground;
|
||||
case 0:
|
||||
return AreaType_null;
|
||||
case 1:
|
||||
return AreaType_water;
|
||||
case 2:
|
||||
return AreaType_door;
|
||||
case 3:
|
||||
return AreaType_pathgrid;
|
||||
case 4:
|
||||
return AreaType_ground;
|
||||
}
|
||||
return AreaType_null;
|
||||
}
|
||||
@ -83,7 +88,7 @@ namespace
|
||||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
std::generate_n(out, count, [&] {
|
||||
return CellWater {generateVec2i(1000, random), Water {ESM::Land::REAL_SIZE, distribution(random)}};
|
||||
return CellWater{ generateVec2i(1000, random), Water{ ESM::Land::REAL_SIZE, distribution(random) } };
|
||||
});
|
||||
}
|
||||
|
||||
@ -97,7 +102,8 @@ namespace
|
||||
if (distribution(random) < 0.939)
|
||||
{
|
||||
generateVertices(std::back_inserter(vertices), triangles * 2.467, random);
|
||||
generateIndices(std::back_inserter(indices), static_cast<int>(vertices.size() / 3) - 1, vertices.size() * 1.279, random);
|
||||
generateIndices(std::back_inserter(indices), static_cast<int>(vertices.size() / 3) - 1,
|
||||
vertices.size() * 1.279, random);
|
||||
generateAreaTypes(std::back_inserter(areaTypes), indices.size() / 3, random);
|
||||
}
|
||||
return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes));
|
||||
@ -113,10 +119,8 @@ namespace
|
||||
result.mMinHeight = distribution(random);
|
||||
result.mMaxHeight = result.mMinHeight + 1.0;
|
||||
result.mLength = static_cast<std::uint8_t>(ESM::Land::LAND_SIZE);
|
||||
std::generate_n(std::back_inserter(result.mHeights), ESM::Land::LAND_NUM_VERTS, [&]
|
||||
{
|
||||
return distribution(random);
|
||||
});
|
||||
std::generate_n(
|
||||
std::back_inserter(result.mHeights), ESM::Land::LAND_NUM_VERTS, [&] { return distribution(random); });
|
||||
result.mOriginalSize = ESM::Land::LAND_SIZE;
|
||||
result.mMinX = 0;
|
||||
result.mMinY = 0;
|
||||
@ -140,16 +144,16 @@ namespace
|
||||
const CollisionShapeType agentShapeType = CollisionShapeType::Aabb;
|
||||
const osg::Vec3f agentHalfExtents = generateAgentHalfExtents(0.5, 1.5, random);
|
||||
const TilePosition tilePosition = generateVec2i(10000, random);
|
||||
const Version version {
|
||||
const Version version{
|
||||
.mGeneration = std::uniform_int_distribution<std::size_t>(0, 100)(random),
|
||||
.mRevision = std::uniform_int_distribution<std::size_t>(0, 10000)(random),
|
||||
};
|
||||
Mesh mesh = generateMesh(triangles, random);
|
||||
std::vector<CellWater> water;
|
||||
generateWater(std::back_inserter(water), 1, random);
|
||||
RecastMesh recastMesh(version, std::move(mesh), std::move(water),
|
||||
{generateHeightfield(random)}, {generateFlatHeightfield(random)}, {});
|
||||
return Key {AgentBounds {agentShapeType, agentHalfExtents}, tilePosition, std::move(recastMesh)};
|
||||
RecastMesh recastMesh(version, std::move(mesh), std::move(water), { generateHeightfield(random) },
|
||||
{ generateFlatHeightfield(random) }, {});
|
||||
return Key{ AgentBounds{ agentShapeType, agentHalfExtents }, tilePosition, std::move(recastMesh) };
|
||||
}
|
||||
|
||||
constexpr std::size_t trianglesPerTile = 239;
|
||||
@ -168,8 +172,7 @@ namespace
|
||||
while (true)
|
||||
{
|
||||
Key key = generateKey(trianglesPerTile, random);
|
||||
cache.set(key.mAgentBounds, key.mTilePosition, key.mRecastMesh,
|
||||
std::make_unique<PreparedNavMeshData>());
|
||||
cache.set(key.mAgentBounds, key.mTilePosition, key.mRecastMesh, std::make_unique<PreparedNavMeshData>());
|
||||
*out++ = std::move(key);
|
||||
const std::size_t newSize = cache.getStats().mNavMeshCacheSize;
|
||||
if (size >= newSize)
|
||||
@ -250,8 +253,8 @@ namespace
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
const auto& key = keys[n++ % keys.size()];
|
||||
const auto result = cache.set(key.mAgentBounds, key.mTilePosition, key.mRecastMesh,
|
||||
std::make_unique<PreparedNavMeshData>());
|
||||
const auto result = cache.set(
|
||||
key.mAgentBounds, key.mTilePosition, key.mRecastMesh, std::make_unique<PreparedNavMeshData>());
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <components/bsa/compressedbsafile.hpp>
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/files/conversion.hpp>
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
#include <components/misc/strings/conversion.hpp>
|
||||
|
||||
#define BSATOOL_VERSION 1.1
|
||||
@ -29,7 +29,7 @@ struct Arguments
|
||||
bool fullpath;
|
||||
};
|
||||
|
||||
bool parseOptions (int argc, char** argv, Arguments &info)
|
||||
bool parseOptions(int argc, char** argv, Arguments& info)
|
||||
{
|
||||
bpo::options_description desc(R"(Inspect and extract files from Bethesda BSA archives
|
||||
|
||||
@ -61,7 +61,7 @@ Allowed options)");
|
||||
|
||||
auto addHiddenOption = hidden.add_options();
|
||||
addHiddenOption("mode,m", bpo::value<std::string>(), "bsatool mode");
|
||||
addHiddenOption("input-file,i", bpo::value< Files::MaybeQuotedPathContainer >(), "input file");
|
||||
addHiddenOption("input-file,i", bpo::value<Files::MaybeQuotedPathContainer>(), "input file");
|
||||
|
||||
bpo::positional_options_description p;
|
||||
p.add("mode", 1).add("input-file", 3);
|
||||
@ -73,53 +73,50 @@ Allowed options)");
|
||||
bpo::variables_map variables;
|
||||
try
|
||||
{
|
||||
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
|
||||
.options(all).positional(p).run();
|
||||
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv).options(all).positional(p).run();
|
||||
bpo::store(valid_opts, variables);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cout << "ERROR parsing arguments: " << e.what() << "\n\n"
|
||||
<< desc << std::endl;
|
||||
std::cout << "ERROR parsing arguments: " << e.what() << "\n\n" << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bpo::notify(variables);
|
||||
|
||||
if (variables.count ("help"))
|
||||
if (variables.count("help"))
|
||||
{
|
||||
std::cout << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (variables.count ("version"))
|
||||
if (variables.count("version"))
|
||||
{
|
||||
std::cout << "BSATool version " << BSATOOL_VERSION << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (!variables.count("mode"))
|
||||
{
|
||||
std::cout << "ERROR: no mode specified!\n\n"
|
||||
<< desc << std::endl;
|
||||
std::cout << "ERROR: no mode specified!\n\n" << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
info.mode = variables["mode"].as<std::string>();
|
||||
if (!(info.mode == "list" || info.mode == "extract" || info.mode == "extractall" || info.mode == "add" || info.mode == "create"))
|
||||
if (!(info.mode == "list" || info.mode == "extract" || info.mode == "extractall" || info.mode == "add"
|
||||
|| info.mode == "create"))
|
||||
{
|
||||
std::cout << std::endl << "ERROR: invalid mode \"" << info.mode << "\"\n\n"
|
||||
<< desc << std::endl;
|
||||
std::cout << std::endl << "ERROR: invalid mode \"" << info.mode << "\"\n\n" << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!variables.count("input-file"))
|
||||
{
|
||||
std::cout << "\nERROR: missing BSA archive\n\n"
|
||||
<< desc << std::endl;
|
||||
std::cout << "\nERROR: missing BSA archive\n\n" << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
auto inputFiles = variables["input-file"].as< Files::MaybeQuotedPathContainer >();
|
||||
auto inputFiles = variables["input-file"].as<Files::MaybeQuotedPathContainer>();
|
||||
|
||||
info.filename = inputFiles[0].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
|
||||
info.filename = inputFiles[0].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26
|
||||
// due to implementation bugs.
|
||||
|
||||
// Default output to the working directory
|
||||
info.outdir = std::filesystem::current_path();
|
||||
@ -128,28 +125,30 @@ Allowed options)");
|
||||
{
|
||||
if (inputFiles.size() < 2)
|
||||
{
|
||||
std::cout << "\nERROR: file to extract unspecified\n\n"
|
||||
<< desc << std::endl;
|
||||
std::cout << "\nERROR: file to extract unspecified\n\n" << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (inputFiles.size() > 1)
|
||||
info.extractfile = inputFiles[1].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
|
||||
info.extractfile = inputFiles[1].u8string(); // This call to u8string is redundant, but required to build on
|
||||
// MSVC 14.26 due to implementation bugs.
|
||||
if (inputFiles.size() > 2)
|
||||
info.outdir = inputFiles[2].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
|
||||
info.outdir = inputFiles[2].u8string(); // This call to u8string is redundant, but required to build on
|
||||
// MSVC 14.26 due to implementation bugs.
|
||||
}
|
||||
else if (info.mode == "add")
|
||||
{
|
||||
if (inputFiles.empty())
|
||||
{
|
||||
std::cout << "\nERROR: file to add unspecified\n\n"
|
||||
<< desc << std::endl;
|
||||
std::cout << "\nERROR: file to add unspecified\n\n" << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (inputFiles.size() > 1)
|
||||
info.addfile = inputFiles[1].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
|
||||
info.addfile = inputFiles[1].u8string(); // This call to u8string is redundant, but required to build on
|
||||
// MSVC 14.26 due to implementation bugs.
|
||||
}
|
||||
else if (inputFiles.size() > 1)
|
||||
info.outdir = inputFiles[1].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
|
||||
info.outdir = inputFiles[1].u8string(); // This call to u8string is redundant, but required to build on
|
||||
// MSVC 14.26 due to implementation bugs.
|
||||
|
||||
info.longformat = variables.count("long") != 0;
|
||||
info.fullpath = variables.count("full-path") != 0;
|
||||
@ -157,14 +156,14 @@ Allowed options)");
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename File>
|
||||
template <typename File>
|
||||
int list(std::unique_ptr<File>& bsa, Arguments& info)
|
||||
{
|
||||
// List all files
|
||||
const auto &files = bsa->getList();
|
||||
const auto& files = bsa->getList();
|
||||
for (const auto& file : files)
|
||||
{
|
||||
if(info.longformat)
|
||||
if (info.longformat)
|
||||
{
|
||||
// Long format
|
||||
std::ios::fmtflags f(std::cout.flags());
|
||||
@ -180,7 +179,7 @@ int list(std::unique_ptr<File>& bsa, Arguments& info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename File>
|
||||
template <typename File>
|
||||
int extract(std::unique_ptr<File>& bsa, Arguments& info)
|
||||
{
|
||||
auto archivePath = info.extractfile.u8string();
|
||||
@ -207,7 +206,7 @@ int extract(std::unique_ptr<File>& bsa, Arguments& info)
|
||||
}
|
||||
|
||||
// Get the target path (the path the file will be extracted to)
|
||||
std::filesystem::path relPath (extractPath);
|
||||
std::filesystem::path relPath(extractPath);
|
||||
|
||||
std::filesystem::path target;
|
||||
if (info.fullpath)
|
||||
@ -221,14 +220,16 @@ int extract(std::unique_ptr<File>& bsa, Arguments& info)
|
||||
std::filesystem::file_status s = std::filesystem::status(target.parent_path());
|
||||
if (!std::filesystem::is_directory(s))
|
||||
{
|
||||
std::cout << "ERROR: " << Files::pathToUnicodeString(target.parent_path()) << " is not a directory." << std::endl;
|
||||
std::cout << "ERROR: " << Files::pathToUnicodeString(target.parent_path()) << " is not a directory."
|
||||
<< std::endl;
|
||||
return 3;
|
||||
}
|
||||
|
||||
std::ofstream out(target, std::ios::binary);
|
||||
|
||||
// Write the file to disk
|
||||
std::cout << "Extracting " << Files::pathToUnicodeString(info.extractfile) << " to " << Files::pathToUnicodeString(target) << std::endl;
|
||||
std::cout << "Extracting " << Files::pathToUnicodeString(info.extractfile) << " to "
|
||||
<< Files::pathToUnicodeString(target) << std::endl;
|
||||
|
||||
out << stream->rdbuf();
|
||||
out.close();
|
||||
@ -236,10 +237,10 @@ int extract(std::unique_ptr<File>& bsa, Arguments& info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename File>
|
||||
template <typename File>
|
||||
int extractAll(std::unique_ptr<File>& bsa, Arguments& info)
|
||||
{
|
||||
for (const auto &file : bsa->getList())
|
||||
for (const auto& file : bsa->getList())
|
||||
{
|
||||
std::string extractPath(file.name());
|
||||
Misc::StringUtils::replaceAll(extractPath, "\\", "/");
|
||||
@ -271,7 +272,7 @@ int extractAll(std::unique_ptr<File>& bsa, Arguments& info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename File>
|
||||
template <typename File>
|
||||
int add(std::unique_ptr<File>& bsa, Arguments& info)
|
||||
{
|
||||
std::fstream stream(info.addfile, std::ios_base::binary | std::ios_base::out | std::ios_base::in);
|
||||
@ -280,7 +281,7 @@ int add(std::unique_ptr<File>& bsa, Arguments& info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename File>
|
||||
template <typename File>
|
||||
int call(Arguments& info)
|
||||
{
|
||||
std::unique_ptr<File> bsa = std::make_unique<File>();
|
||||
|
@ -1,11 +1,13 @@
|
||||
#include <components/debug/debugging.hpp>
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/esm3/readerscache.hpp>
|
||||
#include <components/esmloader/esmdata.hpp>
|
||||
#include <components/esmloader/load.hpp>
|
||||
#include <components/fallback/fallback.hpp>
|
||||
#include <components/fallback/validate.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/platform/platform.hpp>
|
||||
#include <components/resource/bulletshapemanager.hpp>
|
||||
#include <components/resource/foreachbulletobject.hpp>
|
||||
#include <components/resource/imagemanager.hpp>
|
||||
@ -15,8 +17,6 @@
|
||||
#include <components/version/version.hpp>
|
||||
#include <components/vfs/manager.hpp>
|
||||
#include <components/vfs/registerarchives.hpp>
|
||||
#include <components/esm3/readerscache.hpp>
|
||||
#include <components/platform/platform.hpp>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
@ -27,7 +27,6 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace bpo = boost::program_options;
|
||||
@ -44,33 +43,41 @@ namespace
|
||||
|
||||
addOption("version", "print version information and quit");
|
||||
|
||||
addOption("data", bpo::value<Files::MaybeQuotedPathContainer>()->default_value(Files::MaybeQuotedPathContainer(), "data")
|
||||
->multitoken()->composing(), "set data directories (later directories have higher priority)");
|
||||
addOption("data",
|
||||
bpo::value<Files::MaybeQuotedPathContainer>()
|
||||
->default_value(Files::MaybeQuotedPathContainer(), "data")
|
||||
->multitoken()
|
||||
->composing(),
|
||||
"set data directories (later directories have higher priority)");
|
||||
|
||||
addOption("data-local", bpo::value<Files::MaybeQuotedPathContainer::value_type>()->default_value(Files::MaybeQuotedPathContainer::value_type(), ""),
|
||||
"set local data directory (highest priority)");
|
||||
addOption("data-local",
|
||||
bpo::value<Files::MaybeQuotedPathContainer::value_type>()->default_value(
|
||||
Files::MaybeQuotedPathContainer::value_type(), ""),
|
||||
"set local data directory (highest priority)");
|
||||
|
||||
addOption("fallback-archive", bpo::value<StringsVector>()->default_value(StringsVector(), "fallback-archive")
|
||||
->multitoken()->composing(), "set fallback BSA archives (later archives have higher priority)");
|
||||
addOption("fallback-archive",
|
||||
bpo::value<StringsVector>()->default_value(StringsVector(), "fallback-archive")->multitoken()->composing(),
|
||||
"set fallback BSA archives (later archives have higher priority)");
|
||||
|
||||
addOption("resources", bpo::value<Files::MaybeQuotedPath>()->default_value(Files::MaybeQuotedPath(), "resources"),
|
||||
"set resources directory");
|
||||
addOption("resources",
|
||||
bpo::value<Files::MaybeQuotedPath>()->default_value(Files::MaybeQuotedPath(), "resources"),
|
||||
"set resources directory");
|
||||
|
||||
addOption("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
|
||||
->multitoken()->composing(), "content file(s): esm/esp, or omwgame/omwaddon/omwscripts");
|
||||
addOption("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")->multitoken()->composing(),
|
||||
"content file(s): esm/esp, or omwgame/omwaddon/omwscripts");
|
||||
|
||||
addOption("fs-strict", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "strict file system handling (no case folding)");
|
||||
addOption("fs-strict", bpo::value<bool>()->implicit_value(true)->default_value(false),
|
||||
"strict file system handling (no case folding)");
|
||||
|
||||
addOption("encoding", bpo::value<std::string>()->
|
||||
default_value("win1252"),
|
||||
"Character encoding used in OpenMW game messages:\n"
|
||||
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
|
||||
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
|
||||
"\n\twin1252 - Western European (Latin) alphabet, used by default");
|
||||
addOption("encoding", bpo::value<std::string>()->default_value("win1252"),
|
||||
"Character encoding used in OpenMW game messages:\n"
|
||||
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, "
|
||||
"Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
|
||||
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
|
||||
"\n\twin1252 - Western European (Latin) alphabet, used by default");
|
||||
|
||||
addOption("fallback", bpo::value<FallbackMap>()->default_value(FallbackMap(), "")
|
||||
->multitoken()->composing(), "fallback values");
|
||||
addOption("fallback", bpo::value<FallbackMap>()->default_value(FallbackMap(), "")->multitoken()->composing(),
|
||||
"fallback values");
|
||||
;
|
||||
Files::ConfigurationManager::addCommonOptions(result);
|
||||
|
||||
@ -81,7 +88,7 @@ namespace
|
||||
{
|
||||
const float (&mValue)[3];
|
||||
|
||||
friend std::ostream& operator <<(std::ostream& stream, const WriteArray& value)
|
||||
friend std::ostream& operator<<(std::ostream& stream, const WriteArray& value)
|
||||
{
|
||||
for (std::size_t i = 0; i < 2; ++i)
|
||||
stream << std::setprecision(std::numeric_limits<float>::max_exponent10) << value.mValue[i] << ", ";
|
||||
@ -104,14 +111,13 @@ namespace
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int runBulletObjectTool(int argc, char *argv[])
|
||||
int runBulletObjectTool(int argc, char* argv[])
|
||||
{
|
||||
Platform::init();
|
||||
|
||||
bpo::options_description desc = makeOptionsDescription();
|
||||
|
||||
bpo::parsed_options options = bpo::command_line_parser(argc, argv)
|
||||
.options(desc).allow_unregistered().run();
|
||||
bpo::parsed_options options = bpo::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
|
||||
bpo::variables_map variables;
|
||||
|
||||
bpo::store(options, variables);
|
||||
@ -168,25 +174,28 @@ namespace
|
||||
query.mLoadGameSettings = true;
|
||||
query.mLoadLands = true;
|
||||
query.mLoadStatics = true;
|
||||
const EsmLoader::EsmData esmData = EsmLoader::loadEsmData(query, contentFiles, fileCollections, readers, &encoder);
|
||||
const EsmLoader::EsmData esmData
|
||||
= EsmLoader::loadEsmData(query, contentFiles, fileCollections, readers, &encoder);
|
||||
|
||||
Resource::ImageManager imageManager(&vfs);
|
||||
Resource::NifFileManager nifFileManager(&vfs);
|
||||
Resource::SceneManager sceneManager(&vfs, &imageManager, &nifFileManager);
|
||||
Resource::BulletShapeManager bulletShapeManager(&vfs, &sceneManager, &nifFileManager);
|
||||
|
||||
Resource::forEachBulletObject(readers, vfs, bulletShapeManager, esmData,
|
||||
[] (const ESM::Cell& cell, const Resource::BulletObject& object)
|
||||
{
|
||||
Resource::forEachBulletObject(
|
||||
readers, vfs, bulletShapeManager, esmData, [](const ESM::Cell& cell, const Resource::BulletObject& object) {
|
||||
Log(Debug::Verbose) << "Found bullet object in " << (cell.isExterior() ? "exterior" : "interior")
|
||||
<< " cell \"" << cell.getDescription() << "\":"
|
||||
<< " fileName=\"" << object.mShape->mFileName << '"'
|
||||
<< " fileHash=" << toHex(object.mShape->mFileHash)
|
||||
<< " collisionShape=" << std::boolalpha << (object.mShape->mCollisionShape == nullptr)
|
||||
<< " avoidCollisionShape=" << std::boolalpha << (object.mShape->mAvoidCollisionShape == nullptr)
|
||||
<< " position=(" << WriteArray {object.mPosition.pos} << ')'
|
||||
<< " rotation=(" << WriteArray {object.mPosition.rot} << ')'
|
||||
<< " scale=" << std::setprecision(std::numeric_limits<float>::max_exponent10) << object.mScale;
|
||||
<< " cell \"" << cell.getDescription() << "\":"
|
||||
<< " fileName=\"" << object.mShape->mFileName << '"'
|
||||
<< " fileHash=" << toHex(object.mShape->mFileHash)
|
||||
<< " collisionShape=" << std::boolalpha
|
||||
<< (object.mShape->mCollisionShape == nullptr)
|
||||
<< " avoidCollisionShape=" << std::boolalpha
|
||||
<< (object.mShape->mAvoidCollisionShape == nullptr) << " position=("
|
||||
<< WriteArray{ object.mPosition.pos } << ')' << " rotation=("
|
||||
<< WriteArray{ object.mPosition.rot } << ')'
|
||||
<< " scale=" << std::setprecision(std::numeric_limits<float>::max_exponent10)
|
||||
<< object.mScale;
|
||||
});
|
||||
|
||||
Log(Debug::Info) << "Done";
|
||||
@ -195,7 +204,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
return wrapApplication(runBulletObjectTool, argc, argv, "BulletObjectTool");
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef OPENMW_ESMTOOL_ARGUMENTS_H
|
||||
#define OPENMW_ESMTOOL_ARGUMENTS_H
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include <components/esm/format.hpp>
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,7 @@ std::string_view bodyPartLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= 26)
|
||||
{
|
||||
static constexpr std::string_view bodyPartLabels[] = {
|
||||
static constexpr std::string_view bodyPartLabels[] = {
|
||||
"Head",
|
||||
"Hair",
|
||||
"Neck",
|
||||
@ -58,7 +58,7 @@ std::string_view meshPartLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= ESM::BodyPart::MP_Tail)
|
||||
{
|
||||
static constexpr std::string_view meshPartLabels[] = {
|
||||
static constexpr std::string_view meshPartLabels[] = {
|
||||
"Head",
|
||||
"Hair",
|
||||
"Neck",
|
||||
@ -85,7 +85,7 @@ std::string_view meshTypeLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= ESM::BodyPart::MT_Armor)
|
||||
{
|
||||
static constexpr std::string_view meshTypeLabels[] = {
|
||||
static constexpr std::string_view meshTypeLabels[] = {
|
||||
"Skin",
|
||||
"Clothing",
|
||||
"Armor",
|
||||
@ -122,7 +122,7 @@ std::string_view armorTypeLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= 10)
|
||||
{
|
||||
static constexpr std::string_view armorTypeLabels[] = {
|
||||
static constexpr std::string_view armorTypeLabels[] = {
|
||||
"Helmet",
|
||||
"Cuirass",
|
||||
"Left Pauldron",
|
||||
@ -243,11 +243,16 @@ std::string_view aiTypeLabel(ESM::AiPackageType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ESM::AI_Wander: return "Wander";
|
||||
case ESM::AI_Travel: return "Travel";
|
||||
case ESM::AI_Follow: return "Follow";
|
||||
case ESM::AI_Escort: return "Escort";
|
||||
case ESM::AI_Activate: return "Activate";
|
||||
case ESM::AI_Wander:
|
||||
return "Wander";
|
||||
case ESM::AI_Travel:
|
||||
return "Travel";
|
||||
case ESM::AI_Follow:
|
||||
return "Follow";
|
||||
case ESM::AI_Escort:
|
||||
return "Escort";
|
||||
case ESM::AI_Activate:
|
||||
return "Activate";
|
||||
}
|
||||
return "Invalid";
|
||||
}
|
||||
@ -256,7 +261,7 @@ std::string_view magicEffectLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= 142)
|
||||
{
|
||||
static constexpr std::string_view magicEffectLabels [] = {
|
||||
static constexpr std::string_view magicEffectLabels[] = {
|
||||
"Water Breathing",
|
||||
"Swift Swim",
|
||||
"Water Walking",
|
||||
@ -411,7 +416,7 @@ std::string_view attributeLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= 7)
|
||||
{
|
||||
static constexpr std::string_view attributeLabels [] = {
|
||||
static constexpr std::string_view attributeLabels[] = {
|
||||
"Strength",
|
||||
"Intelligence",
|
||||
"Willpower",
|
||||
@ -431,7 +436,7 @@ std::string_view spellTypeLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= 5)
|
||||
{
|
||||
static constexpr std::string_view spellTypeLabels [] = {
|
||||
static constexpr std::string_view spellTypeLabels[] = {
|
||||
"Spells",
|
||||
"Abilities",
|
||||
"Blight Disease",
|
||||
@ -449,7 +454,7 @@ std::string_view specializationLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= 2)
|
||||
{
|
||||
static constexpr std::string_view specializationLabels [] = {
|
||||
static constexpr std::string_view specializationLabels[] = {
|
||||
"Combat",
|
||||
"Magic",
|
||||
"Stealth",
|
||||
@ -464,7 +469,7 @@ std::string_view skillLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= 26)
|
||||
{
|
||||
static constexpr std::string_view skillLabels [] = {
|
||||
static constexpr std::string_view skillLabels[] = {
|
||||
"Block",
|
||||
"Armorer",
|
||||
"Medium Armor",
|
||||
@ -503,7 +508,7 @@ std::string_view apparatusTypeLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= 3)
|
||||
{
|
||||
static constexpr std::string_view apparatusTypeLabels [] = {
|
||||
static constexpr std::string_view apparatusTypeLabels[] = {
|
||||
"Mortar",
|
||||
"Alembic",
|
||||
"Calcinator",
|
||||
@ -519,7 +524,7 @@ std::string_view rangeTypeLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= 2)
|
||||
{
|
||||
static constexpr std::string_view rangeTypeLabels [] = {
|
||||
static constexpr std::string_view rangeTypeLabels[] = {
|
||||
"Self",
|
||||
"Touch",
|
||||
"Target",
|
||||
@ -534,7 +539,7 @@ std::string_view schoolLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= 5)
|
||||
{
|
||||
static constexpr std::string_view schoolLabels [] = {
|
||||
static constexpr std::string_view schoolLabels[] = {
|
||||
"Alteration",
|
||||
"Conjuration",
|
||||
"Destruction",
|
||||
@ -552,7 +557,7 @@ std::string_view enchantTypeLabel(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= 3)
|
||||
{
|
||||
static constexpr std::string_view enchantTypeLabels [] = {
|
||||
static constexpr std::string_view enchantTypeLabels[] = {
|
||||
"Cast Once",
|
||||
"Cast When Strikes",
|
||||
"Cast When Used",
|
||||
@ -656,13 +661,15 @@ std::string_view ruleFunction(int idx)
|
||||
std::string bodyPartFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::BodyPart::BPF_Female) properties += "Female ";
|
||||
if (flags & ESM::BodyPart::BPF_NotPlayable) properties += "NotPlayable ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::BodyPart::BPF_Female|
|
||||
ESM::BodyPart::BPF_NotPlayable));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::BodyPart::BPF_Female)
|
||||
properties += "Female ";
|
||||
if (flags & ESM::BodyPart::BPF_NotPlayable)
|
||||
properties += "NotPlayable ";
|
||||
int unused = (0xFFFFFFFF ^ (ESM::BodyPart::BPF_Female | ESM::BodyPart::BPF_NotPlayable));
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -670,20 +677,23 @@ std::string bodyPartFlags(int flags)
|
||||
std::string cellFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::Cell::HasWater) properties += "HasWater ";
|
||||
if (flags & ESM::Cell::Interior) properties += "Interior ";
|
||||
if (flags & ESM::Cell::NoSleep) properties += "NoSleep ";
|
||||
if (flags & ESM::Cell::QuasiEx) properties += "QuasiEx ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::Cell::HasWater)
|
||||
properties += "HasWater ";
|
||||
if (flags & ESM::Cell::Interior)
|
||||
properties += "Interior ";
|
||||
if (flags & ESM::Cell::NoSleep)
|
||||
properties += "NoSleep ";
|
||||
if (flags & ESM::Cell::QuasiEx)
|
||||
properties += "QuasiEx ";
|
||||
// This used value is not in the ESM component.
|
||||
if (flags & 0x00000040) properties += "Unknown ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Cell::HasWater|
|
||||
ESM::Cell::Interior|
|
||||
ESM::Cell::NoSleep|
|
||||
ESM::Cell::QuasiEx|
|
||||
0x00000040));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
if (flags & 0x00000040)
|
||||
properties += "Unknown ";
|
||||
int unused = (0xFFFFFFFF
|
||||
^ (ESM::Cell::HasWater | ESM::Cell::Interior | ESM::Cell::NoSleep | ESM::Cell::QuasiEx | 0x00000040));
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -691,15 +701,17 @@ std::string cellFlags(int flags)
|
||||
std::string containerFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::Container::Unknown) properties += "Unknown ";
|
||||
if (flags & ESM::Container::Organic) properties += "Organic ";
|
||||
if (flags & ESM::Container::Respawn) properties += "Respawn ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Container::Unknown|
|
||||
ESM::Container::Organic|
|
||||
ESM::Container::Respawn));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::Container::Unknown)
|
||||
properties += "Unknown ";
|
||||
if (flags & ESM::Container::Organic)
|
||||
properties += "Organic ";
|
||||
if (flags & ESM::Container::Respawn)
|
||||
properties += "Respawn ";
|
||||
int unused = (0xFFFFFFFF ^ (ESM::Container::Unknown | ESM::Container::Organic | ESM::Container::Respawn));
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -707,25 +719,29 @@ std::string containerFlags(int flags)
|
||||
std::string creatureFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::Creature::Base) properties += "Base ";
|
||||
if (flags & ESM::Creature::Walks) properties += "Walks ";
|
||||
if (flags & ESM::Creature::Swims) properties += "Swims ";
|
||||
if (flags & ESM::Creature::Flies) properties += "Flies ";
|
||||
if (flags & ESM::Creature::Bipedal) properties += "Bipedal ";
|
||||
if (flags & ESM::Creature::Respawn) properties += "Respawn ";
|
||||
if (flags & ESM::Creature::Weapon) properties += "Weapon ";
|
||||
if (flags & ESM::Creature::Essential) properties += "Essential ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Creature::Base|
|
||||
ESM::Creature::Walks|
|
||||
ESM::Creature::Swims|
|
||||
ESM::Creature::Flies|
|
||||
ESM::Creature::Bipedal|
|
||||
ESM::Creature::Respawn|
|
||||
ESM::Creature::Weapon|
|
||||
ESM::Creature::Essential));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::Creature::Base)
|
||||
properties += "Base ";
|
||||
if (flags & ESM::Creature::Walks)
|
||||
properties += "Walks ";
|
||||
if (flags & ESM::Creature::Swims)
|
||||
properties += "Swims ";
|
||||
if (flags & ESM::Creature::Flies)
|
||||
properties += "Flies ";
|
||||
if (flags & ESM::Creature::Bipedal)
|
||||
properties += "Bipedal ";
|
||||
if (flags & ESM::Creature::Respawn)
|
||||
properties += "Respawn ";
|
||||
if (flags & ESM::Creature::Weapon)
|
||||
properties += "Weapon ";
|
||||
if (flags & ESM::Creature::Essential)
|
||||
properties += "Essential ";
|
||||
int unused = (0xFFFFFFFF
|
||||
^ (ESM::Creature::Base | ESM::Creature::Walks | ESM::Creature::Swims | ESM::Creature::Flies
|
||||
| ESM::Creature::Bipedal | ESM::Creature::Respawn | ESM::Creature::Weapon | ESM::Creature::Essential));
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%02X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -733,9 +749,12 @@ std::string creatureFlags(int flags)
|
||||
std::string enchantmentFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::Enchantment::Autocalc) properties += "Autocalc ";
|
||||
if (flags & (0xFFFFFFFF ^ ESM::Enchantment::Autocalc)) properties += "Invalid ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::Enchantment::Autocalc)
|
||||
properties += "Autocalc ";
|
||||
if (flags & (0xFFFFFFFF ^ ESM::Enchantment::Autocalc))
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -746,11 +765,16 @@ std::string landFlags(int flags)
|
||||
// The ESM component says that this first four bits are used, but
|
||||
// only the first three bits are used as far as I can tell.
|
||||
// There's also no enumeration of the bit in the ESM component.
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & 0x00000001) properties += "Unknown1 ";
|
||||
if (flags & 0x00000004) properties += "Unknown3 ";
|
||||
if (flags & 0x00000002) properties += "Unknown2 ";
|
||||
if (flags & 0xFFFFFFF8) properties += "Invalid ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & 0x00000001)
|
||||
properties += "Unknown1 ";
|
||||
if (flags & 0x00000004)
|
||||
properties += "Unknown3 ";
|
||||
if (flags & 0x00000002)
|
||||
properties += "Unknown2 ";
|
||||
if (flags & 0xFFFFFFF8)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -758,13 +782,15 @@ std::string landFlags(int flags)
|
||||
std::string itemListFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::ItemLevList::AllLevels) properties += "AllLevels ";
|
||||
if (flags & ESM::ItemLevList::Each) properties += "Each ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::ItemLevList::AllLevels|
|
||||
ESM::ItemLevList::Each));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::ItemLevList::AllLevels)
|
||||
properties += "AllLevels ";
|
||||
if (flags & ESM::ItemLevList::Each)
|
||||
properties += "Each ";
|
||||
int unused = (0xFFFFFFFF ^ (ESM::ItemLevList::AllLevels | ESM::ItemLevList::Each));
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -772,10 +798,13 @@ std::string itemListFlags(int flags)
|
||||
std::string creatureListFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::CreatureLevList::AllLevels) properties += "AllLevels ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::CreatureLevList::AllLevels)
|
||||
properties += "AllLevels ";
|
||||
int unused = (0xFFFFFFFF ^ ESM::CreatureLevList::AllLevels);
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -783,27 +812,31 @@ std::string creatureListFlags(int flags)
|
||||
std::string lightFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::Light::Dynamic) properties += "Dynamic ";
|
||||
if (flags & ESM::Light::Fire) properties += "Fire ";
|
||||
if (flags & ESM::Light::Carry) properties += "Carry ";
|
||||
if (flags & ESM::Light::Flicker) properties += "Flicker ";
|
||||
if (flags & ESM::Light::FlickerSlow) properties += "FlickerSlow ";
|
||||
if (flags & ESM::Light::Pulse) properties += "Pulse ";
|
||||
if (flags & ESM::Light::PulseSlow) properties += "PulseSlow ";
|
||||
if (flags & ESM::Light::Negative) properties += "Negative ";
|
||||
if (flags & ESM::Light::OffDefault) properties += "OffDefault ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Light::Dynamic|
|
||||
ESM::Light::Fire|
|
||||
ESM::Light::Carry|
|
||||
ESM::Light::Flicker|
|
||||
ESM::Light::FlickerSlow|
|
||||
ESM::Light::Pulse|
|
||||
ESM::Light::PulseSlow|
|
||||
ESM::Light::Negative|
|
||||
ESM::Light::OffDefault));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::Light::Dynamic)
|
||||
properties += "Dynamic ";
|
||||
if (flags & ESM::Light::Fire)
|
||||
properties += "Fire ";
|
||||
if (flags & ESM::Light::Carry)
|
||||
properties += "Carry ";
|
||||
if (flags & ESM::Light::Flicker)
|
||||
properties += "Flicker ";
|
||||
if (flags & ESM::Light::FlickerSlow)
|
||||
properties += "FlickerSlow ";
|
||||
if (flags & ESM::Light::Pulse)
|
||||
properties += "Pulse ";
|
||||
if (flags & ESM::Light::PulseSlow)
|
||||
properties += "PulseSlow ";
|
||||
if (flags & ESM::Light::Negative)
|
||||
properties += "Negative ";
|
||||
if (flags & ESM::Light::OffDefault)
|
||||
properties += "OffDefault ";
|
||||
int unused = (0xFFFFFFFF
|
||||
^ (ESM::Light::Dynamic | ESM::Light::Fire | ESM::Light::Carry | ESM::Light::Flicker | ESM::Light::FlickerSlow
|
||||
| ESM::Light::Pulse | ESM::Light::PulseSlow | ESM::Light::Negative | ESM::Light::OffDefault));
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -811,27 +844,47 @@ std::string lightFlags(int flags)
|
||||
std::string magicEffectFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::MagicEffect::TargetAttribute) properties += "TargetAttribute ";
|
||||
if (flags & ESM::MagicEffect::TargetSkill) properties += "TargetSkill ";
|
||||
if (flags & ESM::MagicEffect::NoDuration) properties += "NoDuration ";
|
||||
if (flags & ESM::MagicEffect::NoMagnitude) properties += "NoMagnitude ";
|
||||
if (flags & ESM::MagicEffect::Harmful) properties += "Harmful ";
|
||||
if (flags & ESM::MagicEffect::ContinuousVfx) properties += "ContinuousVFX ";
|
||||
if (flags & ESM::MagicEffect::CastSelf) properties += "CastSelf ";
|
||||
if (flags & ESM::MagicEffect::CastTouch) properties += "CastTouch ";
|
||||
if (flags & ESM::MagicEffect::CastTarget) properties += "CastTarget ";
|
||||
if (flags & ESM::MagicEffect::AppliedOnce) properties += "AppliedOnce ";
|
||||
if (flags & ESM::MagicEffect::Stealth) properties += "Stealth ";
|
||||
if (flags & ESM::MagicEffect::NonRecastable) properties += "NonRecastable ";
|
||||
if (flags & ESM::MagicEffect::IllegalDaedra) properties += "IllegalDaedra ";
|
||||
if (flags & ESM::MagicEffect::Unreflectable) properties += "Unreflectable ";
|
||||
if (flags & ESM::MagicEffect::CasterLinked) properties += "CasterLinked ";
|
||||
if (flags & ESM::MagicEffect::AllowSpellmaking) properties += "AllowSpellmaking ";
|
||||
if (flags & ESM::MagicEffect::AllowEnchanting) properties += "AllowEnchanting ";
|
||||
if (flags & ESM::MagicEffect::NegativeLight) properties += "NegativeLight ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::MagicEffect::TargetAttribute)
|
||||
properties += "TargetAttribute ";
|
||||
if (flags & ESM::MagicEffect::TargetSkill)
|
||||
properties += "TargetSkill ";
|
||||
if (flags & ESM::MagicEffect::NoDuration)
|
||||
properties += "NoDuration ";
|
||||
if (flags & ESM::MagicEffect::NoMagnitude)
|
||||
properties += "NoMagnitude ";
|
||||
if (flags & ESM::MagicEffect::Harmful)
|
||||
properties += "Harmful ";
|
||||
if (flags & ESM::MagicEffect::ContinuousVfx)
|
||||
properties += "ContinuousVFX ";
|
||||
if (flags & ESM::MagicEffect::CastSelf)
|
||||
properties += "CastSelf ";
|
||||
if (flags & ESM::MagicEffect::CastTouch)
|
||||
properties += "CastTouch ";
|
||||
if (flags & ESM::MagicEffect::CastTarget)
|
||||
properties += "CastTarget ";
|
||||
if (flags & ESM::MagicEffect::AppliedOnce)
|
||||
properties += "AppliedOnce ";
|
||||
if (flags & ESM::MagicEffect::Stealth)
|
||||
properties += "Stealth ";
|
||||
if (flags & ESM::MagicEffect::NonRecastable)
|
||||
properties += "NonRecastable ";
|
||||
if (flags & ESM::MagicEffect::IllegalDaedra)
|
||||
properties += "IllegalDaedra ";
|
||||
if (flags & ESM::MagicEffect::Unreflectable)
|
||||
properties += "Unreflectable ";
|
||||
if (flags & ESM::MagicEffect::CasterLinked)
|
||||
properties += "CasterLinked ";
|
||||
if (flags & ESM::MagicEffect::AllowSpellmaking)
|
||||
properties += "AllowSpellmaking ";
|
||||
if (flags & ESM::MagicEffect::AllowEnchanting)
|
||||
properties += "AllowEnchanting ";
|
||||
if (flags & ESM::MagicEffect::NegativeLight)
|
||||
properties += "NegativeLight ";
|
||||
|
||||
if (flags & 0xFFFC0000) properties += "Invalid ";
|
||||
if (flags & 0xFFFC0000)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -839,21 +892,24 @@ std::string magicEffectFlags(int flags)
|
||||
std::string npcFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::NPC::Base) properties += "Base ";
|
||||
if (flags & ESM::NPC::Autocalc) properties += "Autocalc ";
|
||||
if (flags & ESM::NPC::Female) properties += "Female ";
|
||||
if (flags & ESM::NPC::Respawn) properties += "Respawn ";
|
||||
if (flags & ESM::NPC::Essential) properties += "Essential ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::NPC::Base)
|
||||
properties += "Base ";
|
||||
if (flags & ESM::NPC::Autocalc)
|
||||
properties += "Autocalc ";
|
||||
if (flags & ESM::NPC::Female)
|
||||
properties += "Female ";
|
||||
if (flags & ESM::NPC::Respawn)
|
||||
properties += "Respawn ";
|
||||
if (flags & ESM::NPC::Essential)
|
||||
properties += "Essential ";
|
||||
// Whether corpses persist is a bit that is unaccounted for,
|
||||
// however relatively few NPCs have this bit set.
|
||||
int unused = (0xFF ^
|
||||
(ESM::NPC::Base|
|
||||
ESM::NPC::Autocalc|
|
||||
ESM::NPC::Female|
|
||||
ESM::NPC::Respawn|
|
||||
ESM::NPC::Essential));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
int unused
|
||||
= (0xFF ^ (ESM::NPC::Base | ESM::NPC::Autocalc | ESM::NPC::Female | ESM::NPC::Respawn | ESM::NPC::Essential));
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%02X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -861,14 +917,16 @@ std::string npcFlags(int flags)
|
||||
std::string raceFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
// All races have the playable flag set in Bethesda files.
|
||||
if (flags & ESM::Race::Playable) properties += "Playable ";
|
||||
if (flags & ESM::Race::Beast) properties += "Beast ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Race::Playable|
|
||||
ESM::Race::Beast));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
if (flags & ESM::Race::Playable)
|
||||
properties += "Playable ";
|
||||
if (flags & ESM::Race::Beast)
|
||||
properties += "Beast ";
|
||||
int unused = (0xFFFFFFFF ^ (ESM::Race::Playable | ESM::Race::Beast));
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -876,15 +934,17 @@ std::string raceFlags(int flags)
|
||||
std::string spellFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::Spell::F_Autocalc) properties += "Autocalc ";
|
||||
if (flags & ESM::Spell::F_PCStart) properties += "PCStart ";
|
||||
if (flags & ESM::Spell::F_Always) properties += "Always ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Spell::F_Autocalc|
|
||||
ESM::Spell::F_PCStart|
|
||||
ESM::Spell::F_Always));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::Spell::F_Autocalc)
|
||||
properties += "Autocalc ";
|
||||
if (flags & ESM::Spell::F_PCStart)
|
||||
properties += "PCStart ";
|
||||
if (flags & ESM::Spell::F_Always)
|
||||
properties += "Always ";
|
||||
int unused = (0xFFFFFFFF ^ (ESM::Spell::F_Autocalc | ESM::Spell::F_PCStart | ESM::Spell::F_Always));
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -892,16 +952,18 @@ std::string spellFlags(int flags)
|
||||
std::string weaponFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
// The interpretation of the flags are still unclear to me.
|
||||
// Apparently you can't be Silver without being Magical? Many of
|
||||
// the "Magical" weapons don't have enchantments of any sort.
|
||||
if (flags & ESM::Weapon::Magical) properties += "Magical ";
|
||||
if (flags & ESM::Weapon::Silver) properties += "Silver ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Weapon::Magical|
|
||||
ESM::Weapon::Silver));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
if (flags & ESM::Weapon::Magical)
|
||||
properties += "Magical ";
|
||||
if (flags & ESM::Weapon::Silver)
|
||||
properties += "Silver ";
|
||||
int unused = (0xFFFFFFFF ^ (ESM::Weapon::Magical | ESM::Weapon::Silver));
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
@ -909,13 +971,19 @@ std::string weaponFlags(int flags)
|
||||
std::string recordFlags(uint32_t flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::FLAG_Deleted) properties += "Deleted ";
|
||||
if (flags & ESM::FLAG_Persistent) properties += "Persistent ";
|
||||
if (flags & ESM::FLAG_Ignored) properties += "Ignored ";
|
||||
if (flags & ESM::FLAG_Blocked) properties += "Blocked ";
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::FLAG_Deleted)
|
||||
properties += "Deleted ";
|
||||
if (flags & ESM::FLAG_Persistent)
|
||||
properties += "Persistent ";
|
||||
if (flags & ESM::FLAG_Ignored)
|
||||
properties += "Ignored ";
|
||||
if (flags & ESM::FLAG_Blocked)
|
||||
properties += "Blocked ";
|
||||
int unused = ~(ESM::FLAG_Deleted | ESM::FLAG_Persistent | ESM::FLAG_Ignored | ESM::FLAG_Blocked);
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
#ifndef OPENMW_ESMTOOL_RECORD_H
|
||||
#define OPENMW_ESMTOOL_RECORD_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <components/esm/records.hpp>
|
||||
|
||||
@ -14,7 +14,8 @@ namespace ESM
|
||||
|
||||
namespace EsmTool
|
||||
{
|
||||
template <class T> class Record;
|
||||
template <class T>
|
||||
class Record;
|
||||
|
||||
class RecordBase
|
||||
{
|
||||
@ -25,9 +26,9 @@ namespace EsmTool
|
||||
bool mPrintPlain;
|
||||
|
||||
public:
|
||||
RecordBase ()
|
||||
: mFlags(0)
|
||||
, mPrintPlain(false)
|
||||
RecordBase()
|
||||
: mFlags(0)
|
||||
, mPrintPlain(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -35,32 +36,25 @@ namespace EsmTool
|
||||
|
||||
virtual std::string getId() const = 0;
|
||||
|
||||
uint32_t getFlags() const {
|
||||
return mFlags;
|
||||
}
|
||||
uint32_t getFlags() const { return mFlags; }
|
||||
|
||||
void setFlags(uint32_t flags) {
|
||||
mFlags = flags;
|
||||
}
|
||||
void setFlags(uint32_t flags) { mFlags = flags; }
|
||||
|
||||
ESM::NAME getType() const {
|
||||
return mType;
|
||||
}
|
||||
ESM::NAME getType() const { return mType; }
|
||||
|
||||
void setPrintPlain(bool plain) {
|
||||
mPrintPlain = plain;
|
||||
}
|
||||
void setPrintPlain(bool plain) { mPrintPlain = plain; }
|
||||
|
||||
virtual void load(ESM::ESMReader &esm) = 0;
|
||||
virtual void save(ESM::ESMWriter &esm) = 0;
|
||||
virtual void load(ESM::ESMReader& esm) = 0;
|
||||
virtual void save(ESM::ESMWriter& esm) = 0;
|
||||
virtual void print() = 0;
|
||||
|
||||
static std::unique_ptr<RecordBase> create(ESM::NAME type);
|
||||
|
||||
// just make it a bit shorter
|
||||
template <class T>
|
||||
Record<T> *cast() {
|
||||
return static_cast<Record<T> *>(this);
|
||||
Record<T>* cast()
|
||||
{
|
||||
return static_cast<Record<T>*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
@ -73,75 +67,115 @@ namespace EsmTool
|
||||
public:
|
||||
Record()
|
||||
: mIsDeleted(false)
|
||||
{}
|
||||
|
||||
std::string getId() const override {
|
||||
return mData.mId;
|
||||
{
|
||||
}
|
||||
|
||||
T &get() {
|
||||
return mData;
|
||||
}
|
||||
std::string getId() const override { return mData.mId; }
|
||||
|
||||
void save(ESM::ESMWriter &esm) override {
|
||||
mData.save(esm, mIsDeleted);
|
||||
}
|
||||
T& get() { return mData; }
|
||||
|
||||
void load(ESM::ESMReader &esm) override {
|
||||
mData.load(esm, mIsDeleted);
|
||||
}
|
||||
void save(ESM::ESMWriter& esm) override { mData.save(esm, mIsDeleted); }
|
||||
|
||||
void load(ESM::ESMReader& esm) override { mData.load(esm, mIsDeleted); }
|
||||
|
||||
void print() override;
|
||||
};
|
||||
|
||||
template<> std::string Record<ESM::Cell>::getId() const;
|
||||
template<> std::string Record<ESM::Land>::getId() const;
|
||||
template<> std::string Record<ESM::MagicEffect>::getId() const;
|
||||
template<> std::string Record<ESM::Pathgrid>::getId() const;
|
||||
template<> std::string Record<ESM::Skill>::getId() const;
|
||||
|
||||
template<> void Record<ESM::Activator>::print();
|
||||
template<> void Record<ESM::Potion>::print();
|
||||
template<> void Record<ESM::Armor>::print();
|
||||
template<> void Record<ESM::Apparatus>::print();
|
||||
template<> void Record<ESM::BodyPart>::print();
|
||||
template<> void Record<ESM::Book>::print();
|
||||
template<> void Record<ESM::BirthSign>::print();
|
||||
template<> void Record<ESM::Cell>::print();
|
||||
template<> void Record<ESM::Class>::print();
|
||||
template<> void Record<ESM::Clothing>::print();
|
||||
template<> void Record<ESM::Container>::print();
|
||||
template<> void Record<ESM::Creature>::print();
|
||||
template<> void Record<ESM::Dialogue>::print();
|
||||
template<> void Record<ESM::Door>::print();
|
||||
template<> void Record<ESM::Enchantment>::print();
|
||||
template<> void Record<ESM::Faction>::print();
|
||||
template<> void Record<ESM::Global>::print();
|
||||
template<> void Record<ESM::GameSetting>::print();
|
||||
template<> void Record<ESM::DialInfo>::print();
|
||||
template<> void Record<ESM::Ingredient>::print();
|
||||
template<> void Record<ESM::Land>::print();
|
||||
template<> void Record<ESM::CreatureLevList>::print();
|
||||
template<> void Record<ESM::ItemLevList>::print();
|
||||
template<> void Record<ESM::Light>::print();
|
||||
template<> void Record<ESM::Lockpick>::print();
|
||||
template<> void Record<ESM::Probe>::print();
|
||||
template<> void Record<ESM::Repair>::print();
|
||||
template<> void Record<ESM::LandTexture>::print();
|
||||
template<> void Record<ESM::MagicEffect>::print();
|
||||
template<> void Record<ESM::Miscellaneous>::print();
|
||||
template<> void Record<ESM::NPC>::print();
|
||||
template<> void Record<ESM::Pathgrid>::print();
|
||||
template<> void Record<ESM::Race>::print();
|
||||
template<> void Record<ESM::Region>::print();
|
||||
template<> void Record<ESM::Script>::print();
|
||||
template<> void Record<ESM::Skill>::print();
|
||||
template<> void Record<ESM::SoundGenerator>::print();
|
||||
template<> void Record<ESM::Sound>::print();
|
||||
template<> void Record<ESM::Spell>::print();
|
||||
template<> void Record<ESM::StartScript>::print();
|
||||
template<> void Record<ESM::Static>::print();
|
||||
template<> void Record<ESM::Weapon>::print();
|
||||
template <>
|
||||
std::string Record<ESM::Cell>::getId() const;
|
||||
template <>
|
||||
std::string Record<ESM::Land>::getId() const;
|
||||
template <>
|
||||
std::string Record<ESM::MagicEffect>::getId() const;
|
||||
template <>
|
||||
std::string Record<ESM::Pathgrid>::getId() const;
|
||||
template <>
|
||||
std::string Record<ESM::Skill>::getId() const;
|
||||
|
||||
template <>
|
||||
void Record<ESM::Activator>::print();
|
||||
template <>
|
||||
void Record<ESM::Potion>::print();
|
||||
template <>
|
||||
void Record<ESM::Armor>::print();
|
||||
template <>
|
||||
void Record<ESM::Apparatus>::print();
|
||||
template <>
|
||||
void Record<ESM::BodyPart>::print();
|
||||
template <>
|
||||
void Record<ESM::Book>::print();
|
||||
template <>
|
||||
void Record<ESM::BirthSign>::print();
|
||||
template <>
|
||||
void Record<ESM::Cell>::print();
|
||||
template <>
|
||||
void Record<ESM::Class>::print();
|
||||
template <>
|
||||
void Record<ESM::Clothing>::print();
|
||||
template <>
|
||||
void Record<ESM::Container>::print();
|
||||
template <>
|
||||
void Record<ESM::Creature>::print();
|
||||
template <>
|
||||
void Record<ESM::Dialogue>::print();
|
||||
template <>
|
||||
void Record<ESM::Door>::print();
|
||||
template <>
|
||||
void Record<ESM::Enchantment>::print();
|
||||
template <>
|
||||
void Record<ESM::Faction>::print();
|
||||
template <>
|
||||
void Record<ESM::Global>::print();
|
||||
template <>
|
||||
void Record<ESM::GameSetting>::print();
|
||||
template <>
|
||||
void Record<ESM::DialInfo>::print();
|
||||
template <>
|
||||
void Record<ESM::Ingredient>::print();
|
||||
template <>
|
||||
void Record<ESM::Land>::print();
|
||||
template <>
|
||||
void Record<ESM::CreatureLevList>::print();
|
||||
template <>
|
||||
void Record<ESM::ItemLevList>::print();
|
||||
template <>
|
||||
void Record<ESM::Light>::print();
|
||||
template <>
|
||||
void Record<ESM::Lockpick>::print();
|
||||
template <>
|
||||
void Record<ESM::Probe>::print();
|
||||
template <>
|
||||
void Record<ESM::Repair>::print();
|
||||
template <>
|
||||
void Record<ESM::LandTexture>::print();
|
||||
template <>
|
||||
void Record<ESM::MagicEffect>::print();
|
||||
template <>
|
||||
void Record<ESM::Miscellaneous>::print();
|
||||
template <>
|
||||
void Record<ESM::NPC>::print();
|
||||
template <>
|
||||
void Record<ESM::Pathgrid>::print();
|
||||
template <>
|
||||
void Record<ESM::Race>::print();
|
||||
template <>
|
||||
void Record<ESM::Region>::print();
|
||||
template <>
|
||||
void Record<ESM::Script>::print();
|
||||
template <>
|
||||
void Record<ESM::Skill>::print();
|
||||
template <>
|
||||
void Record<ESM::SoundGenerator>::print();
|
||||
template <>
|
||||
void Record<ESM::Sound>::print();
|
||||
template <>
|
||||
void Record<ESM::Spell>::print();
|
||||
template <>
|
||||
void Record<ESM::StartScript>::print();
|
||||
template <>
|
||||
void Record<ESM::Static>::print();
|
||||
template <>
|
||||
void Record<ESM::Weapon>::print();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -21,79 +21,115 @@ namespace EsmTool
|
||||
|
||||
explicit Params(const Arguments& info)
|
||||
: mQuite(info.quiet_given || info.mode == "clone")
|
||||
{}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::string toString(ESM4::GroupType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ESM4::Grp_RecordType: return "RecordType";
|
||||
case ESM4::Grp_WorldChild: return "WorldChild";
|
||||
case ESM4::Grp_InteriorCell: return "InteriorCell";
|
||||
case ESM4::Grp_InteriorSubCell: return "InteriorSubCell";
|
||||
case ESM4::Grp_ExteriorCell: return "ExteriorCell";
|
||||
case ESM4::Grp_ExteriorSubCell: return "ExteriorSubCell";
|
||||
case ESM4::Grp_CellChild: return "CellChild";
|
||||
case ESM4::Grp_TopicChild: return "TopicChild";
|
||||
case ESM4::Grp_CellPersistentChild: return "CellPersistentChild";
|
||||
case ESM4::Grp_CellTemporaryChild: return "CellTemporaryChild";
|
||||
case ESM4::Grp_CellVisibleDistChild: return "CellVisibleDistChild";
|
||||
case ESM4::Grp_RecordType:
|
||||
return "RecordType";
|
||||
case ESM4::Grp_WorldChild:
|
||||
return "WorldChild";
|
||||
case ESM4::Grp_InteriorCell:
|
||||
return "InteriorCell";
|
||||
case ESM4::Grp_InteriorSubCell:
|
||||
return "InteriorSubCell";
|
||||
case ESM4::Grp_ExteriorCell:
|
||||
return "ExteriorCell";
|
||||
case ESM4::Grp_ExteriorSubCell:
|
||||
return "ExteriorSubCell";
|
||||
case ESM4::Grp_CellChild:
|
||||
return "CellChild";
|
||||
case ESM4::Grp_TopicChild:
|
||||
return "TopicChild";
|
||||
case ESM4::Grp_CellPersistentChild:
|
||||
return "CellPersistentChild";
|
||||
case ESM4::Grp_CellTemporaryChild:
|
||||
return "CellTemporaryChild";
|
||||
case ESM4::Grp_CellVisibleDistChild:
|
||||
return "CellVisibleDistChild";
|
||||
}
|
||||
|
||||
return "Unknown (" + std::to_string(type) + ")";
|
||||
}
|
||||
|
||||
template <class T, class = std::void_t<>>
|
||||
struct HasFormId : std::false_type {};
|
||||
struct HasFormId : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct HasFormId<T, std::void_t<decltype(T::mFormId)>> : std::true_type {};
|
||||
struct HasFormId<T, std::void_t<decltype(T::mFormId)>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr bool hasFormId = HasFormId<T>::value;
|
||||
|
||||
template <class T, class = std::void_t<>>
|
||||
struct HasFlags : std::false_type {};
|
||||
struct HasFlags : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct HasFlags<T, std::void_t<decltype(T::mFlags)>> : std::true_type {};
|
||||
struct HasFlags<T, std::void_t<decltype(T::mFlags)>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr bool hasFlags = HasFlags<T>::value;
|
||||
|
||||
template <class T, class = std::void_t<>>
|
||||
struct HasEditorId : std::false_type {};
|
||||
struct HasEditorId : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct HasEditorId<T, std::void_t<decltype(T::mEditorId)>> : std::true_type {};
|
||||
struct HasEditorId<T, std::void_t<decltype(T::mEditorId)>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr bool hasEditorId = HasEditorId<T>::value;
|
||||
|
||||
template <class T, class = std::void_t<>>
|
||||
struct HasModel : std::false_type {};
|
||||
struct HasModel : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct HasModel<T, std::void_t<decltype(T::mModel)>> : std::true_type {};
|
||||
struct HasModel<T, std::void_t<decltype(T::mModel)>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr bool hasModel = HasModel<T>::value;
|
||||
|
||||
template <class T, class = std::void_t<>>
|
||||
struct HasNif : std::false_type {};
|
||||
struct HasNif : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct HasNif<T, std::void_t<decltype(T::mNif)>> : std::true_type {};
|
||||
struct HasNif<T, std::void_t<decltype(T::mNif)>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr bool hasNif = HasNif<T>::value;
|
||||
|
||||
template <class T, class = std::void_t<>>
|
||||
struct HasKf : std::false_type {};
|
||||
struct HasKf : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct HasKf<T, std::void_t<decltype(T::mKf)>> : std::true_type {};
|
||||
struct HasKf<T, std::void_t<decltype(T::mKf)>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr bool hasKf = HasKf<T>::value;
|
||||
@ -150,148 +186,286 @@ namespace EsmTool
|
||||
{
|
||||
switch (static_cast<ESM4::RecordTypes>(reader.hdr().record.typeId))
|
||||
{
|
||||
case ESM4::REC_AACT: break;
|
||||
case ESM4::REC_ACHR: return readTypedRecord<ESM4::ActorCharacter>(params, reader);
|
||||
case ESM4::REC_ACRE: return readTypedRecord<ESM4::ActorCreature>(params, reader);
|
||||
case ESM4::REC_ACTI: return readTypedRecord<ESM4::Activator>(params, reader);
|
||||
case ESM4::REC_ADDN: break;
|
||||
case ESM4::REC_ALCH: return readTypedRecord<ESM4::Potion>(params, reader);
|
||||
case ESM4::REC_ALOC: return readTypedRecord<ESM4::MediaLocationController>(params, reader);
|
||||
case ESM4::REC_AMMO: return readTypedRecord<ESM4::Ammunition>(params, reader);
|
||||
case ESM4::REC_ANIO: return readTypedRecord<ESM4::AnimObject>(params, reader);
|
||||
case ESM4::REC_APPA: return readTypedRecord<ESM4::Apparatus>(params, reader);
|
||||
case ESM4::REC_ARMA: return readTypedRecord<ESM4::ArmorAddon>(params, reader);
|
||||
case ESM4::REC_ARMO: return readTypedRecord<ESM4::Armor>(params, reader);
|
||||
case ESM4::REC_ARTO: break;
|
||||
case ESM4::REC_ASPC: return readTypedRecord<ESM4::AcousticSpace>(params, reader);
|
||||
case ESM4::REC_ASTP: break;
|
||||
case ESM4::REC_AVIF: break;
|
||||
case ESM4::REC_BOOK: return readTypedRecord<ESM4::Book>(params, reader);
|
||||
case ESM4::REC_BPTD: return readTypedRecord<ESM4::BodyPartData>(params, reader);
|
||||
case ESM4::REC_CAMS: break;
|
||||
case ESM4::REC_CCRD: break;
|
||||
case ESM4::REC_CELL: return readTypedRecord<ESM4::Cell>(params, reader);
|
||||
case ESM4::REC_CLAS: return readTypedRecord<ESM4::Class>(params, reader);
|
||||
case ESM4::REC_CLFM: return readTypedRecord<ESM4::Colour>(params, reader);
|
||||
case ESM4::REC_CLMT: break;
|
||||
case ESM4::REC_CLOT: return readTypedRecord<ESM4::Clothing>(params, reader);
|
||||
case ESM4::REC_CMNY: break;
|
||||
case ESM4::REC_COBJ: break;
|
||||
case ESM4::REC_COLL: break;
|
||||
case ESM4::REC_CONT: return readTypedRecord<ESM4::Container>(params, reader);
|
||||
case ESM4::REC_CPTH: break;
|
||||
case ESM4::REC_CREA: return readTypedRecord<ESM4::Creature>(params, reader);
|
||||
case ESM4::REC_CSTY: break;
|
||||
case ESM4::REC_DEBR: break;
|
||||
case ESM4::REC_DIAL: return readTypedRecord<ESM4::Dialogue>(params, reader);
|
||||
case ESM4::REC_DLBR: break;
|
||||
case ESM4::REC_DLVW: break;
|
||||
case ESM4::REC_DOBJ: return readTypedRecord<ESM4::DefaultObj>(params, reader);
|
||||
case ESM4::REC_DOOR: return readTypedRecord<ESM4::Door>(params, reader);
|
||||
case ESM4::REC_DUAL: break;
|
||||
case ESM4::REC_ECZN: break;
|
||||
case ESM4::REC_EFSH: break;
|
||||
case ESM4::REC_ENCH: break;
|
||||
case ESM4::REC_EQUP: break;
|
||||
case ESM4::REC_EXPL: break;
|
||||
case ESM4::REC_EYES: return readTypedRecord<ESM4::Eyes>(params, reader);
|
||||
case ESM4::REC_FACT: break;
|
||||
case ESM4::REC_FLOR: return readTypedRecord<ESM4::Flora>(params, reader);
|
||||
case ESM4::REC_FLST: return readTypedRecord<ESM4::FormIdList>(params, reader);
|
||||
case ESM4::REC_FSTP: break;
|
||||
case ESM4::REC_FSTS: break;
|
||||
case ESM4::REC_FURN: return readTypedRecord<ESM4::Furniture>(params, reader);
|
||||
case ESM4::REC_GLOB: return readTypedRecord<ESM4::GlobalVariable>(params, reader);
|
||||
case ESM4::REC_GMST: break;
|
||||
case ESM4::REC_GRAS: return readTypedRecord<ESM4::Grass>(params, reader);
|
||||
case ESM4::REC_GRUP: break;
|
||||
case ESM4::REC_HAIR: return readTypedRecord<ESM4::Hair>(params, reader);
|
||||
case ESM4::REC_HAZD: break;
|
||||
case ESM4::REC_HDPT: return readTypedRecord<ESM4::HeadPart>(params, reader);
|
||||
case ESM4::REC_AACT:
|
||||
break;
|
||||
case ESM4::REC_ACHR:
|
||||
return readTypedRecord<ESM4::ActorCharacter>(params, reader);
|
||||
case ESM4::REC_ACRE:
|
||||
return readTypedRecord<ESM4::ActorCreature>(params, reader);
|
||||
case ESM4::REC_ACTI:
|
||||
return readTypedRecord<ESM4::Activator>(params, reader);
|
||||
case ESM4::REC_ADDN:
|
||||
break;
|
||||
case ESM4::REC_ALCH:
|
||||
return readTypedRecord<ESM4::Potion>(params, reader);
|
||||
case ESM4::REC_ALOC:
|
||||
return readTypedRecord<ESM4::MediaLocationController>(params, reader);
|
||||
case ESM4::REC_AMMO:
|
||||
return readTypedRecord<ESM4::Ammunition>(params, reader);
|
||||
case ESM4::REC_ANIO:
|
||||
return readTypedRecord<ESM4::AnimObject>(params, reader);
|
||||
case ESM4::REC_APPA:
|
||||
return readTypedRecord<ESM4::Apparatus>(params, reader);
|
||||
case ESM4::REC_ARMA:
|
||||
return readTypedRecord<ESM4::ArmorAddon>(params, reader);
|
||||
case ESM4::REC_ARMO:
|
||||
return readTypedRecord<ESM4::Armor>(params, reader);
|
||||
case ESM4::REC_ARTO:
|
||||
break;
|
||||
case ESM4::REC_ASPC:
|
||||
return readTypedRecord<ESM4::AcousticSpace>(params, reader);
|
||||
case ESM4::REC_ASTP:
|
||||
break;
|
||||
case ESM4::REC_AVIF:
|
||||
break;
|
||||
case ESM4::REC_BOOK:
|
||||
return readTypedRecord<ESM4::Book>(params, reader);
|
||||
case ESM4::REC_BPTD:
|
||||
return readTypedRecord<ESM4::BodyPartData>(params, reader);
|
||||
case ESM4::REC_CAMS:
|
||||
break;
|
||||
case ESM4::REC_CCRD:
|
||||
break;
|
||||
case ESM4::REC_CELL:
|
||||
return readTypedRecord<ESM4::Cell>(params, reader);
|
||||
case ESM4::REC_CLAS:
|
||||
return readTypedRecord<ESM4::Class>(params, reader);
|
||||
case ESM4::REC_CLFM:
|
||||
return readTypedRecord<ESM4::Colour>(params, reader);
|
||||
case ESM4::REC_CLMT:
|
||||
break;
|
||||
case ESM4::REC_CLOT:
|
||||
return readTypedRecord<ESM4::Clothing>(params, reader);
|
||||
case ESM4::REC_CMNY:
|
||||
break;
|
||||
case ESM4::REC_COBJ:
|
||||
break;
|
||||
case ESM4::REC_COLL:
|
||||
break;
|
||||
case ESM4::REC_CONT:
|
||||
return readTypedRecord<ESM4::Container>(params, reader);
|
||||
case ESM4::REC_CPTH:
|
||||
break;
|
||||
case ESM4::REC_CREA:
|
||||
return readTypedRecord<ESM4::Creature>(params, reader);
|
||||
case ESM4::REC_CSTY:
|
||||
break;
|
||||
case ESM4::REC_DEBR:
|
||||
break;
|
||||
case ESM4::REC_DIAL:
|
||||
return readTypedRecord<ESM4::Dialogue>(params, reader);
|
||||
case ESM4::REC_DLBR:
|
||||
break;
|
||||
case ESM4::REC_DLVW:
|
||||
break;
|
||||
case ESM4::REC_DOBJ:
|
||||
return readTypedRecord<ESM4::DefaultObj>(params, reader);
|
||||
case ESM4::REC_DOOR:
|
||||
return readTypedRecord<ESM4::Door>(params, reader);
|
||||
case ESM4::REC_DUAL:
|
||||
break;
|
||||
case ESM4::REC_ECZN:
|
||||
break;
|
||||
case ESM4::REC_EFSH:
|
||||
break;
|
||||
case ESM4::REC_ENCH:
|
||||
break;
|
||||
case ESM4::REC_EQUP:
|
||||
break;
|
||||
case ESM4::REC_EXPL:
|
||||
break;
|
||||
case ESM4::REC_EYES:
|
||||
return readTypedRecord<ESM4::Eyes>(params, reader);
|
||||
case ESM4::REC_FACT:
|
||||
break;
|
||||
case ESM4::REC_FLOR:
|
||||
return readTypedRecord<ESM4::Flora>(params, reader);
|
||||
case ESM4::REC_FLST:
|
||||
return readTypedRecord<ESM4::FormIdList>(params, reader);
|
||||
case ESM4::REC_FSTP:
|
||||
break;
|
||||
case ESM4::REC_FSTS:
|
||||
break;
|
||||
case ESM4::REC_FURN:
|
||||
return readTypedRecord<ESM4::Furniture>(params, reader);
|
||||
case ESM4::REC_GLOB:
|
||||
return readTypedRecord<ESM4::GlobalVariable>(params, reader);
|
||||
case ESM4::REC_GMST:
|
||||
break;
|
||||
case ESM4::REC_GRAS:
|
||||
return readTypedRecord<ESM4::Grass>(params, reader);
|
||||
case ESM4::REC_GRUP:
|
||||
break;
|
||||
case ESM4::REC_HAIR:
|
||||
return readTypedRecord<ESM4::Hair>(params, reader);
|
||||
case ESM4::REC_HAZD:
|
||||
break;
|
||||
case ESM4::REC_HDPT:
|
||||
return readTypedRecord<ESM4::HeadPart>(params, reader);
|
||||
case ESM4::REC_IDLE:
|
||||
// FIXME: ESM4::IdleAnimation::load does not work with Oblivion.esm
|
||||
// return readTypedRecord<ESM4::IdleAnimation>(params, reader);
|
||||
break;
|
||||
case ESM4::REC_IDLM: return readTypedRecord<ESM4::IdleMarker>(params, reader);
|
||||
case ESM4::REC_IMAD: break;
|
||||
case ESM4::REC_IMGS: break;
|
||||
case ESM4::REC_IMOD: return readTypedRecord<ESM4::ItemMod>(params, reader);
|
||||
case ESM4::REC_INFO: return readTypedRecord<ESM4::DialogInfo>(params, reader);
|
||||
case ESM4::REC_INGR: return readTypedRecord<ESM4::Ingredient>(params, reader);
|
||||
case ESM4::REC_IPCT: break;
|
||||
case ESM4::REC_IPDS: break;
|
||||
case ESM4::REC_KEYM: return readTypedRecord<ESM4::Key>(params, reader);
|
||||
case ESM4::REC_KYWD: break;
|
||||
case ESM4::REC_LAND: return readTypedRecord<ESM4::Land>(params, reader);
|
||||
case ESM4::REC_LCRT: break;
|
||||
case ESM4::REC_LCTN: break;
|
||||
case ESM4::REC_LGTM: return readTypedRecord<ESM4::LightingTemplate>(params, reader);
|
||||
case ESM4::REC_LIGH: return readTypedRecord<ESM4::Light>(params, reader);
|
||||
case ESM4::REC_LSCR: break;
|
||||
case ESM4::REC_LTEX: return readTypedRecord<ESM4::LandTexture>(params, reader);
|
||||
case ESM4::REC_LVLC: return readTypedRecord<ESM4::LevelledCreature>(params, reader);
|
||||
case ESM4::REC_LVLI: return readTypedRecord<ESM4::LevelledItem>(params, reader);
|
||||
case ESM4::REC_LVLN: return readTypedRecord<ESM4::LevelledNpc>(params, reader);
|
||||
case ESM4::REC_LVSP: break;
|
||||
case ESM4::REC_MATO: return readTypedRecord<ESM4::Material>(params, reader);
|
||||
case ESM4::REC_MATT: break;
|
||||
case ESM4::REC_MESG: break;
|
||||
case ESM4::REC_MGEF: break;
|
||||
case ESM4::REC_MISC: return readTypedRecord<ESM4::MiscItem>(params, reader);
|
||||
case ESM4::REC_MOVT: break;
|
||||
case ESM4::REC_MSET: return readTypedRecord<ESM4::MediaSet>(params, reader);
|
||||
case ESM4::REC_MSTT: return readTypedRecord<ESM4::MovableStatic>(params, reader);
|
||||
case ESM4::REC_MUSC: return readTypedRecord<ESM4::Music>(params, reader);
|
||||
case ESM4::REC_MUST: break;
|
||||
case ESM4::REC_NAVI: return readTypedRecord<ESM4::Navigation>(params, reader);
|
||||
case ESM4::REC_NAVM: return readTypedRecord<ESM4::NavMesh>(params, reader);
|
||||
case ESM4::REC_NOTE: return readTypedRecord<ESM4::Note>(params, reader);
|
||||
case ESM4::REC_NPC_: return readTypedRecord<ESM4::Npc>(params, reader);
|
||||
case ESM4::REC_OTFT: return readTypedRecord<ESM4::Outfit>(params, reader);
|
||||
case ESM4::REC_PACK: return readTypedRecord<ESM4::AIPackage>(params, reader);
|
||||
case ESM4::REC_PERK: break;
|
||||
case ESM4::REC_PGRD: return readTypedRecord<ESM4::Pathgrid>(params, reader);
|
||||
case ESM4::REC_PGRE: return readTypedRecord<ESM4::PlacedGrenade>(params, reader);
|
||||
case ESM4::REC_PHZD: break;
|
||||
case ESM4::REC_PROJ: break;
|
||||
case ESM4::REC_PWAT: return readTypedRecord<ESM4::PlaceableWater>(params, reader);
|
||||
case ESM4::REC_QUST: return readTypedRecord<ESM4::Quest>(params, reader);
|
||||
case ESM4::REC_RACE: return readTypedRecord<ESM4::Race>(params, reader);
|
||||
case ESM4::REC_REFR: return readTypedRecord<ESM4::Reference>(params, reader);
|
||||
case ESM4::REC_REGN: return readTypedRecord<ESM4::Region>(params, reader);
|
||||
case ESM4::REC_RELA: break;
|
||||
case ESM4::REC_REVB: break;
|
||||
case ESM4::REC_RFCT: break;
|
||||
case ESM4::REC_ROAD: return readTypedRecord<ESM4::Road>(params, reader);
|
||||
case ESM4::REC_SBSP: return readTypedRecord<ESM4::SubSpace>(params, reader);
|
||||
case ESM4::REC_SCEN: break;
|
||||
case ESM4::REC_SCOL: return readTypedRecord<ESM4::StaticCollection>(params, reader);
|
||||
case ESM4::REC_SCPT: return readTypedRecord<ESM4::Script>(params, reader);
|
||||
case ESM4::REC_SCRL: return readTypedRecord<ESM4::Scroll>(params, reader);
|
||||
case ESM4::REC_SGST: return readTypedRecord<ESM4::SigilStone>(params, reader);
|
||||
case ESM4::REC_SHOU: break;
|
||||
case ESM4::REC_SLGM: return readTypedRecord<ESM4::SoulGem>(params, reader);
|
||||
case ESM4::REC_SMBN: break;
|
||||
case ESM4::REC_SMEN: break;
|
||||
case ESM4::REC_SMQN: break;
|
||||
case ESM4::REC_SNCT: break;
|
||||
case ESM4::REC_SNDR: return readTypedRecord<ESM4::SoundReference>(params, reader);
|
||||
case ESM4::REC_SOPM: break;
|
||||
case ESM4::REC_SOUN: return readTypedRecord<ESM4::Sound>(params, reader);
|
||||
case ESM4::REC_SPEL: break;
|
||||
case ESM4::REC_SPGD: break;
|
||||
case ESM4::REC_STAT: return readTypedRecord<ESM4::Static>(params, reader);
|
||||
case ESM4::REC_TACT: return readTypedRecord<ESM4::TalkingActivator>(params, reader);
|
||||
case ESM4::REC_TERM: return readTypedRecord<ESM4::Terminal>(params, reader);
|
||||
case ESM4::REC_TES4: return readTypedRecord<ESM4::Header>(params, reader);
|
||||
case ESM4::REC_TREE: return readTypedRecord<ESM4::Tree>(params, reader);
|
||||
case ESM4::REC_TXST: return readTypedRecord<ESM4::TextureSet>(params, reader);
|
||||
case ESM4::REC_VTYP: break;
|
||||
case ESM4::REC_WATR: break;
|
||||
case ESM4::REC_WEAP: return readTypedRecord<ESM4::Weapon>(params, reader);
|
||||
case ESM4::REC_WOOP: break;
|
||||
case ESM4::REC_WRLD: return readTypedRecord<ESM4::World>(params, reader);
|
||||
case ESM4::REC_WTHR: break;
|
||||
case ESM4::REC_IDLM:
|
||||
return readTypedRecord<ESM4::IdleMarker>(params, reader);
|
||||
case ESM4::REC_IMAD:
|
||||
break;
|
||||
case ESM4::REC_IMGS:
|
||||
break;
|
||||
case ESM4::REC_IMOD:
|
||||
return readTypedRecord<ESM4::ItemMod>(params, reader);
|
||||
case ESM4::REC_INFO:
|
||||
return readTypedRecord<ESM4::DialogInfo>(params, reader);
|
||||
case ESM4::REC_INGR:
|
||||
return readTypedRecord<ESM4::Ingredient>(params, reader);
|
||||
case ESM4::REC_IPCT:
|
||||
break;
|
||||
case ESM4::REC_IPDS:
|
||||
break;
|
||||
case ESM4::REC_KEYM:
|
||||
return readTypedRecord<ESM4::Key>(params, reader);
|
||||
case ESM4::REC_KYWD:
|
||||
break;
|
||||
case ESM4::REC_LAND:
|
||||
return readTypedRecord<ESM4::Land>(params, reader);
|
||||
case ESM4::REC_LCRT:
|
||||
break;
|
||||
case ESM4::REC_LCTN:
|
||||
break;
|
||||
case ESM4::REC_LGTM:
|
||||
return readTypedRecord<ESM4::LightingTemplate>(params, reader);
|
||||
case ESM4::REC_LIGH:
|
||||
return readTypedRecord<ESM4::Light>(params, reader);
|
||||
case ESM4::REC_LSCR:
|
||||
break;
|
||||
case ESM4::REC_LTEX:
|
||||
return readTypedRecord<ESM4::LandTexture>(params, reader);
|
||||
case ESM4::REC_LVLC:
|
||||
return readTypedRecord<ESM4::LevelledCreature>(params, reader);
|
||||
case ESM4::REC_LVLI:
|
||||
return readTypedRecord<ESM4::LevelledItem>(params, reader);
|
||||
case ESM4::REC_LVLN:
|
||||
return readTypedRecord<ESM4::LevelledNpc>(params, reader);
|
||||
case ESM4::REC_LVSP:
|
||||
break;
|
||||
case ESM4::REC_MATO:
|
||||
return readTypedRecord<ESM4::Material>(params, reader);
|
||||
case ESM4::REC_MATT:
|
||||
break;
|
||||
case ESM4::REC_MESG:
|
||||
break;
|
||||
case ESM4::REC_MGEF:
|
||||
break;
|
||||
case ESM4::REC_MISC:
|
||||
return readTypedRecord<ESM4::MiscItem>(params, reader);
|
||||
case ESM4::REC_MOVT:
|
||||
break;
|
||||
case ESM4::REC_MSET:
|
||||
return readTypedRecord<ESM4::MediaSet>(params, reader);
|
||||
case ESM4::REC_MSTT:
|
||||
return readTypedRecord<ESM4::MovableStatic>(params, reader);
|
||||
case ESM4::REC_MUSC:
|
||||
return readTypedRecord<ESM4::Music>(params, reader);
|
||||
case ESM4::REC_MUST:
|
||||
break;
|
||||
case ESM4::REC_NAVI:
|
||||
return readTypedRecord<ESM4::Navigation>(params, reader);
|
||||
case ESM4::REC_NAVM:
|
||||
return readTypedRecord<ESM4::NavMesh>(params, reader);
|
||||
case ESM4::REC_NOTE:
|
||||
return readTypedRecord<ESM4::Note>(params, reader);
|
||||
case ESM4::REC_NPC_:
|
||||
return readTypedRecord<ESM4::Npc>(params, reader);
|
||||
case ESM4::REC_OTFT:
|
||||
return readTypedRecord<ESM4::Outfit>(params, reader);
|
||||
case ESM4::REC_PACK:
|
||||
return readTypedRecord<ESM4::AIPackage>(params, reader);
|
||||
case ESM4::REC_PERK:
|
||||
break;
|
||||
case ESM4::REC_PGRD:
|
||||
return readTypedRecord<ESM4::Pathgrid>(params, reader);
|
||||
case ESM4::REC_PGRE:
|
||||
return readTypedRecord<ESM4::PlacedGrenade>(params, reader);
|
||||
case ESM4::REC_PHZD:
|
||||
break;
|
||||
case ESM4::REC_PROJ:
|
||||
break;
|
||||
case ESM4::REC_PWAT:
|
||||
return readTypedRecord<ESM4::PlaceableWater>(params, reader);
|
||||
case ESM4::REC_QUST:
|
||||
return readTypedRecord<ESM4::Quest>(params, reader);
|
||||
case ESM4::REC_RACE:
|
||||
return readTypedRecord<ESM4::Race>(params, reader);
|
||||
case ESM4::REC_REFR:
|
||||
return readTypedRecord<ESM4::Reference>(params, reader);
|
||||
case ESM4::REC_REGN:
|
||||
return readTypedRecord<ESM4::Region>(params, reader);
|
||||
case ESM4::REC_RELA:
|
||||
break;
|
||||
case ESM4::REC_REVB:
|
||||
break;
|
||||
case ESM4::REC_RFCT:
|
||||
break;
|
||||
case ESM4::REC_ROAD:
|
||||
return readTypedRecord<ESM4::Road>(params, reader);
|
||||
case ESM4::REC_SBSP:
|
||||
return readTypedRecord<ESM4::SubSpace>(params, reader);
|
||||
case ESM4::REC_SCEN:
|
||||
break;
|
||||
case ESM4::REC_SCOL:
|
||||
return readTypedRecord<ESM4::StaticCollection>(params, reader);
|
||||
case ESM4::REC_SCPT:
|
||||
return readTypedRecord<ESM4::Script>(params, reader);
|
||||
case ESM4::REC_SCRL:
|
||||
return readTypedRecord<ESM4::Scroll>(params, reader);
|
||||
case ESM4::REC_SGST:
|
||||
return readTypedRecord<ESM4::SigilStone>(params, reader);
|
||||
case ESM4::REC_SHOU:
|
||||
break;
|
||||
case ESM4::REC_SLGM:
|
||||
return readTypedRecord<ESM4::SoulGem>(params, reader);
|
||||
case ESM4::REC_SMBN:
|
||||
break;
|
||||
case ESM4::REC_SMEN:
|
||||
break;
|
||||
case ESM4::REC_SMQN:
|
||||
break;
|
||||
case ESM4::REC_SNCT:
|
||||
break;
|
||||
case ESM4::REC_SNDR:
|
||||
return readTypedRecord<ESM4::SoundReference>(params, reader);
|
||||
case ESM4::REC_SOPM:
|
||||
break;
|
||||
case ESM4::REC_SOUN:
|
||||
return readTypedRecord<ESM4::Sound>(params, reader);
|
||||
case ESM4::REC_SPEL:
|
||||
break;
|
||||
case ESM4::REC_SPGD:
|
||||
break;
|
||||
case ESM4::REC_STAT:
|
||||
return readTypedRecord<ESM4::Static>(params, reader);
|
||||
case ESM4::REC_TACT:
|
||||
return readTypedRecord<ESM4::TalkingActivator>(params, reader);
|
||||
case ESM4::REC_TERM:
|
||||
return readTypedRecord<ESM4::Terminal>(params, reader);
|
||||
case ESM4::REC_TES4:
|
||||
return readTypedRecord<ESM4::Header>(params, reader);
|
||||
case ESM4::REC_TREE:
|
||||
return readTypedRecord<ESM4::Tree>(params, reader);
|
||||
case ESM4::REC_TXST:
|
||||
return readTypedRecord<ESM4::TextureSet>(params, reader);
|
||||
case ESM4::REC_VTYP:
|
||||
break;
|
||||
case ESM4::REC_WATR:
|
||||
break;
|
||||
case ESM4::REC_WEAP:
|
||||
return readTypedRecord<ESM4::Weapon>(params, reader);
|
||||
case ESM4::REC_WOOP:
|
||||
break;
|
||||
case ESM4::REC_WRLD:
|
||||
return readTypedRecord<ESM4::World>(params, reader);
|
||||
case ESM4::REC_WTHR:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!params.mQuite)
|
||||
@ -307,8 +481,8 @@ namespace EsmTool
|
||||
const ESM4::RecordHeader& header = reader.hdr();
|
||||
|
||||
if (!params.mQuite)
|
||||
std::cout << "\nGroup: " << toString(static_cast<ESM4::GroupType>(header.group.type))
|
||||
<< " " << ESM::NAME(header.group.typeId).toStringView() << '\n';
|
||||
std::cout << "\nGroup: " << toString(static_cast<ESM4::GroupType>(header.group.type)) << " "
|
||||
<< ESM::NAME(header.group.typeId).toStringView() << '\n';
|
||||
|
||||
switch (static_cast<ESM4::GroupType>(header.group.type))
|
||||
{
|
||||
@ -366,8 +540,8 @@ namespace EsmTool
|
||||
if (!params.mQuite)
|
||||
{
|
||||
std::cout << "Author: " << reader.getAuthor() << '\n'
|
||||
<< "Description: " << reader.getDesc() << '\n'
|
||||
<< "File format version: " << reader.esmVersion() << '\n';
|
||||
<< "Description: " << reader.getDesc() << '\n'
|
||||
<< "File format version: " << reader.esmVersion() << '\n';
|
||||
|
||||
if (const std::vector<ESM::MasterData>& masterData = reader.getGameFiles(); !masterData.empty())
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include <components/misc/strings/lower.hpp>
|
||||
|
||||
@ -18,16 +18,16 @@ namespace ESSImport
|
||||
return mwIndex;
|
||||
}
|
||||
|
||||
void convertACDT (const ACDT& acdt, ESM::CreatureStats& cStats)
|
||||
void convertACDT(const ACDT& acdt, ESM::CreatureStats& cStats)
|
||||
{
|
||||
for (int i=0; i<3; ++i)
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
int writeIndex = translateDynamicIndex(i);
|
||||
cStats.mDynamic[writeIndex].mBase = acdt.mDynamic[i][1];
|
||||
cStats.mDynamic[writeIndex].mMod = 0.f;
|
||||
cStats.mDynamic[writeIndex].mCurrent = acdt.mDynamic[i][0];
|
||||
}
|
||||
for (int i=0; i<8; ++i)
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
cStats.mAttributes[i].mBase = acdt.mAttributes[i][1];
|
||||
cStats.mAttributes[i].mMod = 0.f;
|
||||
@ -38,14 +38,14 @@ namespace ESSImport
|
||||
cStats.mAttacked = (acdt.mFlags & Attacked) != 0;
|
||||
}
|
||||
|
||||
void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats)
|
||||
void convertACSC(const ACSC& acsc, ESM::CreatureStats& cStats)
|
||||
{
|
||||
cStats.mDead = (acsc.mFlags & Dead) != 0;
|
||||
}
|
||||
|
||||
void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats)
|
||||
void convertNpcData(const ActorData& actorData, ESM::NpcStats& npcStats)
|
||||
{
|
||||
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
{
|
||||
npcStats.mSkills[i].mMod = 0.f;
|
||||
npcStats.mSkills[i].mCurrent = actorData.mSkills[i][1];
|
||||
@ -55,32 +55,29 @@ namespace ESSImport
|
||||
npcStats.mTimeToStartDrowning = actorData.mACDT.mBreathMeter;
|
||||
}
|
||||
|
||||
void convertANIS (const ANIS& anis, ESM::AnimationState& state)
|
||||
void convertANIS(const ANIS& anis, ESM::AnimationState& state)
|
||||
{
|
||||
static const char* animGroups[] =
|
||||
{
|
||||
"Idle", "Idle2", "Idle3", "Idle4", "Idle5", "Idle6", "Idle7", "Idle8", "Idle9", "Idlehh", "Idle1h", "Idle2c",
|
||||
"Idle2w", "IdleSwim", "IdleSpell", "IdleCrossbow", "IdleSneak", "IdleStorm", "Torch", "Hit1", "Hit2", "Hit3",
|
||||
"Hit4", "Hit5", "SwimHit1", "SwimHit2", "SwimHit3", "Death1", "Death2", "Death3", "Death4", "Death5",
|
||||
"DeathKnockDown", "DeathKnockOut", "KnockDown", "KnockOut", "SwimDeath", "SwimDeath2", "SwimDeath3",
|
||||
"SwimDeathKnockDown", "SwimDeathKnockOut", "SwimKnockOut", "SwimKnockDown", "SwimWalkForward",
|
||||
"SwimWalkBack", "SwimWalkLeft", "SwimWalkRight", "SwimRunForward", "SwimRunBack", "SwimRunLeft",
|
||||
"SwimRunRight", "SwimTurnLeft", "SwimTurnRight", "WalkForward", "WalkBack", "WalkLeft", "WalkRight",
|
||||
"TurnLeft", "TurnRight", "RunForward", "RunBack", "RunLeft", "RunRight", "SneakForward", "SneakBack",
|
||||
"SneakLeft", "SneakRight", "Jump", "WalkForwardhh", "WalkBackhh", "WalkLefthh", "WalkRighthh",
|
||||
"TurnLefthh", "TurnRighthh", "RunForwardhh", "RunBackhh", "RunLefthh", "RunRighthh", "SneakForwardhh",
|
||||
"SneakBackhh", "SneakLefthh", "SneakRighthh", "Jumphh", "WalkForward1h", "WalkBack1h", "WalkLeft1h",
|
||||
"WalkRight1h", "TurnLeft1h", "TurnRight1h", "RunForward1h", "RunBack1h", "RunLeft1h", "RunRight1h",
|
||||
"SneakForward1h", "SneakBack1h", "SneakLeft1h", "SneakRight1h", "Jump1h", "WalkForward2c", "WalkBack2c",
|
||||
"WalkLeft2c", "WalkRight2c", "TurnLeft2c", "TurnRight2c", "RunForward2c", "RunBack2c", "RunLeft2c",
|
||||
"RunRight2c", "SneakForward2c", "SneakBack2c", "SneakLeft2c", "SneakRight2c", "Jump2c", "WalkForward2w",
|
||||
"WalkBack2w", "WalkLeft2w", "WalkRight2w", "TurnLeft2w", "TurnRight2w", "RunForward2w", "RunBack2w",
|
||||
"RunLeft2w", "RunRight2w", "SneakForward2w", "SneakBack2w", "SneakLeft2w", "SneakRight2w", "Jump2w",
|
||||
"SpellCast", "SpellTurnLeft", "SpellTurnRight", "Attack1", "Attack2", "Attack3", "SwimAttack1",
|
||||
static const char* animGroups[] = { "Idle", "Idle2", "Idle3", "Idle4", "Idle5", "Idle6", "Idle7", "Idle8",
|
||||
"Idle9", "Idlehh", "Idle1h", "Idle2c", "Idle2w", "IdleSwim", "IdleSpell", "IdleCrossbow", "IdleSneak",
|
||||
"IdleStorm", "Torch", "Hit1", "Hit2", "Hit3", "Hit4", "Hit5", "SwimHit1", "SwimHit2", "SwimHit3", "Death1",
|
||||
"Death2", "Death3", "Death4", "Death5", "DeathKnockDown", "DeathKnockOut", "KnockDown", "KnockOut",
|
||||
"SwimDeath", "SwimDeath2", "SwimDeath3", "SwimDeathKnockDown", "SwimDeathKnockOut", "SwimKnockOut",
|
||||
"SwimKnockDown", "SwimWalkForward", "SwimWalkBack", "SwimWalkLeft", "SwimWalkRight", "SwimRunForward",
|
||||
"SwimRunBack", "SwimRunLeft", "SwimRunRight", "SwimTurnLeft", "SwimTurnRight", "WalkForward", "WalkBack",
|
||||
"WalkLeft", "WalkRight", "TurnLeft", "TurnRight", "RunForward", "RunBack", "RunLeft", "RunRight",
|
||||
"SneakForward", "SneakBack", "SneakLeft", "SneakRight", "Jump", "WalkForwardhh", "WalkBackhh", "WalkLefthh",
|
||||
"WalkRighthh", "TurnLefthh", "TurnRighthh", "RunForwardhh", "RunBackhh", "RunLefthh", "RunRighthh",
|
||||
"SneakForwardhh", "SneakBackhh", "SneakLefthh", "SneakRighthh", "Jumphh", "WalkForward1h", "WalkBack1h",
|
||||
"WalkLeft1h", "WalkRight1h", "TurnLeft1h", "TurnRight1h", "RunForward1h", "RunBack1h", "RunLeft1h",
|
||||
"RunRight1h", "SneakForward1h", "SneakBack1h", "SneakLeft1h", "SneakRight1h", "Jump1h", "WalkForward2c",
|
||||
"WalkBack2c", "WalkLeft2c", "WalkRight2c", "TurnLeft2c", "TurnRight2c", "RunForward2c", "RunBack2c",
|
||||
"RunLeft2c", "RunRight2c", "SneakForward2c", "SneakBack2c", "SneakLeft2c", "SneakRight2c", "Jump2c",
|
||||
"WalkForward2w", "WalkBack2w", "WalkLeft2w", "WalkRight2w", "TurnLeft2w", "TurnRight2w", "RunForward2w",
|
||||
"RunBack2w", "RunLeft2w", "RunRight2w", "SneakForward2w", "SneakBack2w", "SneakLeft2w", "SneakRight2w",
|
||||
"Jump2w", "SpellCast", "SpellTurnLeft", "SpellTurnRight", "Attack1", "Attack2", "Attack3", "SwimAttack1",
|
||||
"SwimAttack2", "SwimAttack3", "HandToHand", "Crossbow", "BowAndArrow", "ThrowWeapon", "WeaponOneHand",
|
||||
"WeaponTwoHand", "WeaponTwoWide", "Shield", "PickProbe", "InventoryHandToHand", "InventoryWeaponOneHand",
|
||||
"InventoryWeaponTwoHand", "InventoryWeaponTwoWide"
|
||||
};
|
||||
"InventoryWeaponTwoHand", "InventoryWeaponTwoWide" };
|
||||
|
||||
if (anis.mGroupIndex < (sizeof(animGroups) / sizeof(*animGroups)))
|
||||
{
|
||||
|
@ -1,10 +1,10 @@
|
||||
#ifndef OPENMW_ESSIMPORT_CONVERTACDT_H
|
||||
#define OPENMW_ESSIMPORT_CONVERTACDT_H
|
||||
|
||||
#include <components/esm3/creaturestats.hpp>
|
||||
#include <components/esm3/npcstats.hpp>
|
||||
#include <components/esm3/loadskil.hpp>
|
||||
#include <components/esm3/animationstate.hpp>
|
||||
#include <components/esm3/creaturestats.hpp>
|
||||
#include <components/esm3/loadskil.hpp>
|
||||
#include <components/esm3/npcstats.hpp>
|
||||
|
||||
#include "importacdt.hpp"
|
||||
|
||||
@ -14,13 +14,12 @@ namespace ESSImport
|
||||
// OpenMW uses Health,Magicka,Fatigue, MW uses Health,Fatigue,Magicka
|
||||
int translateDynamicIndex(int mwIndex);
|
||||
|
||||
void convertACDT(const ACDT& acdt, ESM::CreatureStats& cStats);
|
||||
void convertACSC(const ACSC& acsc, ESM::CreatureStats& cStats);
|
||||
|
||||
void convertACDT (const ACDT& acdt, ESM::CreatureStats& cStats);
|
||||
void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats);
|
||||
void convertNpcData(const ActorData& actorData, ESM::NpcStats& npcStats);
|
||||
|
||||
void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats);
|
||||
|
||||
void convertANIS (const ANIS& anis, ESM::AnimationState& state);
|
||||
void convertANIS(const ANIS& anis, ESM::AnimationState& state);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertCNTC(const CNTC &cntc, ESM::ContainerState &state)
|
||||
void convertCNTC(const CNTC& cntc, ESM::ContainerState& state)
|
||||
{
|
||||
convertInventory(cntc.mInventory, state.mInventory);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertCREC(const CREC &crec, ESM::CreatureState &state)
|
||||
void convertCREC(const CREC& crec, ESM::CreatureState& state)
|
||||
{
|
||||
convertInventory(crec.mInventory, state.mInventory);
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
#include "converter.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <osgDB/WriteFile>
|
||||
|
||||
#include <components/esm3/creaturestate.hpp>
|
||||
#include <components/esm3/containerstate.hpp>
|
||||
#include <components/esm3/creaturestate.hpp>
|
||||
|
||||
#include <components/misc/constants.hpp>
|
||||
|
||||
#include "convertcrec.hpp"
|
||||
#include "convertcntc.hpp"
|
||||
#include "convertcrec.hpp"
|
||||
#include "convertscri.hpp"
|
||||
|
||||
namespace
|
||||
@ -19,7 +19,7 @@ namespace
|
||||
|
||||
void convertImage(char* data, int size, int width, int height, GLenum pf, const std::string& out)
|
||||
{
|
||||
osg::ref_ptr<osg::Image> image (new osg::Image);
|
||||
osg::ref_ptr<osg::Image> image(new osg::Image);
|
||||
image->allocateImage(width, height, 1, pf, GL_UNSIGNED_BYTE);
|
||||
memcpy(image->data(), data, size);
|
||||
image->flipVertical();
|
||||
@ -27,7 +27,6 @@ namespace
|
||||
osgDB::writeImageFile(*image, out);
|
||||
}
|
||||
|
||||
|
||||
void convertCellRef(const ESSImport::CellRef& cellref, ESM::ObjectState& objstate)
|
||||
{
|
||||
objstate.mEnabled = cellref.mEnabled;
|
||||
@ -51,17 +50,17 @@ namespace
|
||||
return false; // entirely numeric refid, this is a reference to
|
||||
// a dynamically created record e.g. player-enchanted weapon
|
||||
|
||||
std::string index = indexedRefId.substr(indexedRefId.size()-8);
|
||||
std::string index = indexedRefId.substr(indexedRefId.size() - 8);
|
||||
return index.find_first_not_of("0123456789ABCDEF") == std::string::npos;
|
||||
}
|
||||
|
||||
void splitIndexedRefId(const std::string& indexedRefId, int& refIndex, std::string& refId)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << std::hex << indexedRefId.substr(indexedRefId.size()-8,8);
|
||||
stream << std::hex << indexedRefId.substr(indexedRefId.size() - 8, 8);
|
||||
stream >> refIndex;
|
||||
|
||||
refId = indexedRefId.substr(0,indexedRefId.size()-8);
|
||||
refId = indexedRefId.substr(0, indexedRefId.size() - 8);
|
||||
}
|
||||
|
||||
int convertActorId(const std::string& indexedRefId, ESSImport::Context& context)
|
||||
@ -89,14 +88,13 @@ namespace
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
|
||||
struct MAPH
|
||||
{
|
||||
unsigned int size;
|
||||
unsigned int value;
|
||||
};
|
||||
|
||||
void ConvertFMAP::read(ESM::ESMReader &esm)
|
||||
void ConvertFMAP::read(ESM::ESMReader& esm)
|
||||
{
|
||||
MAPH maph;
|
||||
esm.getHNT(maph, "MAPH");
|
||||
@ -112,55 +110,55 @@ namespace ESSImport
|
||||
|
||||
// to match openmw size
|
||||
// FIXME: filtering?
|
||||
mGlobalMapImage->scaleImage(maph.size*2, maph.size*2, 1, GL_UNSIGNED_BYTE);
|
||||
mGlobalMapImage->scaleImage(maph.size * 2, maph.size * 2, 1, GL_UNSIGNED_BYTE);
|
||||
}
|
||||
|
||||
void ConvertFMAP::write(ESM::ESMWriter &esm)
|
||||
void ConvertFMAP::write(ESM::ESMWriter& esm)
|
||||
{
|
||||
int numcells = mGlobalMapImage->s() / 18; // NB truncating, doesn't divide perfectly
|
||||
// with the 512x512 map the game has by default
|
||||
int cellSize = mGlobalMapImage->s()/numcells;
|
||||
// with the 512x512 map the game has by default
|
||||
int cellSize = mGlobalMapImage->s() / numcells;
|
||||
|
||||
// Note the upper left corner of the (0,0) cell should be at (width/2, height/2)
|
||||
|
||||
mContext->mGlobalMapState.mBounds.mMinX = -numcells/2;
|
||||
mContext->mGlobalMapState.mBounds.mMaxX = (numcells-1)/2;
|
||||
mContext->mGlobalMapState.mBounds.mMinY = -(numcells-1)/2;
|
||||
mContext->mGlobalMapState.mBounds.mMaxY = numcells/2;
|
||||
mContext->mGlobalMapState.mBounds.mMinX = -numcells / 2;
|
||||
mContext->mGlobalMapState.mBounds.mMaxX = (numcells - 1) / 2;
|
||||
mContext->mGlobalMapState.mBounds.mMinY = -(numcells - 1) / 2;
|
||||
mContext->mGlobalMapState.mBounds.mMaxY = numcells / 2;
|
||||
|
||||
osg::ref_ptr<osg::Image> image2 (new osg::Image);
|
||||
int width = cellSize*numcells;
|
||||
int height = cellSize*numcells;
|
||||
osg::ref_ptr<osg::Image> image2(new osg::Image);
|
||||
int width = cellSize * numcells;
|
||||
int height = cellSize * numcells;
|
||||
std::vector<unsigned char> data;
|
||||
data.resize(width*height*4, 0);
|
||||
data.resize(width * height * 4, 0);
|
||||
|
||||
image2->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
|
||||
memcpy(image2->data(), data.data(), data.size());
|
||||
|
||||
for (const auto & exploredCell : mContext->mExploredCells)
|
||||
for (const auto& exploredCell : mContext->mExploredCells)
|
||||
{
|
||||
if (exploredCell.first > mContext->mGlobalMapState.mBounds.mMaxX
|
||||
|| exploredCell.first < mContext->mGlobalMapState.mBounds.mMinX
|
||||
|| exploredCell.second > mContext->mGlobalMapState.mBounds.mMaxY
|
||||
|| exploredCell.second < mContext->mGlobalMapState.mBounds.mMinY)
|
||||
|| exploredCell.first < mContext->mGlobalMapState.mBounds.mMinX
|
||||
|| exploredCell.second > mContext->mGlobalMapState.mBounds.mMaxY
|
||||
|| exploredCell.second < mContext->mGlobalMapState.mBounds.mMinY)
|
||||
{
|
||||
// out of bounds, I think this could happen, since the original engine had a fixed-size map
|
||||
continue;
|
||||
}
|
||||
|
||||
int imageLeftSrc = mGlobalMapImage->s()/2;
|
||||
int imageTopSrc = mGlobalMapImage->t()/2;
|
||||
int imageLeftSrc = mGlobalMapImage->s() / 2;
|
||||
int imageTopSrc = mGlobalMapImage->t() / 2;
|
||||
imageLeftSrc += exploredCell.first * cellSize;
|
||||
imageTopSrc -= exploredCell.second * cellSize;
|
||||
int imageLeftDst = width/2;
|
||||
int imageTopDst = height/2;
|
||||
int imageLeftDst = width / 2;
|
||||
int imageTopDst = height / 2;
|
||||
imageLeftDst += exploredCell.first * cellSize;
|
||||
imageTopDst -= exploredCell.second * cellSize;
|
||||
for (int x=0; x<cellSize; ++x)
|
||||
for (int y=0; y<cellSize; ++y)
|
||||
for (int x = 0; x < cellSize; ++x)
|
||||
for (int y = 0; y < cellSize; ++y)
|
||||
{
|
||||
unsigned int col = *(unsigned int*)mGlobalMapImage->data(imageLeftSrc+x, imageTopSrc+y, 0);
|
||||
*(unsigned int*)image2->data(imageLeftDst+x, imageTopDst+y, 0) = col;
|
||||
unsigned int col = *(unsigned int*)mGlobalMapImage->data(imageLeftSrc + x, imageTopSrc + y, 0);
|
||||
*(unsigned int*)image2->data(imageLeftDst + x, imageTopDst + y, 0) = col;
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,7 +175,8 @@ namespace ESSImport
|
||||
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image2, ostream);
|
||||
if (!result.success())
|
||||
{
|
||||
std::cerr << "Error: can't write global map image: " << result.message() << " code " << result.status() << std::endl;
|
||||
std::cerr << "Error: can't write global map image: " << result.message() << " code " << result.status()
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -189,7 +188,7 @@ namespace ESSImport
|
||||
esm.endRecord(ESM::REC_GMAP);
|
||||
}
|
||||
|
||||
void ConvertCell::read(ESM::ESMReader &esm)
|
||||
void ConvertCell::read(ESM::ESMReader& esm)
|
||||
{
|
||||
ESM::Cell cell;
|
||||
bool isDeleted = false;
|
||||
@ -234,15 +233,15 @@ namespace ESSImport
|
||||
|
||||
esm.getExact(nam8, 32);
|
||||
|
||||
newcell.mFogOfWar.reserve(16*16);
|
||||
for (int x=0; x<16; ++x)
|
||||
newcell.mFogOfWar.reserve(16 * 16);
|
||||
for (int x = 0; x < 16; ++x)
|
||||
{
|
||||
for (int y=0; y<16; ++y)
|
||||
for (int y = 0; y < 16; ++y)
|
||||
{
|
||||
size_t pos = x*16+y;
|
||||
size_t bytepos = pos/8;
|
||||
assert(bytepos<32);
|
||||
int bit = pos%8;
|
||||
size_t pos = x * 16 + y;
|
||||
size_t bytepos = pos / 8;
|
||||
assert(bytepos < 32);
|
||||
int bit = pos % 8;
|
||||
newcell.mFogOfWar.push_back(((nam8[bytepos] >> bit) & (0x1)) ? 0xffffffff : 0x000000ff);
|
||||
}
|
||||
}
|
||||
@ -252,7 +251,8 @@ namespace ESSImport
|
||||
std::ostringstream filename;
|
||||
filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga";
|
||||
|
||||
convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, GL_RGBA, filename.str());
|
||||
convertImage(
|
||||
(char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size() * 4, 16, 16, GL_RGBA, filename.str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,7 +271,7 @@ namespace ESSImport
|
||||
while (esm.hasMoreSubs() && esm.peekNextSub("FRMR"))
|
||||
{
|
||||
CellRef ref;
|
||||
ref.load (esm);
|
||||
ref.load(esm);
|
||||
cellrefs.push_back(ref);
|
||||
}
|
||||
|
||||
@ -307,14 +307,13 @@ namespace ESSImport
|
||||
|
||||
newcell.mRefs = cellrefs;
|
||||
|
||||
|
||||
if (cell.isExterior())
|
||||
mExtCells[std::make_pair(cell.mData.mX, cell.mData.mY)] = newcell;
|
||||
else
|
||||
mIntCells[cell.mName] = newcell;
|
||||
}
|
||||
|
||||
void ConvertCell::writeCell(const Cell &cell, ESM::ESMWriter& esm)
|
||||
void ConvertCell::writeCell(const Cell& cell, ESM::ESMWriter& esm)
|
||||
{
|
||||
ESM::Cell esmcell = cell.mCell;
|
||||
esm.startRecord(ESM::REC_CSTA);
|
||||
@ -329,9 +328,9 @@ namespace ESSImport
|
||||
csta.mWaterLevel = esmcell.mWater;
|
||||
csta.save(esm);
|
||||
|
||||
for (const auto & cellref : cell.mRefs)
|
||||
for (const auto& cellref : cell.mRefs)
|
||||
{
|
||||
ESM::CellRef out (cellref);
|
||||
ESM::CellRef out(cellref);
|
||||
|
||||
// TODO: use mContext->mCreatures/mNpcs
|
||||
|
||||
@ -348,7 +347,7 @@ namespace ESSImport
|
||||
objstate.mRef.mRefID = idLower;
|
||||
objstate.mHasCustomState = false;
|
||||
convertCellRef(cellref, objstate);
|
||||
esm.writeHNT ("OBJE", 0);
|
||||
esm.writeHNT("OBJE", 0);
|
||||
objstate.save(esm);
|
||||
continue;
|
||||
}
|
||||
@ -359,8 +358,7 @@ namespace ESSImport
|
||||
|
||||
std::string idLower = Misc::StringUtils::lowerCase(out.mRefID);
|
||||
|
||||
auto npccIt = mContext->mNpcChanges.find(
|
||||
std::make_pair(refIndex, out.mRefID));
|
||||
auto npccIt = mContext->mNpcChanges.find(std::make_pair(refIndex, out.mRefID));
|
||||
if (npccIt != mContext->mNpcChanges.end())
|
||||
{
|
||||
ESM::NpcState objstate;
|
||||
@ -380,15 +378,15 @@ namespace ESSImport
|
||||
convertCellRef(cellref, objstate);
|
||||
|
||||
objstate.mCreatureStats.mActorId = mContext->generateActorId();
|
||||
mContext->mActorIdMap.insert(std::make_pair(std::make_pair(refIndex, out.mRefID), objstate.mCreatureStats.mActorId));
|
||||
mContext->mActorIdMap.insert(
|
||||
std::make_pair(std::make_pair(refIndex, out.mRefID), objstate.mCreatureStats.mActorId));
|
||||
|
||||
esm.writeHNT ("OBJE", ESM::REC_NPC_);
|
||||
esm.writeHNT("OBJE", ESM::REC_NPC_);
|
||||
objstate.save(esm);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto cntcIt = mContext->mContainerChanges.find(
|
||||
std::make_pair(refIndex, out.mRefID));
|
||||
auto cntcIt = mContext->mContainerChanges.find(std::make_pair(refIndex, out.mRefID));
|
||||
if (cntcIt != mContext->mContainerChanges.end())
|
||||
{
|
||||
ESM::ContainerState objstate;
|
||||
@ -397,13 +395,12 @@ namespace ESSImport
|
||||
objstate.mRef.mRefID = idLower;
|
||||
convertCNTC(cntcIt->second, objstate);
|
||||
convertCellRef(cellref, objstate);
|
||||
esm.writeHNT ("OBJE", ESM::REC_CONT);
|
||||
esm.writeHNT("OBJE", ESM::REC_CONT);
|
||||
objstate.save(esm);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto crecIt = mContext->mCreatureChanges.find(
|
||||
std::make_pair(refIndex, out.mRefID));
|
||||
auto crecIt = mContext->mCreatureChanges.find(std::make_pair(refIndex, out.mRefID));
|
||||
if (crecIt != mContext->mCreatureChanges.end())
|
||||
{
|
||||
ESM::CreatureState objstate;
|
||||
@ -422,9 +419,10 @@ namespace ESSImport
|
||||
convertCellRef(cellref, objstate);
|
||||
|
||||
objstate.mCreatureStats.mActorId = mContext->generateActorId();
|
||||
mContext->mActorIdMap.insert(std::make_pair(std::make_pair(refIndex, out.mRefID), objstate.mCreatureStats.mActorId));
|
||||
mContext->mActorIdMap.insert(
|
||||
std::make_pair(std::make_pair(refIndex, out.mRefID), objstate.mCreatureStats.mActorId));
|
||||
|
||||
esm.writeHNT ("OBJE", ESM::REC_CREA);
|
||||
esm.writeHNT("OBJE", ESM::REC_CREA);
|
||||
objstate.save(esm);
|
||||
continue;
|
||||
}
|
||||
@ -438,15 +436,15 @@ namespace ESSImport
|
||||
esm.endRecord(ESM::REC_CSTA);
|
||||
}
|
||||
|
||||
void ConvertCell::write(ESM::ESMWriter &esm)
|
||||
void ConvertCell::write(ESM::ESMWriter& esm)
|
||||
{
|
||||
for (const auto & cell : mIntCells)
|
||||
for (const auto& cell : mIntCells)
|
||||
writeCell(cell.second, esm);
|
||||
|
||||
for (const auto & cell : mExtCells)
|
||||
for (const auto& cell : mExtCells)
|
||||
writeCell(cell.second, esm);
|
||||
|
||||
for (const auto & marker : mMarkers)
|
||||
for (const auto& marker : mMarkers)
|
||||
{
|
||||
esm.startRecord(ESM::REC_MARK);
|
||||
marker.save(esm);
|
||||
@ -482,11 +480,12 @@ namespace ESSImport
|
||||
convertBaseState(out, pnam);
|
||||
|
||||
auto it = std::find_if(mContext->mActiveSpells.begin(), mContext->mActiveSpells.end(),
|
||||
[&pnam](const SPLM::ActiveSpell& spell) -> bool { return spell.mIndex == pnam.mSplmIndex; });
|
||||
[&pnam](const SPLM::ActiveSpell& spell) -> bool { return spell.mIndex == pnam.mSplmIndex; });
|
||||
|
||||
if (it == mContext->mActiveSpells.end())
|
||||
{
|
||||
std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString() << "\" (invalid spell link)" << std::endl;
|
||||
std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString()
|
||||
<< "\" (invalid spell link)" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -507,7 +506,7 @@ namespace ESSImport
|
||||
base.mPosition = pnam.mPosition;
|
||||
|
||||
osg::Quat orient;
|
||||
orient.makeRotate(osg::Vec3f(0,1,0), pnam.mVelocity);
|
||||
orient.makeRotate(osg::Vec3f(0, 1, 0), pnam.mVelocity);
|
||||
base.mOrientation = orient;
|
||||
|
||||
base.mActorId = convertActorId(pnam.mActorId.toString(), *mContext);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,17 +7,17 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertInventory(const Inventory &inventory, ESM::InventoryState &state)
|
||||
void convertInventory(const Inventory& inventory, ESM::InventoryState& state)
|
||||
{
|
||||
int index = 0;
|
||||
for (const auto & item : inventory.mItems)
|
||||
for (const auto& item : inventory.mItems)
|
||||
{
|
||||
ESM::ObjectState objstate;
|
||||
objstate.blank();
|
||||
objstate.mRef = item;
|
||||
objstate.mRef.mRefID = Misc::StringUtils::lowerCase(item.mId);
|
||||
objstate.mCount = std::abs(item.mCount); // restocking items have negative count in the savefile
|
||||
// openmw handles them differently, so no need to set any flags
|
||||
// openmw handles them differently, so no need to set any flags
|
||||
state.mItems.push_back(objstate);
|
||||
if (item.mRelativeEquipmentSlot != -1)
|
||||
// Note we should really write the absolute slot here, which we do not know about
|
||||
|
@ -8,7 +8,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertInventory (const Inventory& inventory, ESM::InventoryState& state);
|
||||
void convertInventory(const Inventory& inventory, ESM::InventoryState& state);
|
||||
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertNPCC(const NPCC &npcc, ESM::NpcState &npcState)
|
||||
void convertNPCC(const NPCC& npcc, ESM::NpcState& npcState)
|
||||
{
|
||||
npcState.mNpcStats.mDisposition = npcc.mNPDT.mDisposition;
|
||||
npcState.mNpcStats.mReputation = npcc.mNPDT.mReputation;
|
||||
|
@ -8,7 +8,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertNPCC (const NPCC& npcc, ESM::NpcState& npcState);
|
||||
void convertNPCC(const NPCC& npcc, ESM::NpcState& npcState);
|
||||
|
||||
}
|
||||
|
||||
|
@ -8,13 +8,15 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls)
|
||||
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics,
|
||||
bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls)
|
||||
{
|
||||
out.mObject.mPosition.rot[0] = -atan2(pcdt.mPNAM.mVerticalRotation.mData[2][1], pcdt.mPNAM.mVerticalRotation.mData[2][2]);
|
||||
out.mObject.mPosition.rot[0]
|
||||
= -atan2(pcdt.mPNAM.mVerticalRotation.mData[2][1], pcdt.mPNAM.mVerticalRotation.mData[2][2]);
|
||||
|
||||
out.mBirthsign = pcdt.mBirthsign;
|
||||
out.mObject.mNpcStats.mBounty = pcdt.mBounty;
|
||||
for (const auto & essFaction : pcdt.mFactions)
|
||||
for (const auto& essFaction : pcdt.mFactions)
|
||||
{
|
||||
ESM::NpcStats::Faction faction;
|
||||
faction.mExpelled = (essFaction.mFlags & 0x2) != 0;
|
||||
@ -22,11 +24,11 @@ namespace ESSImport
|
||||
faction.mReputation = essFaction.mReputation;
|
||||
out.mObject.mNpcStats.mFactions[Misc::StringUtils::lowerCase(essFaction.mFactionName.toString())] = faction;
|
||||
}
|
||||
for (int i=0; i<3; ++i)
|
||||
for (int i = 0; i < 3; ++i)
|
||||
out.mObject.mNpcStats.mSpecIncreases[i] = pcdt.mPNAM.mSpecIncreases[i];
|
||||
for (int i=0; i<8; ++i)
|
||||
for (int i = 0; i < 8; ++i)
|
||||
out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i];
|
||||
for (int i=0; i<27; ++i)
|
||||
for (int i = 0; i < 27; ++i)
|
||||
out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i];
|
||||
out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress;
|
||||
|
||||
@ -39,7 +41,7 @@ namespace ESSImport
|
||||
teleportingEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_TeleportingDisabled);
|
||||
levitationEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LevitationDisabled);
|
||||
|
||||
for (const auto & knownDialogueTopic : pcdt.mKnownDialogueTopics)
|
||||
for (const auto& knownDialogueTopic : pcdt.mKnownDialogueTopics)
|
||||
{
|
||||
outDialogueTopics.push_back(Misc::StringUtils::lowerCase(knownDialogueTopic));
|
||||
}
|
||||
|
@ -3,13 +3,14 @@
|
||||
|
||||
#include "importplayer.hpp"
|
||||
|
||||
#include <components/esm3/player.hpp>
|
||||
#include <components/esm3/controlsstate.hpp>
|
||||
#include <components/esm3/player.hpp>
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls);
|
||||
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics,
|
||||
bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls);
|
||||
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertSCPT(const SCPT &scpt, ESM::GlobalScript &out)
|
||||
void convertSCPT(const SCPT& scpt, ESM::GlobalScript& out)
|
||||
{
|
||||
out.mId = Misc::StringUtils::lowerCase(scpt.mSCHD.mName.toString());
|
||||
out.mRunning = scpt.mRunning;
|
||||
|
@ -8,7 +8,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertSCPT(const SCPT& scpt, ESM::GlobalScript& out);
|
||||
void convertSCPT(const SCPT& scpt, ESM::GlobalScript& out);
|
||||
|
||||
}
|
||||
|
||||
|
@ -19,12 +19,12 @@ namespace
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertSCRI(const SCRI &scri, ESM::Locals &locals)
|
||||
void convertSCRI(const SCRI& scri, ESM::Locals& locals)
|
||||
{
|
||||
// order *is* important, as we do not have variable names available in this format
|
||||
storeVariables<short, ESM::VT_Short> (scri.mShorts, locals, scri.mScript);
|
||||
storeVariables<int, ESM::VT_Int> (scri.mLongs, locals, scri.mScript);
|
||||
storeVariables<float, ESM::VT_Float> (scri.mFloats, locals, scri.mScript);
|
||||
storeVariables<short, ESM::VT_Short>(scri.mShorts, locals, scri.mScript);
|
||||
storeVariables<int, ESM::VT_Int>(scri.mLongs, locals, scri.mScript);
|
||||
storeVariables<float, ESM::VT_Float>(scri.mFloats, locals, scri.mScript);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace ESSImport
|
||||
{
|
||||
|
||||
/// Convert script variable assignments
|
||||
void convertSCRI (const SCRI& scri, ESM::Locals& locals);
|
||||
void convertSCRI(const SCRI& scri, ESM::Locals& locals);
|
||||
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,8 @@ namespace ESSImport
|
||||
float mDynamic[3][2];
|
||||
unsigned char mUnknown3[16];
|
||||
float mAttributes[8][2];
|
||||
float mMagicEffects[27]; // Effect attributes: https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes
|
||||
float mMagicEffects[27]; // Effect attributes:
|
||||
// https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes
|
||||
unsigned char mUnknown4[4];
|
||||
unsigned int mGoldPool;
|
||||
unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void CellRef::load(ESM::ESMReader &esm)
|
||||
void CellRef::load(ESM::ESMReader& esm)
|
||||
{
|
||||
blank();
|
||||
|
||||
@ -13,7 +13,7 @@ namespace ESSImport
|
||||
|
||||
// this is required since openmw supports more than 255 content files
|
||||
int pluginIndex = (mRefNum.mIndex & 0xff000000) >> 24;
|
||||
mRefNum.mContentFile = pluginIndex-1;
|
||||
mRefNum.mContentFile = pluginIndex - 1;
|
||||
mRefNum.mIndex &= 0x00ffffff;
|
||||
|
||||
mIndexedRefId = esm.getHNString("NAME");
|
||||
@ -39,7 +39,7 @@ namespace ESSImport
|
||||
esm.skipHSub();
|
||||
|
||||
if (esm.isNextSub("MNAM"))
|
||||
esm.skipHSub();
|
||||
esm.skipHSub();
|
||||
|
||||
bool isDeleted = false;
|
||||
ESM::CellRef::loadData(esm, isDeleted);
|
||||
@ -123,10 +123,10 @@ namespace ESSImport
|
||||
|
||||
// FIXME: not all actors have this, add flag
|
||||
if (esm.isNextSub("CHRD")) // npc only
|
||||
esm.getHExact(mActorData.mSkills, 27*2*sizeof(int));
|
||||
esm.getHExact(mActorData.mSkills, 27 * 2 * sizeof(int));
|
||||
|
||||
if (esm.isNextSub("CRED")) // creature only
|
||||
esm.getHExact(mActorData.mCombatStats, 3*2*sizeof(int));
|
||||
esm.getHExact(mActorData.mCombatStats, 3 * 2 * sizeof(int));
|
||||
|
||||
mActorData.mSCRI.load(esm);
|
||||
|
||||
@ -146,7 +146,7 @@ namespace ESSImport
|
||||
// probably some identifier for the creature that has been spawned?
|
||||
unsigned char lvcr;
|
||||
esm.getHT(lvcr);
|
||||
//std::cout << "LVCR: " << (int)lvcr << std::endl;
|
||||
// std::cout << "LVCR: " << (int)lvcr << std::endl;
|
||||
}
|
||||
|
||||
mEnabled = true;
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void CNTC::load(ESM::ESMReader &esm)
|
||||
void CNTC::load(ESM::ESMReader& esm)
|
||||
{
|
||||
mIndex = 0;
|
||||
esm.getHNT(mIndex, "INDX");
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void CREC::load(ESM::ESMReader &esm)
|
||||
void CREC::load(ESM::ESMReader& esm)
|
||||
{
|
||||
esm.getHNT(mIndex, "INDX");
|
||||
|
||||
@ -14,9 +14,8 @@ namespace ESSImport
|
||||
float scale;
|
||||
esm.getHNOT(scale, "XSCL");
|
||||
|
||||
|
||||
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|
||||
|| esm.isNextSub("AI_A"))
|
||||
|| esm.isNextSub("AI_A"))
|
||||
mAiPackages.add(esm);
|
||||
|
||||
mInventory.load(esm);
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void DIAL::load(ESM::ESMReader &esm)
|
||||
void DIAL::load(ESM::ESMReader& esm)
|
||||
{
|
||||
// See ESM::Dialogue::Type enum, not sure why we would need this here though
|
||||
int type = 0;
|
||||
|
@ -1,26 +1,26 @@
|
||||
#include "importer.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <osgDB/ReadFile>
|
||||
#include <osg/ImageUtils>
|
||||
#include <osgDB/ReadFile>
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <components/esm3/esmwriter.hpp>
|
||||
#include <components/esm/defs.hpp>
|
||||
|
||||
#include <components/esm3/savedgame.hpp>
|
||||
#include <components/esm3/player.hpp>
|
||||
#include <components/esm3/savedgame.hpp>
|
||||
|
||||
#include <components/esm3/loadalch.hpp>
|
||||
#include <components/esm3/loadspel.hpp>
|
||||
#include <components/esm3/loadarmo.hpp>
|
||||
#include <components/esm3/loadweap.hpp>
|
||||
#include <components/esm3/loadclot.hpp>
|
||||
#include <components/esm3/loadench.hpp>
|
||||
#include <components/esm3/loadlevlist.hpp>
|
||||
#include <components/esm3/loadspel.hpp>
|
||||
#include <components/esm3/loadweap.hpp>
|
||||
|
||||
#include <components/misc/constants.hpp>
|
||||
|
||||
@ -35,25 +35,25 @@ namespace
|
||||
|
||||
void writeScreenshot(const ESM::Header& fileHeader, ESM::SavedGame& out)
|
||||
{
|
||||
if (fileHeader.mSCRS.size() != 128*128*4)
|
||||
if (fileHeader.mSCRS.size() != 128 * 128 * 4)
|
||||
{
|
||||
std::cerr << "Error: unexpected screenshot size " << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Image> image (new osg::Image);
|
||||
osg::ref_ptr<osg::Image> image(new osg::Image);
|
||||
image->allocateImage(128, 128, 1, GL_RGB, GL_UNSIGNED_BYTE);
|
||||
|
||||
// need to convert pixel format from BGRA to RGB as the jpg readerwriter doesn't support it otherwise
|
||||
auto it = fileHeader.mSCRS.begin();
|
||||
for (int y=0; y<128; ++y)
|
||||
for (int y = 0; y < 128; ++y)
|
||||
{
|
||||
for (int x=0; x<128; ++x)
|
||||
for (int x = 0; x < 128; ++x)
|
||||
{
|
||||
assert(image->data(x,y));
|
||||
*(image->data(x,y)+2) = *it++;
|
||||
*(image->data(x,y)+1) = *it++;
|
||||
*image->data(x,y) = *it++;
|
||||
assert(image->data(x, y));
|
||||
*(image->data(x, y) + 2) = *it++;
|
||||
*(image->data(x, y) + 1) = *it++;
|
||||
*image->data(x, y) = *it++;
|
||||
++it; // skip alpha
|
||||
}
|
||||
}
|
||||
@ -72,7 +72,8 @@ namespace
|
||||
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image, ostream);
|
||||
if (!result.success())
|
||||
{
|
||||
std::cerr << "Error: can't write screenshot: " << result.message() << " code " << result.status() << std::endl;
|
||||
std::cerr << "Error: can't write screenshot: " << result.message() << " code " << result.status()
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -85,12 +86,12 @@ namespace
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
Importer::Importer(const std::filesystem::path &essfile, const std::filesystem::path &outfile, const std::string &encoding)
|
||||
Importer::Importer(
|
||||
const std::filesystem::path& essfile, const std::filesystem::path& outfile, const std::string& encoding)
|
||||
: mEssFile(essfile)
|
||||
, mOutFile(outfile)
|
||||
, mEncoding(encoding)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
struct File
|
||||
@ -112,7 +113,7 @@ namespace ESSImport
|
||||
std::vector<Record> mRecords;
|
||||
};
|
||||
|
||||
void read(const std::filesystem::path &filename, File& file)
|
||||
void read(const std::filesystem::path& filename, File& file)
|
||||
{
|
||||
ESM::ESMReader esm;
|
||||
esm.open(filename);
|
||||
@ -143,14 +144,14 @@ namespace ESSImport
|
||||
void Importer::compare()
|
||||
{
|
||||
// data that always changes (and/or is already fully decoded) should be blacklisted
|
||||
std::set<std::pair<std::string, std::string> > blacklist;
|
||||
std::set<std::pair<std::string, std::string>> blacklist;
|
||||
blacklist.insert(std::make_pair("GLOB", "FLTV")); // gamehour
|
||||
blacklist.insert(std::make_pair("REFR", "DATA")); // player position
|
||||
blacklist.insert(std::make_pair("CELL", "NAM8")); // fog of war
|
||||
blacklist.insert(std::make_pair("GAME", "GMDT")); // weather data, current time always changes
|
||||
blacklist.insert(std::make_pair("CELL", "DELE")); // first 3 bytes are uninitialized
|
||||
|
||||
// this changes way too often, name suggests some renderer internal data?
|
||||
// this changes way too often, name suggests some renderer internal data?
|
||||
blacklist.insert(std::make_pair("CELL", "ND3D"));
|
||||
blacklist.insert(std::make_pair("REFR", "ND3D"));
|
||||
|
||||
@ -160,7 +161,7 @@ namespace ESSImport
|
||||
read(mOutFile, file2); // todo rename variable
|
||||
|
||||
// FIXME: use max(size1, size2)
|
||||
for (unsigned int i=0; i<file1.mRecords.size(); ++i)
|
||||
for (unsigned int i = 0; i < file1.mRecords.size(); ++i)
|
||||
{
|
||||
File::Record rec = file1.mRecords[i];
|
||||
|
||||
@ -183,14 +184,15 @@ namespace ESSImport
|
||||
}
|
||||
|
||||
// FIXME: use max(size1, size2)
|
||||
for (unsigned int j=0; j<rec.mSubrecords.size(); ++j)
|
||||
for (unsigned int j = 0; j < rec.mSubrecords.size(); ++j)
|
||||
{
|
||||
File::Subrecord sub = rec.mSubrecords[j];
|
||||
|
||||
if (j >= rec2.mSubrecords.size())
|
||||
{
|
||||
std::ios::fmtflags f(std::cout.flags());
|
||||
std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl;
|
||||
std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset
|
||||
<< std::endl;
|
||||
std::cout.flags(f);
|
||||
return;
|
||||
}
|
||||
@ -200,8 +202,9 @@ namespace ESSImport
|
||||
if (sub.mName != sub2.mName)
|
||||
{
|
||||
std::ios::fmtflags f(std::cout.flags());
|
||||
std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset
|
||||
<< " (2) 0x" << sub2.mFileOffset << std::endl;
|
||||
std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName
|
||||
<< ") at (1) 0x" << std::hex << sub.mFileOffset << " (2) 0x" << sub2.mFileOffset
|
||||
<< std::endl;
|
||||
std::cout.flags(f);
|
||||
break; // TODO: try to recover
|
||||
}
|
||||
@ -213,11 +216,11 @@ namespace ESSImport
|
||||
|
||||
std::ios::fmtflags f(std::cout.flags());
|
||||
|
||||
std::cout << "Different subrecord data for " << rec.mName << "." << sub.mName << " at (1) 0x" << std::hex << sub.mFileOffset
|
||||
<< " (2) 0x" << sub2.mFileOffset << std::endl;
|
||||
std::cout << "Different subrecord data for " << rec.mName << "." << sub.mName << " at (1) 0x"
|
||||
<< std::hex << sub.mFileOffset << " (2) 0x" << sub2.mFileOffset << std::endl;
|
||||
|
||||
std::cout << "Data 1:" << std::endl;
|
||||
for (unsigned int k=0; k<sub.mData.size(); ++k)
|
||||
for (unsigned int k = 0; k < sub.mData.size(); ++k)
|
||||
{
|
||||
bool different = false;
|
||||
if (k >= sub2.mData.size() || sub2.mData[k] != sub.mData[k])
|
||||
@ -232,7 +235,7 @@ namespace ESSImport
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "Data 2:" << std::endl;
|
||||
for (unsigned int k=0; k<sub2.mData.size(); ++k)
|
||||
for (unsigned int k = 0; k < sub2.mData.size(); ++k)
|
||||
{
|
||||
bool different = false;
|
||||
if (k >= sub.mData.size() || sub.mData[k] != sub2.mData[k])
|
||||
@ -279,12 +282,12 @@ namespace ESSImport
|
||||
converters[ESM::REC_CREA] = std::make_unique<ConvertCREA>();
|
||||
converters[ESM::REC_NPCC] = std::make_unique<ConvertNPCC>();
|
||||
converters[ESM::REC_CREC] = std::make_unique<ConvertCREC>();
|
||||
converters[recREFR ] = std::make_unique<ConvertREFR>();
|
||||
converters[recPCDT ] = std::make_unique<ConvertPCDT>();
|
||||
converters[recFMAP ] = std::make_unique<ConvertFMAP>();
|
||||
converters[recKLST ] = std::make_unique<ConvertKLST>();
|
||||
converters[recSTLN ] = std::make_unique<ConvertSTLN>();
|
||||
converters[recGAME ] = std::make_unique<ConvertGAME>();
|
||||
converters[recREFR] = std::make_unique<ConvertREFR>();
|
||||
converters[recPCDT] = std::make_unique<ConvertPCDT>();
|
||||
converters[recFMAP] = std::make_unique<ConvertFMAP>();
|
||||
converters[recKLST] = std::make_unique<ConvertKLST>();
|
||||
converters[recSTLN] = std::make_unique<ConvertSTLN>();
|
||||
converters[recGAME] = std::make_unique<ConvertGAME>();
|
||||
converters[ESM::REC_CELL] = std::make_unique<ConvertCell>();
|
||||
converters[ESM::REC_ALCH] = std::make_unique<DefaultConverter<ESM::Potion>>();
|
||||
converters[ESM::REC_CLAS] = std::make_unique<ConvertClass>();
|
||||
@ -301,7 +304,7 @@ namespace ESSImport
|
||||
converters[ESM::REC_INFO] = std::make_unique<ConvertINFO>();
|
||||
converters[ESM::REC_DIAL] = std::make_unique<ConvertDIAL>();
|
||||
converters[ESM::REC_QUES] = std::make_unique<ConvertQUES>();
|
||||
converters[recJOUR ] = std::make_unique<ConvertJOUR>();
|
||||
converters[recJOUR] = std::make_unique<ConvertJOUR>();
|
||||
converters[ESM::REC_SCPT] = std::make_unique<ConvertSCPT>();
|
||||
converters[ESM::REC_PROJ] = std::make_unique<ConvertPROJ>();
|
||||
converters[recSPLM] = std::make_unique<ConvertSPLM>();
|
||||
@ -313,7 +316,7 @@ namespace ESSImport
|
||||
|
||||
std::set<unsigned int> unknownRecords;
|
||||
|
||||
for (const auto & converter : converters)
|
||||
for (const auto& converter : converters)
|
||||
{
|
||||
converter.second->setContext(context);
|
||||
}
|
||||
@ -333,7 +336,8 @@ namespace ESSImport
|
||||
if (unknownRecords.insert(n.toInt()).second)
|
||||
{
|
||||
std::ios::fmtflags f(std::cerr.flags());
|
||||
std::cerr << "Error: unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl;
|
||||
std::cerr << "Error: unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset()
|
||||
<< ")" << std::endl;
|
||||
std::cerr.flags(f);
|
||||
}
|
||||
|
||||
@ -343,7 +347,7 @@ namespace ESSImport
|
||||
|
||||
ESM::ESMWriter writer;
|
||||
|
||||
writer.setFormat (ESM::SavedGame::sCurrentFormat);
|
||||
writer.setFormat(ESM::SavedGame::sCurrentFormat);
|
||||
|
||||
std::ofstream stream(mOutFile, std::ios::out | std::ios::binary);
|
||||
// all unused
|
||||
@ -351,15 +355,15 @@ namespace ESSImport
|
||||
writer.setType(0);
|
||||
writer.setAuthor("");
|
||||
writer.setDescription("");
|
||||
writer.setRecordCount (0);
|
||||
writer.setRecordCount(0);
|
||||
|
||||
for (const auto & master : header.mMaster)
|
||||
for (const auto& master : header.mMaster)
|
||||
writer.addMaster(master.name, 0); // not using the size information anyway -> use value of 0
|
||||
|
||||
writer.save (stream);
|
||||
writer.save(stream);
|
||||
|
||||
ESM::SavedGame profile;
|
||||
for (const auto & master : header.mMaster)
|
||||
for (const auto& master : header.mMaster)
|
||||
{
|
||||
profile.mContentFiles.push_back(master.name);
|
||||
}
|
||||
@ -379,14 +383,13 @@ namespace ESSImport
|
||||
|
||||
writeScreenshot(header, profile);
|
||||
|
||||
writer.startRecord (ESM::REC_SAVE);
|
||||
profile.save (writer);
|
||||
writer.endRecord (ESM::REC_SAVE);
|
||||
writer.startRecord(ESM::REC_SAVE);
|
||||
profile.save(writer);
|
||||
writer.endRecord(ESM::REC_SAVE);
|
||||
|
||||
// Writing order should be Dynamic Store -> Cells -> Player,
|
||||
// so that references to dynamic records can be recognized when loading
|
||||
for (auto it = converters.begin();
|
||||
it != converters.end(); ++it)
|
||||
for (auto it = converters.begin(); it != converters.end(); ++it)
|
||||
{
|
||||
if (it->second->getStage() != 0)
|
||||
continue;
|
||||
@ -398,8 +401,7 @@ namespace ESSImport
|
||||
context.mPlayerBase.save(writer);
|
||||
writer.endRecord(ESM::REC_NPC_);
|
||||
|
||||
for (auto it = converters.begin();
|
||||
it != converters.end(); ++it)
|
||||
for (auto it = converters.begin(); it != converters.end(); ++it)
|
||||
{
|
||||
if (it->second->getStage() != 1)
|
||||
continue;
|
||||
@ -410,8 +412,10 @@ namespace ESSImport
|
||||
if (context.mPlayer.mCellId.mPaged)
|
||||
{
|
||||
// exterior cell -> determine cell coordinates based on position
|
||||
int cellX = static_cast<int>(std::floor(context.mPlayer.mObject.mPosition.pos[0] / Constants::CellSizeInUnits));
|
||||
int cellY = static_cast<int>(std::floor(context.mPlayer.mObject.mPosition.pos[1] / Constants::CellSizeInUnits));
|
||||
int cellX
|
||||
= static_cast<int>(std::floor(context.mPlayer.mObject.mPosition.pos[0] / Constants::CellSizeInUnits));
|
||||
int cellY
|
||||
= static_cast<int>(std::floor(context.mPlayer.mObject.mPosition.pos[1] / Constants::CellSizeInUnits));
|
||||
context.mPlayer.mCellId.mIndex.mX = cellX;
|
||||
context.mPlayer.mCellId.mIndex.mY = cellY;
|
||||
}
|
||||
@ -423,15 +427,14 @@ namespace ESSImport
|
||||
writer.endRecord(ESM::REC_ACTC);
|
||||
|
||||
// Stage 2 requires cell references to be written / actors IDs assigned
|
||||
for (auto it = converters.begin();
|
||||
it != converters.end(); ++it)
|
||||
for (auto it = converters.begin(); it != converters.end(); ++it)
|
||||
{
|
||||
if (it->second->getStage() != 2)
|
||||
continue;
|
||||
it->second->write(writer);
|
||||
}
|
||||
|
||||
writer.startRecord (ESM::REC_DIAS);
|
||||
writer.startRecord(ESM::REC_DIAS);
|
||||
context.mDialogueState.save(writer);
|
||||
writer.endRecord(ESM::REC_DIAS);
|
||||
|
||||
@ -440,5 +443,4 @@ namespace ESSImport
|
||||
writer.endRecord(ESM::REC_INPU);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,8 @@ namespace ESSImport
|
||||
class Importer
|
||||
{
|
||||
public:
|
||||
Importer(const std::filesystem::path &essfile, const std::filesystem::path &outfile, const std::string& encoding);
|
||||
Importer(
|
||||
const std::filesystem::path& essfile, const std::filesystem::path& outfile, const std::string& encoding);
|
||||
|
||||
void run();
|
||||
|
||||
|
@ -3,17 +3,16 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <components/esm3/loadnpc.hpp>
|
||||
#include <components/esm3/player.hpp>
|
||||
#include <components/esm3/controlsstate.hpp>
|
||||
#include <components/esm3/dialoguestate.hpp>
|
||||
#include <components/esm3/globalmap.hpp>
|
||||
#include <components/esm3/loadcrea.hpp>
|
||||
#include <components/esm3/loadnpc.hpp>
|
||||
#include <components/esm3/controlsstate.hpp>
|
||||
#include <components/esm3/player.hpp>
|
||||
|
||||
#include "importnpcc.hpp"
|
||||
#include "importcrec.hpp"
|
||||
#include "importcntc.hpp"
|
||||
#include "importcrec.hpp"
|
||||
#include "importnpcc.hpp"
|
||||
#include "importsplm.h"
|
||||
|
||||
namespace ESSImport
|
||||
@ -33,7 +32,7 @@ namespace ESSImport
|
||||
ESM::ControlsState mControlsState;
|
||||
|
||||
// cells which should show an explored overlay on the global map
|
||||
std::set<std::pair<int, int> > mExploredCells;
|
||||
std::set<std::pair<int, int>> mExploredCells;
|
||||
|
||||
ESM::GlobalMap mGlobalMapState;
|
||||
|
||||
@ -64,10 +63,8 @@ namespace ESSImport
|
||||
playerCellId.mPaged = true;
|
||||
playerCellId.mIndex.mX = playerCellId.mIndex.mY = 0;
|
||||
mPlayer.mCellId = playerCellId;
|
||||
mPlayer.mLastKnownExteriorPosition[0]
|
||||
= mPlayer.mLastKnownExteriorPosition[1]
|
||||
= mPlayer.mLastKnownExteriorPosition[2]
|
||||
= 0.0f;
|
||||
mPlayer.mLastKnownExteriorPosition[0] = mPlayer.mLastKnownExteriorPosition[1]
|
||||
= mPlayer.mLastKnownExteriorPosition[2] = 0.0f;
|
||||
mPlayer.mHasMark = 0;
|
||||
mPlayer.mCurrentCrimeId = -1; // TODO
|
||||
mPlayer.mPaidCrimeId = -1;
|
||||
@ -84,10 +81,7 @@ namespace ESSImport
|
||||
mPlayerBase.blank();
|
||||
}
|
||||
|
||||
int generateActorId()
|
||||
{
|
||||
return mNextActorId++;
|
||||
}
|
||||
int generateActorId() { return mNextActorId++; }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -5,25 +5,25 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void GAME::load(ESM::ESMReader &esm)
|
||||
{
|
||||
esm.getSubNameIs("GMDT");
|
||||
esm.getSubHeader();
|
||||
if (esm.getSubSize() == 92)
|
||||
void GAME::load(ESM::ESMReader& esm)
|
||||
{
|
||||
esm.getExact(&mGMDT, 92);
|
||||
mGMDT.mSecundaPhase = 0;
|
||||
}
|
||||
else if (esm.getSubSize() == 96)
|
||||
{
|
||||
esm.getT(mGMDT);
|
||||
}
|
||||
else
|
||||
esm.fail("unexpected subrecord size for GAME.GMDT");
|
||||
esm.getSubNameIs("GMDT");
|
||||
esm.getSubHeader();
|
||||
if (esm.getSubSize() == 92)
|
||||
{
|
||||
esm.getExact(&mGMDT, 92);
|
||||
mGMDT.mSecundaPhase = 0;
|
||||
}
|
||||
else if (esm.getSubSize() == 96)
|
||||
{
|
||||
esm.getT(mGMDT);
|
||||
}
|
||||
else
|
||||
esm.fail("unexpected subrecord size for GAME.GMDT");
|
||||
|
||||
mGMDT.mWeatherTransition &= (0x000000ff);
|
||||
mGMDT.mSecundaPhase &= (0x000000ff);
|
||||
mGMDT.mMasserPhase &= (0x000000ff);
|
||||
}
|
||||
mGMDT.mWeatherTransition &= (0x000000ff);
|
||||
mGMDT.mSecundaPhase &= (0x000000ff);
|
||||
mGMDT.mMasserPhase &= (0x000000ff);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,13 +14,13 @@ namespace ESSImport
|
||||
{
|
||||
struct GMDT
|
||||
{
|
||||
char mCellName[64] {};
|
||||
int mFogColour {0};
|
||||
float mFogDensity {0.f};
|
||||
int mCurrentWeather {0}, mNextWeather {0};
|
||||
int mWeatherTransition {0}; // 0-100 transition between weathers, top 3 bytes may be garbage
|
||||
float mTimeOfNextTransition {0.f}; // weather changes when gamehour == timeOfNextTransition
|
||||
int mMasserPhase {0}, mSecundaPhase {0}; // top 3 bytes may be garbage
|
||||
char mCellName[64]{};
|
||||
int mFogColour{ 0 };
|
||||
float mFogDensity{ 0.f };
|
||||
int mCurrentWeather{ 0 }, mNextWeather{ 0 };
|
||||
int mWeatherTransition{ 0 }; // 0-100 transition between weathers, top 3 bytes may be garbage
|
||||
float mTimeOfNextTransition{ 0.f }; // weather changes when gamehour == timeOfNextTransition
|
||||
int mMasserPhase{ 0 }, mSecundaPhase{ 0 }; // top 3 bytes may be garbage
|
||||
};
|
||||
|
||||
GMDT mGMDT;
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void INFO::load(ESM::ESMReader &esm)
|
||||
void INFO::load(ESM::ESMReader& esm)
|
||||
{
|
||||
mInfo = esm.getHNString("INAM");
|
||||
mActorRefId = esm.getHNString("ACDT");
|
||||
|
@ -7,7 +7,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void Inventory::load(ESM::ESMReader &esm)
|
||||
void Inventory::load(ESM::ESMReader& esm)
|
||||
{
|
||||
while (esm.isNextSub("NPCO"))
|
||||
{
|
||||
@ -23,7 +23,7 @@ namespace ESSImport
|
||||
|
||||
unsigned int itemCount = std::abs(item.mCount);
|
||||
bool separateStacks = false;
|
||||
for (unsigned int i=0;i<itemCount;++i)
|
||||
for (unsigned int i = 0; i < itemCount; ++i)
|
||||
{
|
||||
bool newStack = esm.isNextSub("XIDX");
|
||||
if (newStack)
|
||||
@ -40,7 +40,7 @@ namespace ESSImport
|
||||
bool isDeleted = false;
|
||||
item.ESM::CellRef::loadData(esm, isDeleted);
|
||||
|
||||
int charge=-1;
|
||||
int charge = -1;
|
||||
esm.getHNOT(charge, "XHLT");
|
||||
item.mChargeInt = charge;
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
#ifndef OPENMW_ESSIMPORT_IMPORTINVENTORY_H
|
||||
#define OPENMW_ESSIMPORT_IMPORTINVENTORY_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <components/esm3/cellref.hpp>
|
||||
#include <components/esm/esmcommon.hpp>
|
||||
#include <components/esm3/cellref.hpp>
|
||||
|
||||
#include "importscri.hpp"
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void JOUR::load(ESM::ESMReader &esm)
|
||||
void JOUR::load(ESM::ESMReader& esm)
|
||||
{
|
||||
mText = esm.getHNString("NAME");
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void KLST::load(ESM::ESMReader &esm)
|
||||
void KLST::load(ESM::ESMReader& esm)
|
||||
{
|
||||
while (esm.isNextSub("KNAM"))
|
||||
{
|
||||
|
@ -1,8 +1,8 @@
|
||||
#ifndef OPENMW_ESSIMPORT_KLST_H
|
||||
#define OPENMW_ESSIMPORT_KLST_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
@ -5,12 +5,12 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void NPCC::load(ESM::ESMReader &esm)
|
||||
void NPCC::load(ESM::ESMReader& esm)
|
||||
{
|
||||
esm.getHNT(mNPDT, "NPDT");
|
||||
|
||||
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|
||||
|| esm.isNextSub("AI_A"))
|
||||
|| esm.isNextSub("AI_A"))
|
||||
mAiPackages.add(esm);
|
||||
|
||||
mInventory.load(esm);
|
||||
|
@ -29,7 +29,7 @@ namespace ESSImport
|
||||
Inventory mInventory;
|
||||
ESM::AIPackageList mAiPackages;
|
||||
|
||||
void load(ESM::ESMReader &esm);
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void PCDT::load(ESM::ESMReader &esm)
|
||||
void PCDT::load(ESM::ESMReader& esm)
|
||||
{
|
||||
while (esm.isNextSub("DNAM"))
|
||||
{
|
||||
|
@ -1,12 +1,12 @@
|
||||
#ifndef OPENMW_ESSIMPORT_PLAYER_H
|
||||
#define OPENMW_ESSIMPORT_PLAYER_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm3/cellref.hpp>
|
||||
#include <components/esm/esmcommon.hpp>
|
||||
#include <components/esm3/cellref.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
@ -16,102 +16,102 @@ namespace ESM
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
/// Other player data
|
||||
struct PCDT
|
||||
{
|
||||
int mBounty;
|
||||
std::string mBirthsign;
|
||||
|
||||
std::vector<std::string> mKnownDialogueTopics;
|
||||
|
||||
enum PlayerFlags
|
||||
/// Other player data
|
||||
struct PCDT
|
||||
{
|
||||
PlayerFlags_ViewSwitchDisabled = 0x1,
|
||||
PlayerFlags_ControlsDisabled = 0x4,
|
||||
PlayerFlags_Sleeping = 0x10,
|
||||
PlayerFlags_Waiting = 0x40,
|
||||
PlayerFlags_WeaponDrawn = 0x80,
|
||||
PlayerFlags_SpellDrawn = 0x100,
|
||||
PlayerFlags_InJail = 0x200,
|
||||
PlayerFlags_JumpingDisabled = 0x1000,
|
||||
PlayerFlags_LookingDisabled = 0x2000,
|
||||
PlayerFlags_VanityModeDisabled = 0x4000,
|
||||
PlayerFlags_WeaponDrawingDisabled = 0x8000,
|
||||
PlayerFlags_SpellDrawingDisabled = 0x10000,
|
||||
PlayerFlags_ThirdPerson = 0x20000,
|
||||
PlayerFlags_TeleportingDisabled = 0x40000,
|
||||
PlayerFlags_LevitationDisabled = 0x80000
|
||||
};
|
||||
int mBounty;
|
||||
std::string mBirthsign;
|
||||
|
||||
std::vector<std::string> mKnownDialogueTopics;
|
||||
|
||||
enum PlayerFlags
|
||||
{
|
||||
PlayerFlags_ViewSwitchDisabled = 0x1,
|
||||
PlayerFlags_ControlsDisabled = 0x4,
|
||||
PlayerFlags_Sleeping = 0x10,
|
||||
PlayerFlags_Waiting = 0x40,
|
||||
PlayerFlags_WeaponDrawn = 0x80,
|
||||
PlayerFlags_SpellDrawn = 0x100,
|
||||
PlayerFlags_InJail = 0x200,
|
||||
PlayerFlags_JumpingDisabled = 0x1000,
|
||||
PlayerFlags_LookingDisabled = 0x2000,
|
||||
PlayerFlags_VanityModeDisabled = 0x4000,
|
||||
PlayerFlags_WeaponDrawingDisabled = 0x8000,
|
||||
PlayerFlags_SpellDrawingDisabled = 0x10000,
|
||||
PlayerFlags_ThirdPerson = 0x20000,
|
||||
PlayerFlags_TeleportingDisabled = 0x40000,
|
||||
PlayerFlags_LevitationDisabled = 0x80000
|
||||
};
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct FNAM
|
||||
{
|
||||
unsigned char mRank;
|
||||
unsigned char mUnknown1[3];
|
||||
int mReputation;
|
||||
unsigned char mFlags; // 0x1: unknown, 0x2: expelled
|
||||
unsigned char mUnknown2[3];
|
||||
ESM::NAME32 mFactionName;
|
||||
};
|
||||
|
||||
struct PNAM
|
||||
{
|
||||
struct MarkLocation
|
||||
struct FNAM
|
||||
{
|
||||
float mX, mY, mZ; // worldspace position
|
||||
float mRotZ; // Z angle in radians
|
||||
int mCellX, mCellY; // grid coordinates; for interior cells this is always (0, 0)
|
||||
unsigned char mRank;
|
||||
unsigned char mUnknown1[3];
|
||||
int mReputation;
|
||||
unsigned char mFlags; // 0x1: unknown, 0x2: expelled
|
||||
unsigned char mUnknown2[3];
|
||||
ESM::NAME32 mFactionName;
|
||||
};
|
||||
|
||||
struct Rotation
|
||||
struct PNAM
|
||||
{
|
||||
float mData[3][3];
|
||||
struct MarkLocation
|
||||
{
|
||||
float mX, mY, mZ; // worldspace position
|
||||
float mRotZ; // Z angle in radians
|
||||
int mCellX, mCellY; // grid coordinates; for interior cells this is always (0, 0)
|
||||
};
|
||||
|
||||
struct Rotation
|
||||
{
|
||||
float mData[3][3];
|
||||
};
|
||||
|
||||
int mPlayerFlags; // controls, camera and draw state
|
||||
unsigned int mLevelProgress;
|
||||
float mSkillProgress[27]; // skill progress, non-uniform scaled
|
||||
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute
|
||||
int mTelekinesisRangeBonus; // in units; seems redundant
|
||||
float mVisionBonus; // range: <0.0, 1.0>; affected by light spells and Get/Mod/SetPCVisionBonus
|
||||
int mDetectKeyMagnitude; // seems redundant
|
||||
int mDetectEnchantmentMagnitude; // seems redundant
|
||||
int mDetectAnimalMagnitude; // seems redundant
|
||||
MarkLocation mMarkLocation;
|
||||
unsigned char mUnknown3[4];
|
||||
Rotation mVerticalRotation;
|
||||
unsigned char mSpecIncreases[3]; // number of skill increases for each specialization
|
||||
unsigned char mUnknown4;
|
||||
};
|
||||
|
||||
int mPlayerFlags; // controls, camera and draw state
|
||||
unsigned int mLevelProgress;
|
||||
float mSkillProgress[27]; // skill progress, non-uniform scaled
|
||||
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute
|
||||
int mTelekinesisRangeBonus; // in units; seems redundant
|
||||
float mVisionBonus; // range: <0.0, 1.0>; affected by light spells and Get/Mod/SetPCVisionBonus
|
||||
int mDetectKeyMagnitude; // seems redundant
|
||||
int mDetectEnchantmentMagnitude; // seems redundant
|
||||
int mDetectAnimalMagnitude; // seems redundant
|
||||
MarkLocation mMarkLocation;
|
||||
unsigned char mUnknown3[4];
|
||||
Rotation mVerticalRotation;
|
||||
unsigned char mSpecIncreases[3]; // number of skill increases for each specialization
|
||||
unsigned char mUnknown4;
|
||||
};
|
||||
struct ENAM
|
||||
{
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
};
|
||||
|
||||
struct ENAM
|
||||
{
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
};
|
||||
|
||||
struct AADT // 44 bytes
|
||||
{
|
||||
int animGroupIndex; // See convertANIS() for the mapping.
|
||||
unsigned char mUnknown5[40];
|
||||
};
|
||||
struct AADT // 44 bytes
|
||||
{
|
||||
int animGroupIndex; // See convertANIS() for the mapping.
|
||||
unsigned char mUnknown5[40];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::vector<FNAM> mFactions;
|
||||
PNAM mPNAM;
|
||||
std::vector<FNAM> mFactions;
|
||||
PNAM mPNAM;
|
||||
|
||||
bool mHasMark;
|
||||
std::string mMNAM; // mark cell name; can also be sDefaultCellname or region name
|
||||
bool mHasMark;
|
||||
std::string mMNAM; // mark cell name; can also be sDefaultCellname or region name
|
||||
|
||||
bool mHasENAM;
|
||||
ENAM mENAM; // last exterior cell
|
||||
bool mHasENAM;
|
||||
ENAM mENAM; // last exterior cell
|
||||
|
||||
bool mHasAADT;
|
||||
AADT mAADT;
|
||||
bool mHasAADT;
|
||||
AADT mAADT;
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
@ -5,14 +5,14 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void ESSImport::PROJ::load(ESM::ESMReader& esm)
|
||||
{
|
||||
while (esm.isNextSub("PNAM"))
|
||||
void ESSImport::PROJ::load(ESM::ESMReader& esm)
|
||||
{
|
||||
PNAM pnam;
|
||||
esm.getHT(pnam);
|
||||
mProjectiles.push_back(pnam);
|
||||
while (esm.isNextSub("PNAM"))
|
||||
{
|
||||
PNAM pnam;
|
||||
esm.getHT(pnam);
|
||||
mProjectiles.push_back(pnam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef OPENMW_ESSIMPORT_IMPORTPROJ_H
|
||||
#define OPENMW_ESSIMPORT_IMPORTPROJ_H
|
||||
|
||||
#include <vector>
|
||||
#include <components/esm/esmcommon.hpp>
|
||||
#include <components/esm/util.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
@ -13,34 +13,34 @@ namespace ESM
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
struct PROJ
|
||||
{
|
||||
struct PROJ
|
||||
{
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct PNAM // 184 bytes
|
||||
{
|
||||
float mAttackStrength;
|
||||
float mSpeed;
|
||||
unsigned char mUnknown[4*2];
|
||||
float mFlightTime;
|
||||
int mSplmIndex; // reference to a SPLM record (0 for ballistic projectiles)
|
||||
unsigned char mUnknown2[4];
|
||||
ESM::Vector3 mVelocity;
|
||||
ESM::Vector3 mPosition;
|
||||
unsigned char mUnknown3[4*9];
|
||||
ESM::NAME32 mActorId; // indexed refID (with the exception of "PlayerSaveGame")
|
||||
ESM::NAME32 mArrowId;
|
||||
ESM::NAME32 mBowId;
|
||||
struct PNAM // 184 bytes
|
||||
{
|
||||
float mAttackStrength;
|
||||
float mSpeed;
|
||||
unsigned char mUnknown[4 * 2];
|
||||
float mFlightTime;
|
||||
int mSplmIndex; // reference to a SPLM record (0 for ballistic projectiles)
|
||||
unsigned char mUnknown2[4];
|
||||
ESM::Vector3 mVelocity;
|
||||
ESM::Vector3 mPosition;
|
||||
unsigned char mUnknown3[4 * 9];
|
||||
ESM::NAME32 mActorId; // indexed refID (with the exception of "PlayerSaveGame")
|
||||
ESM::NAME32 mArrowId;
|
||||
ESM::NAME32 mBowId;
|
||||
|
||||
bool isMagic() const { return mSplmIndex != 0; }
|
||||
};
|
||||
bool isMagic() const { return mSplmIndex != 0; }
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::vector<PNAM> mProjectiles;
|
||||
std::vector<PNAM> mProjectiles;
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void QUES::load(ESM::ESMReader &esm)
|
||||
void QUES::load(ESM::ESMReader& esm)
|
||||
{
|
||||
while (esm.isNextSub("DATA"))
|
||||
mInfo.push_back(esm.getHString());
|
||||
|
@ -2,11 +2,10 @@
|
||||
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void SCPT::load(ESM::ESMReader &esm)
|
||||
void SCPT::load(ESM::ESMReader& esm)
|
||||
{
|
||||
esm.getHNT(mSCHD, "SCHD");
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
#include "importscri.hpp"
|
||||
|
||||
#include <components/esm3/loadscpt.hpp>
|
||||
#include <components/esm/esmcommon.hpp>
|
||||
#include <components/esm3/loadscpt.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
@ -16,8 +16,8 @@ namespace ESSImport
|
||||
|
||||
struct SCHD
|
||||
{
|
||||
ESM::NAME32 mName;
|
||||
ESM::Script::SCHDstruct mData;
|
||||
ESM::NAME32 mName;
|
||||
ESM::Script::SCHDstruct mData;
|
||||
};
|
||||
|
||||
// A running global script
|
||||
|
@ -2,11 +2,10 @@
|
||||
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void SCRI::load(ESM::ESMReader &esm)
|
||||
void SCRI::load(ESM::ESMReader& esm)
|
||||
{
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
|
||||
@ -22,7 +21,7 @@ namespace ESSImport
|
||||
if (esm.isNextSub("SLSD"))
|
||||
{
|
||||
esm.getSubHeader();
|
||||
for (int i=0; i<numShorts; ++i)
|
||||
for (int i = 0; i < numShorts; ++i)
|
||||
{
|
||||
short val;
|
||||
esm.getT(val);
|
||||
@ -34,7 +33,7 @@ namespace ESSImport
|
||||
if (esm.isNextSub("SLLD"))
|
||||
{
|
||||
esm.getSubHeader();
|
||||
for (int i=0; i<numLongs; ++i)
|
||||
for (int i = 0; i < numLongs; ++i)
|
||||
{
|
||||
int val;
|
||||
esm.getT(val);
|
||||
@ -44,7 +43,7 @@ namespace ESSImport
|
||||
if (esm.isNextSub("SLFD"))
|
||||
{
|
||||
esm.getSubHeader();
|
||||
for (int i=0; i<numFloats; ++i)
|
||||
for (int i = 0; i < numFloats; ++i)
|
||||
{
|
||||
float val;
|
||||
esm.getT(val);
|
||||
|
@ -5,39 +5,39 @@
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void SPLM::load(ESM::ESMReader& esm)
|
||||
{
|
||||
while (esm.isNextSub("NAME"))
|
||||
void SPLM::load(ESM::ESMReader& esm)
|
||||
{
|
||||
ActiveSpell spell;
|
||||
esm.getHT(spell.mIndex);
|
||||
esm.getHNT(spell.mSPDT, "SPDT");
|
||||
spell.mTarget = esm.getHNOString("TNAM");
|
||||
|
||||
while (esm.isNextSub("NPDT"))
|
||||
while (esm.isNextSub("NAME"))
|
||||
{
|
||||
ActiveEffect effect;
|
||||
esm.getHT(effect.mNPDT);
|
||||
ActiveSpell spell;
|
||||
esm.getHT(spell.mIndex);
|
||||
esm.getHNT(spell.mSPDT, "SPDT");
|
||||
spell.mTarget = esm.getHNOString("TNAM");
|
||||
|
||||
// Effect-specific subrecords can follow:
|
||||
// - INAM for disintegration and bound effects
|
||||
// - CNAM for summoning and command effects
|
||||
// - VNAM for vampirism
|
||||
// NOTE: There can be multiple INAMs per effect.
|
||||
// TODO: Needs more research.
|
||||
while (esm.isNextSub("NPDT"))
|
||||
{
|
||||
ActiveEffect effect;
|
||||
esm.getHT(effect.mNPDT);
|
||||
|
||||
esm.skipHSubUntil("NAM0"); // sentinel
|
||||
esm.getSubName();
|
||||
esm.skipHSub();
|
||||
// Effect-specific subrecords can follow:
|
||||
// - INAM for disintegration and bound effects
|
||||
// - CNAM for summoning and command effects
|
||||
// - VNAM for vampirism
|
||||
// NOTE: There can be multiple INAMs per effect.
|
||||
// TODO: Needs more research.
|
||||
|
||||
spell.mActiveEffects.push_back(effect);
|
||||
esm.skipHSubUntil("NAM0"); // sentinel
|
||||
esm.getSubName();
|
||||
esm.skipHSub();
|
||||
|
||||
spell.mActiveEffects.push_back(effect);
|
||||
}
|
||||
|
||||
unsigned char xnam; // sentinel
|
||||
esm.getHNT(xnam, "XNAM");
|
||||
|
||||
mActiveSpells.push_back(spell);
|
||||
}
|
||||
|
||||
unsigned char xnam; // sentinel
|
||||
esm.getHNT(xnam, "XNAM");
|
||||
|
||||
mActiveSpells.push_back(spell);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef OPENMW_ESSIMPORT_IMPORTSPLM_H
|
||||
#define OPENMW_ESSIMPORT_IMPORTSPLM_H
|
||||
|
||||
#include <vector>
|
||||
#include <components/esm/esmcommon.hpp>
|
||||
#include <components/esm/util.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
@ -13,69 +13,68 @@ namespace ESM
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
struct SPLM
|
||||
{
|
||||
struct SPLM
|
||||
{
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct SPDT // 160 bytes
|
||||
{
|
||||
int mType; // 1 = spell, 2 = enchantment, 3 = potion
|
||||
ESM::NAME32 mId; // base ID of a spell/enchantment/potion
|
||||
unsigned char mUnknown[4*4];
|
||||
ESM::NAME32 mCasterId;
|
||||
ESM::NAME32 mSourceId; // empty for spells
|
||||
unsigned char mUnknown2[4*11];
|
||||
};
|
||||
struct SPDT // 160 bytes
|
||||
{
|
||||
int mType; // 1 = spell, 2 = enchantment, 3 = potion
|
||||
ESM::NAME32 mId; // base ID of a spell/enchantment/potion
|
||||
unsigned char mUnknown[4 * 4];
|
||||
ESM::NAME32 mCasterId;
|
||||
ESM::NAME32 mSourceId; // empty for spells
|
||||
unsigned char mUnknown2[4 * 11];
|
||||
};
|
||||
|
||||
struct NPDT // 56 bytes
|
||||
{
|
||||
ESM::NAME32 mAffectedActorId;
|
||||
unsigned char mUnknown[4*2];
|
||||
int mMagnitude;
|
||||
float mSecondsActive;
|
||||
unsigned char mUnknown2[4*2];
|
||||
};
|
||||
struct NPDT // 56 bytes
|
||||
{
|
||||
ESM::NAME32 mAffectedActorId;
|
||||
unsigned char mUnknown[4 * 2];
|
||||
int mMagnitude;
|
||||
float mSecondsActive;
|
||||
unsigned char mUnknown2[4 * 2];
|
||||
};
|
||||
|
||||
struct INAM // 40 bytes
|
||||
{
|
||||
int mUnknown;
|
||||
unsigned char mUnknown2;
|
||||
ESM::FixedString<35> mItemId; // disintegrated item / bound item / item to re-equip after expiration
|
||||
};
|
||||
struct INAM // 40 bytes
|
||||
{
|
||||
int mUnknown;
|
||||
unsigned char mUnknown2;
|
||||
ESM::FixedString<35> mItemId; // disintegrated item / bound item / item to re-equip after expiration
|
||||
};
|
||||
|
||||
struct CNAM // 36 bytes
|
||||
{
|
||||
int mUnknown; // seems to always be 0
|
||||
ESM::NAME32 mSummonedOrCommandedActor[32];
|
||||
};
|
||||
|
||||
struct VNAM // 4 bytes
|
||||
{
|
||||
int mUnknown;
|
||||
};
|
||||
struct CNAM // 36 bytes
|
||||
{
|
||||
int mUnknown; // seems to always be 0
|
||||
ESM::NAME32 mSummonedOrCommandedActor[32];
|
||||
};
|
||||
|
||||
struct VNAM // 4 bytes
|
||||
{
|
||||
int mUnknown;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
struct ActiveEffect
|
||||
{
|
||||
NPDT mNPDT;
|
||||
struct ActiveEffect
|
||||
{
|
||||
NPDT mNPDT;
|
||||
};
|
||||
|
||||
struct ActiveSpell
|
||||
{
|
||||
int mIndex;
|
||||
SPDT mSPDT;
|
||||
std::string mTarget;
|
||||
std::vector<ActiveEffect> mActiveEffects;
|
||||
};
|
||||
|
||||
std::vector<ActiveSpell> mActiveSpells;
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
||||
struct ActiveSpell
|
||||
{
|
||||
int mIndex;
|
||||
SPDT mSPDT;
|
||||
std::string mTarget;
|
||||
std::vector<ActiveEffect> mActiveEffects;
|
||||
};
|
||||
|
||||
std::vector<ActiveSpell> mActiveSpells;
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
try
|
||||
@ -22,19 +21,18 @@ Allowed options)");
|
||||
addOption("mwsave,m", bpo::value<Files::MaybeQuotedPath>(), "morrowind .ess save file");
|
||||
addOption("output,o", bpo::value<Files::MaybeQuotedPath>(), "output file (.omwsave)");
|
||||
addOption("compare,c", "compare two .ess files");
|
||||
addOption("encoding", boost::program_options::value<std::string>()->default_value("win1252"), "encoding of the save file");
|
||||
addOption("encoding", boost::program_options::value<std::string>()->default_value("win1252"),
|
||||
"encoding of the save file");
|
||||
p_desc.add("mwsave", 1).add("output", 1);
|
||||
Files::ConfigurationManager::addCommonOptions(desc);
|
||||
|
||||
bpo::variables_map variables;
|
||||
|
||||
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
|
||||
.options(desc)
|
||||
.positional(p_desc)
|
||||
.run();
|
||||
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv).options(desc).positional(p_desc).run();
|
||||
bpo::store(parsed, variables);
|
||||
|
||||
if(variables.count("help") || !variables.count("mwsave") || !variables.count("output")) {
|
||||
if (variables.count("help") || !variables.count("mwsave") || !variables.count("output"))
|
||||
{
|
||||
std::cout << desc;
|
||||
return 0;
|
||||
}
|
||||
@ -54,12 +52,13 @@ Allowed options)");
|
||||
importer.compare();
|
||||
else
|
||||
{
|
||||
static constexpr std::u8string_view ext{u8".omwsave"};
|
||||
static constexpr std::u8string_view ext{ u8".omwsave" };
|
||||
const auto length = outputFile.native().size();
|
||||
if (std::filesystem::exists(outputFile)
|
||||
&& (length < ext.size() || outputFile.u8string().substr(length-ext.size()) != ext))
|
||||
&& (length < ext.size() || outputFile.u8string().substr(length - ext.size()) != ext))
|
||||
{
|
||||
throw std::runtime_error("Output file already exists and does not end in .omwsave. Did you mean to use --compare?");
|
||||
throw std::runtime_error(
|
||||
"Output file already exists and does not end in .omwsave. Did you mean to use --compare?");
|
||||
}
|
||||
importer.run();
|
||||
}
|
||||
|
@ -1,32 +1,32 @@
|
||||
#include "advancedpage.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QCompleter>
|
||||
#include <QFileDialog>
|
||||
#include <QString>
|
||||
|
||||
#include <components/config/gamesettings.hpp>
|
||||
#include <components/contentselector/view/contentselector.hpp>
|
||||
#include <components/contentselector/model/esmfile.hpp>
|
||||
#include <components/contentselector/view/contentselector.hpp>
|
||||
#include <components/detournavigator/collisionshapetype.hpp>
|
||||
|
||||
#include "utils/openalutil.hpp"
|
||||
|
||||
Launcher::AdvancedPage::AdvancedPage(Config::GameSettings &gameSettings, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, mGameSettings(gameSettings)
|
||||
Launcher::AdvancedPage::AdvancedPage(Config::GameSettings& gameSettings, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, mGameSettings(gameSettings)
|
||||
{
|
||||
setObjectName ("AdvancedPage");
|
||||
setObjectName("AdvancedPage");
|
||||
setupUi(this);
|
||||
|
||||
for(const std::string& name : Launcher::enumerateOpenALDevices())
|
||||
for (const std::string& name : Launcher::enumerateOpenALDevices())
|
||||
{
|
||||
audioDeviceSelectorComboBox->addItem(QString::fromStdString(name), QString::fromStdString(name));
|
||||
}
|
||||
for(const std::string& name : Launcher::enumerateOpenALDevicesHrtf())
|
||||
for (const std::string& name : Launcher::enumerateOpenALDevicesHrtf())
|
||||
{
|
||||
hrtfProfileSelectorComboBox->addItem(QString::fromStdString(name), QString::fromStdString(name));
|
||||
}
|
||||
@ -37,14 +37,16 @@ Launcher::AdvancedPage::AdvancedPage(Config::GameSettings &gameSettings, QWidget
|
||||
startDefaultCharacterAtField->setCompleter(&mCellNameCompleter);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::loadCellsForAutocomplete(QStringList cellNames) {
|
||||
void Launcher::AdvancedPage::loadCellsForAutocomplete(QStringList cellNames)
|
||||
{
|
||||
// Update the list of suggestions for the "Start default character at" field
|
||||
mCellNameCompleterModel.setStringList(cellNames);
|
||||
mCellNameCompleter.setCompletionMode(QCompleter::PopupCompletion);
|
||||
mCellNameCompleter.setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::on_skipMenuCheckBox_stateChanged(int state) {
|
||||
void Launcher::AdvancedPage::on_skipMenuCheckBox_stateChanged(int state)
|
||||
{
|
||||
startDefaultCharacterAtLabel->setEnabled(state == Qt::Checked);
|
||||
startDefaultCharacterAtField->setEnabled(state == Qt::Checked);
|
||||
}
|
||||
@ -52,10 +54,7 @@ void Launcher::AdvancedPage::on_skipMenuCheckBox_stateChanged(int state) {
|
||||
void Launcher::AdvancedPage::on_runScriptAfterStartupBrowseButton_clicked()
|
||||
{
|
||||
QString scriptFile = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
QObject::tr("Select script file"),
|
||||
QDir::currentPath(),
|
||||
QString(tr("Text file (*.txt)")));
|
||||
this, QObject::tr("Select script file"), QDir::currentPath(), QString(tr("Text file (*.txt)")));
|
||||
|
||||
if (scriptFile.isEmpty())
|
||||
return;
|
||||
@ -95,7 +94,8 @@ bool Launcher::AdvancedPage::loadSettings()
|
||||
loadSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game");
|
||||
loadSettingBool(permanentBarterDispositionChangeCheckBox, "barter disposition change is permanent", "Game");
|
||||
loadSettingBool(classicReflectedAbsorbSpellsCheckBox, "classic reflected absorb spells behavior", "Game");
|
||||
loadSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game");
|
||||
loadSettingBool(
|
||||
requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game");
|
||||
loadSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
|
||||
loadSettingBool(normaliseRaceSpeedCheckBox, "normalise race speed", "Game");
|
||||
loadSettingBool(swimUpwardCorrectionCheckBox, "swim upward correction", "Game");
|
||||
@ -124,7 +124,8 @@ bool Launcher::AdvancedPage::loadSettings()
|
||||
loadSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders");
|
||||
loadSettingBool(softParticlesCheckBox, "soft particles", "Shaders");
|
||||
loadSettingBool(antialiasAlphaTestCheckBox, "antialias alpha test", "Shaders");
|
||||
if (Settings::Manager::getInt("antialiasing", "Video") == 0) {
|
||||
if (Settings::Manager::getInt("antialiasing", "Video") == 0)
|
||||
{
|
||||
antialiasAlphaTestCheckBox->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
loadSettingBool(magicItemAnimationsCheckBox, "use magic item animations", "Game");
|
||||
@ -140,7 +141,8 @@ bool Launcher::AdvancedPage::loadSettings()
|
||||
|
||||
const bool distantTerrain = Settings::Manager::getBool("distant terrain", "Terrain");
|
||||
const bool objectPaging = Settings::Manager::getBool("object paging", "Terrain");
|
||||
if (distantTerrain && objectPaging) {
|
||||
if (distantTerrain && objectPaging)
|
||||
{
|
||||
distantLandCheckBox->setCheckState(Qt::Checked);
|
||||
}
|
||||
|
||||
@ -210,17 +212,19 @@ bool Launcher::AdvancedPage::loadSettings()
|
||||
// Bug fixes
|
||||
{
|
||||
loadSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game");
|
||||
loadSettingBool(trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
|
||||
loadSettingBool(
|
||||
trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
|
||||
}
|
||||
|
||||
// Miscellaneous
|
||||
{
|
||||
// Saves
|
||||
loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
|
||||
loadSettingInt(maximumQuicksavesComboBox,"max quicksaves", "Saves");
|
||||
loadSettingInt(maximumQuicksavesComboBox, "max quicksaves", "Saves");
|
||||
|
||||
// Other Settings
|
||||
QString screenshotFormatString = QString::fromStdString(Settings::Manager::getString("screenshot format", "General")).toUpper();
|
||||
QString screenshotFormatString
|
||||
= QString::fromStdString(Settings::Manager::getString("screenshot format", "General")).toUpper();
|
||||
if (screenshotFormatComboBox->findText(screenshotFormatString) == -1)
|
||||
screenshotFormatComboBox->addItem(screenshotFormatString);
|
||||
screenshotFormatComboBox->setCurrentIndex(screenshotFormatComboBox->findText(screenshotFormatString));
|
||||
@ -257,7 +261,8 @@ void Launcher::AdvancedPage::saveSettings()
|
||||
saveSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game");
|
||||
saveSettingBool(permanentBarterDispositionChangeCheckBox, "barter disposition change is permanent", "Game");
|
||||
saveSettingBool(classicReflectedAbsorbSpellsCheckBox, "classic reflected absorb spells behavior", "Game");
|
||||
saveSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game");
|
||||
saveSettingBool(
|
||||
requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game");
|
||||
saveSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
|
||||
saveSettingBool(normaliseRaceSpeedCheckBox, "normalise race speed", "Game");
|
||||
saveSettingBool(swimUpwardCorrectionCheckBox, "swim upward correction", "Game");
|
||||
@ -291,7 +296,8 @@ void Launcher::AdvancedPage::saveSettings()
|
||||
const bool distantTerrain = Settings::Manager::getBool("distant terrain", "Terrain");
|
||||
const bool objectPaging = Settings::Manager::getBool("object paging", "Terrain");
|
||||
const bool wantDistantLand = distantLandCheckBox->checkState();
|
||||
if (wantDistantLand != (distantTerrain && objectPaging)) {
|
||||
if (wantDistantLand != (distantTerrain && objectPaging))
|
||||
{
|
||||
Settings::Manager::setBool("distant terrain", "Terrain", wantDistantLand);
|
||||
Settings::Manager::setBool("object paging", "Terrain", wantDistantLand);
|
||||
}
|
||||
@ -343,7 +349,7 @@ void Launcher::AdvancedPage::saveSettings()
|
||||
const std::string& prevHRTFProfile = Settings::Manager::getString("hrtf", "Sound");
|
||||
if (selectedHRTFProfileIndex != 0)
|
||||
{
|
||||
const std::string& newHRTFProfile = hrtfProfileSelectorComboBox->currentText().toUtf8().constData();
|
||||
const std::string& newHRTFProfile = hrtfProfileSelectorComboBox->currentText().toUtf8().constData();
|
||||
if (newHRTFProfile != prevHRTFProfile)
|
||||
Settings::Manager::setString("hrtf", "Sound", newHRTFProfile);
|
||||
}
|
||||
@ -360,7 +366,7 @@ void Launcher::AdvancedPage::saveSettings()
|
||||
saveSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
|
||||
saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
|
||||
saveSettingBool(changeDialogTopicsCheckBox, "color topic enable", "GUI");
|
||||
saveSettingInt(showOwnedComboBox,"show owned", "Game");
|
||||
saveSettingInt(showOwnedComboBox, "show owned", "Game");
|
||||
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
||||
saveSettingBool(useZoomOnMapCheckBox, "allow zooming", "Map");
|
||||
saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
||||
@ -377,7 +383,8 @@ void Launcher::AdvancedPage::saveSettings()
|
||||
// Bug fixes
|
||||
{
|
||||
saveSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game");
|
||||
saveSettingBool(trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
|
||||
saveSettingBool(
|
||||
trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
|
||||
}
|
||||
|
||||
// Miscellaneous
|
||||
@ -413,39 +420,39 @@ void Launcher::AdvancedPage::saveSettings()
|
||||
}
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::loadSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group)
|
||||
void Launcher::AdvancedPage::loadSettingBool(QCheckBox* checkbox, const std::string& setting, const std::string& group)
|
||||
{
|
||||
if (Settings::Manager::getBool(setting, group))
|
||||
checkbox->setCheckState(Qt::Checked);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::saveSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group)
|
||||
void Launcher::AdvancedPage::saveSettingBool(QCheckBox* checkbox, const std::string& setting, const std::string& group)
|
||||
{
|
||||
bool cValue = checkbox->checkState();
|
||||
if (cValue != Settings::Manager::getBool(setting, group))
|
||||
Settings::Manager::setBool(setting, group, cValue);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::loadSettingInt(QComboBox *comboBox, const std::string &setting, const std::string &group)
|
||||
void Launcher::AdvancedPage::loadSettingInt(QComboBox* comboBox, const std::string& setting, const std::string& group)
|
||||
{
|
||||
int currentIndex = Settings::Manager::getInt(setting, group);
|
||||
comboBox->setCurrentIndex(currentIndex);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::saveSettingInt(QComboBox *comboBox, const std::string &setting, const std::string &group)
|
||||
void Launcher::AdvancedPage::saveSettingInt(QComboBox* comboBox, const std::string& setting, const std::string& group)
|
||||
{
|
||||
int currentIndex = comboBox->currentIndex();
|
||||
if (currentIndex != Settings::Manager::getInt(setting, group))
|
||||
Settings::Manager::setInt(setting, group, currentIndex);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::loadSettingInt(QSpinBox *spinBox, const std::string &setting, const std::string &group)
|
||||
void Launcher::AdvancedPage::loadSettingInt(QSpinBox* spinBox, const std::string& setting, const std::string& group)
|
||||
{
|
||||
int value = Settings::Manager::getInt(setting, group);
|
||||
spinBox->setValue(value);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::saveSettingInt(QSpinBox *spinBox, const std::string &setting, const std::string &group)
|
||||
void Launcher::AdvancedPage::saveSettingInt(QSpinBox* spinBox, const std::string& setting, const std::string& group)
|
||||
{
|
||||
int value = spinBox->value();
|
||||
if (value != Settings::Manager::getInt(setting, group))
|
||||
|
@ -8,7 +8,10 @@
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
namespace Config { class GameSettings; }
|
||||
namespace Config
|
||||
{
|
||||
class GameSettings;
|
||||
}
|
||||
|
||||
namespace Launcher
|
||||
{
|
||||
@ -17,7 +20,7 @@ namespace Launcher
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AdvancedPage(Config::GameSettings &gameSettings, QWidget *parent = nullptr);
|
||||
explicit AdvancedPage(Config::GameSettings& gameSettings, QWidget* parent = nullptr);
|
||||
|
||||
bool loadSettings();
|
||||
void saveSettings();
|
||||
@ -33,7 +36,7 @@ namespace Launcher
|
||||
void slotSkyBlendingToggled(bool checked);
|
||||
|
||||
private:
|
||||
Config::GameSettings &mGameSettings;
|
||||
Config::GameSettings& mGameSettings;
|
||||
QCompleter mCellNameCompleter;
|
||||
QStringListModel mCellNameCompleterModel;
|
||||
|
||||
@ -42,12 +45,12 @@ namespace Launcher
|
||||
* @param filePaths the file paths of the content files to be examined
|
||||
*/
|
||||
void loadCellsForAutocomplete(QStringList filePaths);
|
||||
static void loadSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group);
|
||||
static void saveSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group);
|
||||
static void loadSettingInt(QComboBox *comboBox, const std::string& setting, const std::string& group);
|
||||
static void saveSettingInt(QComboBox *comboBox, const std::string& setting, const std::string& group);
|
||||
static void loadSettingInt(QSpinBox *spinBox, const std::string& setting, const std::string& group);
|
||||
static void saveSettingInt(QSpinBox *spinBox, const std::string& setting, const std::string& group);
|
||||
static void loadSettingBool(QCheckBox* checkbox, const std::string& setting, const std::string& group);
|
||||
static void saveSettingBool(QCheckBox* checkbox, const std::string& setting, const std::string& group);
|
||||
static void loadSettingInt(QComboBox* comboBox, const std::string& setting, const std::string& group);
|
||||
static void saveSettingInt(QComboBox* comboBox, const std::string& setting, const std::string& group);
|
||||
static void loadSettingInt(QSpinBox* spinBox, const std::string& setting, const std::string& group);
|
||||
static void saveSettingInt(QSpinBox* spinBox, const std::string& setting, const std::string& group);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -2,13 +2,13 @@
|
||||
#include "maindialog.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QPushButton>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <apps/launcher/utils/cellnameloader.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
@ -31,18 +31,18 @@
|
||||
|
||||
#include "ui_directorypicker.h"
|
||||
|
||||
const char *Launcher::DataFilesPage::mDefaultContentListName = "Default";
|
||||
const char* Launcher::DataFilesPage::mDefaultContentListName = "Default";
|
||||
|
||||
namespace
|
||||
{
|
||||
void contentSubdirs(const QString& path, QStringList& dirs)
|
||||
{
|
||||
QStringList fileFilter {"*.esm", "*.esp", "*.omwaddon", "*.bsa"};
|
||||
QStringList dirFilter {"bookart", "icons", "meshes", "music", "sound", "textures"};
|
||||
QStringList fileFilter{ "*.esm", "*.esp", "*.omwaddon", "*.bsa" };
|
||||
QStringList dirFilter{ "bookart", "icons", "meshes", "music", "sound", "textures" };
|
||||
|
||||
QDir currentDir(path);
|
||||
if (!currentDir.entryInfoList(fileFilter, QDir::Files).empty()
|
||||
|| !currentDir.entryInfoList(dirFilter, QDir::Dirs | QDir::NoDotAndDotDot).empty())
|
||||
|| !currentDir.entryInfoList(dirFilter, QDir::Dirs | QDir::NoDotAndDotDot).empty())
|
||||
dirs.push_back(currentDir.canonicalPath());
|
||||
|
||||
for (const auto& subdir : currentDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot))
|
||||
@ -63,61 +63,44 @@ namespace Launcher
|
||||
|
||||
HandleNavMeshToolMessage operator()(NavMeshTool::ExpectedCells&& message) const
|
||||
{
|
||||
return HandleNavMeshToolMessage {
|
||||
static_cast<int>(message.mCount),
|
||||
mExpectedMaxProgress,
|
||||
static_cast<int>(message.mCount) * 100,
|
||||
mProgress
|
||||
};
|
||||
return HandleNavMeshToolMessage{ static_cast<int>(message.mCount), mExpectedMaxProgress,
|
||||
static_cast<int>(message.mCount) * 100, mProgress };
|
||||
}
|
||||
|
||||
HandleNavMeshToolMessage operator()(NavMeshTool::ProcessedCells&& message) const
|
||||
{
|
||||
return HandleNavMeshToolMessage {
|
||||
mCellsCount,
|
||||
mExpectedMaxProgress,
|
||||
mMaxProgress,
|
||||
std::max(mProgress, static_cast<int>(message.mCount))
|
||||
};
|
||||
return HandleNavMeshToolMessage{ mCellsCount, mExpectedMaxProgress, mMaxProgress,
|
||||
std::max(mProgress, static_cast<int>(message.mCount)) };
|
||||
}
|
||||
|
||||
HandleNavMeshToolMessage operator()(NavMeshTool::ExpectedTiles&& message) const
|
||||
{
|
||||
const int expectedMaxProgress = mCellsCount + static_cast<int>(message.mCount);
|
||||
return HandleNavMeshToolMessage {
|
||||
mCellsCount,
|
||||
expectedMaxProgress,
|
||||
std::max(mMaxProgress, expectedMaxProgress),
|
||||
mProgress
|
||||
};
|
||||
return HandleNavMeshToolMessage{ mCellsCount, expectedMaxProgress,
|
||||
std::max(mMaxProgress, expectedMaxProgress), mProgress };
|
||||
}
|
||||
|
||||
HandleNavMeshToolMessage operator()(NavMeshTool::GeneratedTiles&& message) const
|
||||
{
|
||||
int progress = mCellsCount + static_cast<int>(message.mCount);
|
||||
if (mExpectedMaxProgress < mMaxProgress)
|
||||
progress += static_cast<int>(std::round(
|
||||
(mMaxProgress - mExpectedMaxProgress)
|
||||
* (static_cast<float>(progress) / static_cast<float>(mExpectedMaxProgress))
|
||||
));
|
||||
return HandleNavMeshToolMessage {
|
||||
mCellsCount,
|
||||
mExpectedMaxProgress,
|
||||
mMaxProgress,
|
||||
std::max(mProgress, progress)
|
||||
};
|
||||
progress += static_cast<int>(std::round((mMaxProgress - mExpectedMaxProgress)
|
||||
* (static_cast<float>(progress) / static_cast<float>(mExpectedMaxProgress))));
|
||||
return HandleNavMeshToolMessage{ mCellsCount, mExpectedMaxProgress, mMaxProgress,
|
||||
std::max(mProgress, progress) };
|
||||
}
|
||||
};
|
||||
|
||||
int getMaxNavMeshDbFileSizeMiB()
|
||||
{
|
||||
return static_cast<int>(Settings::Manager::getInt64("max navmeshdb file size", "Navigator") / (1024 * 1024));
|
||||
return static_cast<int>(
|
||||
Settings::Manager::getInt64("max navmeshdb file size", "Navigator") / (1024 * 1024));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings,
|
||||
Config::LauncherSettings &launcherSettings, MainDialog *parent)
|
||||
Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager& cfg, Config::GameSettings& gameSettings,
|
||||
Config::LauncherSettings& launcherSettings, MainDialog* parent)
|
||||
: QWidget(parent)
|
||||
, mMainDialog(parent)
|
||||
, mCfgMgr(cfg)
|
||||
@ -125,78 +108,78 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config:
|
||||
, mLauncherSettings(launcherSettings)
|
||||
, mNavMeshToolInvoker(new Process::ProcessInvoker(this))
|
||||
{
|
||||
ui.setupUi (this);
|
||||
setObjectName ("DataFilesPage");
|
||||
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget, /*showOMWScripts=*/true);
|
||||
ui.setupUi(this);
|
||||
setObjectName("DataFilesPage");
|
||||
mSelector = new ContentSelectorView::ContentSelector(ui.contentSelectorWidget, /*showOMWScripts=*/true);
|
||||
const QString encoding = mGameSettings.value("encoding", "win1252");
|
||||
mSelector->setEncoding(encoding);
|
||||
|
||||
mNewProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this);
|
||||
mCloneProfileDialog = new TextInputDialog(tr("Clone Content List"), tr("Content List name:"), this);
|
||||
|
||||
connect(mNewProfileDialog->lineEdit(), &LineEdit::textChanged,
|
||||
this, &DataFilesPage::updateNewProfileOkButton);
|
||||
connect(mCloneProfileDialog->lineEdit(), &LineEdit::textChanged,
|
||||
this, &DataFilesPage::updateCloneProfileOkButton);
|
||||
connect(mNewProfileDialog->lineEdit(), &LineEdit::textChanged, this, &DataFilesPage::updateNewProfileOkButton);
|
||||
connect(mCloneProfileDialog->lineEdit(), &LineEdit::textChanged, this, &DataFilesPage::updateCloneProfileOkButton);
|
||||
connect(ui.directoryAddSubdirsButton, &QPushButton::released, this, [this]() { this->addSubdirectories(true); });
|
||||
connect(ui.directoryInsertButton, &QPushButton::released, this, [this]() { this->addSubdirectories(false); });
|
||||
connect(ui.directoryUpButton, &QPushButton::released, this, [this]() { this->moveDirectory(-1); });
|
||||
connect(ui.directoryDownButton, &QPushButton::released, this, [this]() { this->moveDirectory(1); });
|
||||
connect(ui.directoryRemoveButton, &QPushButton::released, this, [this]() { this->removeDirectory(); });
|
||||
connect(ui.archiveUpButton, &QPushButton::released, this, [this]() { this->moveArchive(-1); });
|
||||
connect(ui.archiveDownButton, &QPushButton::released, this, [this]() { this->moveArchive(1); });
|
||||
connect(ui.directoryListWidget->model(), &QAbstractItemModel::rowsMoved, this, [this]() { this->sortDirectories(); });
|
||||
connect(ui.directoryInsertButton, &QPushButton::released, this, [this]() { this->addSubdirectories(false); });
|
||||
connect(ui.directoryUpButton, &QPushButton::released, this, [this]() { this->moveDirectory(-1); });
|
||||
connect(ui.directoryDownButton, &QPushButton::released, this, [this]() { this->moveDirectory(1); });
|
||||
connect(ui.directoryRemoveButton, &QPushButton::released, this, [this]() { this->removeDirectory(); });
|
||||
connect(ui.archiveUpButton, &QPushButton::released, this, [this]() { this->moveArchive(-1); });
|
||||
connect(ui.archiveDownButton, &QPushButton::released, this, [this]() { this->moveArchive(1); });
|
||||
connect(
|
||||
ui.directoryListWidget->model(), &QAbstractItemModel::rowsMoved, this, [this]() { this->sortDirectories(); });
|
||||
|
||||
buildView();
|
||||
loadSettings();
|
||||
|
||||
// Connect signal and slot after the settings have been loaded. We only care about the user changing
|
||||
// the addons and don't want to get signals of the system doing it during startup.
|
||||
connect(mSelector, &ContentSelectorView::ContentSelector::signalAddonDataChanged,
|
||||
this, &DataFilesPage::slotAddonDataChanged);
|
||||
connect(mSelector, &ContentSelectorView::ContentSelector::signalAddonDataChanged, this,
|
||||
&DataFilesPage::slotAddonDataChanged);
|
||||
// Call manually to indicate all changes to addon data during startup.
|
||||
slotAddonDataChanged();
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::buildView()
|
||||
{
|
||||
QToolButton * refreshButton = mSelector->refreshButton();
|
||||
QToolButton* refreshButton = mSelector->refreshButton();
|
||||
|
||||
//tool buttons
|
||||
ui.newProfileButton->setToolTip ("Create a new Content List");
|
||||
ui.cloneProfileButton->setToolTip ("Clone the current Content List");
|
||||
ui.deleteProfileButton->setToolTip ("Delete an existing Content List");
|
||||
// tool buttons
|
||||
ui.newProfileButton->setToolTip("Create a new Content List");
|
||||
ui.cloneProfileButton->setToolTip("Clone the current Content List");
|
||||
ui.deleteProfileButton->setToolTip("Delete an existing Content List");
|
||||
|
||||
//combo box
|
||||
// combo box
|
||||
ui.profilesComboBox->addItem(mDefaultContentListName);
|
||||
ui.profilesComboBox->setPlaceholderText (QString("Select a Content List..."));
|
||||
ui.profilesComboBox->setPlaceholderText(QString("Select a Content List..."));
|
||||
ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String(mDefaultContentListName)));
|
||||
|
||||
// Add the actions to the toolbuttons
|
||||
ui.newProfileButton->setDefaultAction (ui.newProfileAction);
|
||||
ui.cloneProfileButton->setDefaultAction (ui.cloneProfileAction);
|
||||
ui.deleteProfileButton->setDefaultAction (ui.deleteProfileAction);
|
||||
ui.newProfileButton->setDefaultAction(ui.newProfileAction);
|
||||
ui.cloneProfileButton->setDefaultAction(ui.cloneProfileAction);
|
||||
ui.deleteProfileButton->setDefaultAction(ui.deleteProfileAction);
|
||||
refreshButton->setDefaultAction(ui.refreshDataFilesAction);
|
||||
|
||||
//establish connections
|
||||
connect (ui.profilesComboBox, qOverload<int>(&::ProfilesComboBox::currentIndexChanged),
|
||||
this, &DataFilesPage::slotProfileChanged);
|
||||
// establish connections
|
||||
connect(ui.profilesComboBox, qOverload<int>(&::ProfilesComboBox::currentIndexChanged), this,
|
||||
&DataFilesPage::slotProfileChanged);
|
||||
|
||||
connect (ui.profilesComboBox, &::ProfilesComboBox::profileRenamed,
|
||||
this, &DataFilesPage::slotProfileRenamed);
|
||||
connect(ui.profilesComboBox, &::ProfilesComboBox::profileRenamed, this, &DataFilesPage::slotProfileRenamed);
|
||||
|
||||
connect (ui.profilesComboBox, qOverload<const QString&,const QString&>(&::ProfilesComboBox::signalProfileChanged),
|
||||
this, &DataFilesPage::slotProfileChangedByUser);
|
||||
connect(ui.profilesComboBox, qOverload<const QString&, const QString&>(&::ProfilesComboBox::signalProfileChanged),
|
||||
this, &DataFilesPage::slotProfileChangedByUser);
|
||||
|
||||
connect(ui.refreshDataFilesAction, &QAction::triggered,
|
||||
this, &DataFilesPage::slotRefreshButtonClicked);
|
||||
connect(ui.refreshDataFilesAction, &QAction::triggered, this, &DataFilesPage::slotRefreshButtonClicked);
|
||||
|
||||
connect(ui.updateNavMeshButton, &QPushButton::clicked, this, &DataFilesPage::startNavMeshTool);
|
||||
connect(ui.cancelNavMeshButton, &QPushButton::clicked, this, &DataFilesPage::killNavMeshTool);
|
||||
|
||||
connect(mNavMeshToolInvoker->getProcess(), &QProcess::readyReadStandardOutput, this, &DataFilesPage::readNavMeshToolStdout);
|
||||
connect(mNavMeshToolInvoker->getProcess(), &QProcess::readyReadStandardError, this, &DataFilesPage::readNavMeshToolStderr);
|
||||
connect(mNavMeshToolInvoker->getProcess(), qOverload<int,QProcess::ExitStatus>(&QProcess::finished), this, &DataFilesPage::navMeshToolFinished);
|
||||
connect(mNavMeshToolInvoker->getProcess(), &QProcess::readyReadStandardOutput, this,
|
||||
&DataFilesPage::readNavMeshToolStdout);
|
||||
connect(mNavMeshToolInvoker->getProcess(), &QProcess::readyReadStandardError, this,
|
||||
&DataFilesPage::readNavMeshToolStderr);
|
||||
connect(mNavMeshToolInvoker->getProcess(), qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
|
||||
&DataFilesPage::navMeshToolFinished);
|
||||
}
|
||||
|
||||
bool Launcher::DataFilesPage::loadSettings()
|
||||
@ -208,8 +191,8 @@ bool Launcher::DataFilesPage::loadSettings()
|
||||
|
||||
qDebug() << "The current profile is: " << currentProfile;
|
||||
|
||||
for (const QString &item : profiles)
|
||||
addProfile (item, false);
|
||||
for (const QString& item : profiles)
|
||||
addProfile(item, false);
|
||||
|
||||
// Hack: also add the current profile
|
||||
if (!currentProfile.isEmpty())
|
||||
@ -267,10 +250,11 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||
|
||||
// deactivate data-local and global data directory: they are always included
|
||||
const auto tmp = currentDir.toUtf8();
|
||||
if (currentDir == mDataLocal || std::filesystem::path(Misc::StringUtils::stringToU8String(tmp)) == globalDataDir)
|
||||
if (currentDir == mDataLocal
|
||||
|| std::filesystem::path(Misc::StringUtils::stringToU8String(tmp)) == globalDataDir)
|
||||
{
|
||||
auto flags = item->flags();
|
||||
item->setFlags(flags & ~(Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled|Qt::ItemIsEnabled));
|
||||
item->setFlags(flags & ~(Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled));
|
||||
}
|
||||
|
||||
// Add a "data file" icon if the directory contains a content file
|
||||
@ -293,7 +277,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||
|
||||
QStringList selectedArchives = mLauncherSettings.getArchiveList(contentModelName);
|
||||
if (selectedArchives.isEmpty())
|
||||
selectedArchives = mGameSettings.getArchiveList();
|
||||
selectedArchives = mGameSettings.getArchiveList();
|
||||
|
||||
// sort and tick BSA according to profile
|
||||
int row = 0;
|
||||
@ -331,27 +315,28 @@ QStringList Launcher::DataFilesPage::filesInProfile(const QString& profileName,
|
||||
return filepaths;
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::saveSettings(const QString &profile)
|
||||
void Launcher::DataFilesPage::saveSettings(const QString& profile)
|
||||
{
|
||||
if (const int value = ui.navMeshMaxSizeSpinBox->value(); value != getMaxNavMeshDbFileSizeMiB())
|
||||
Settings::Manager::setInt64("max navmeshdb file size", "Navigator", static_cast<std::int64_t>(value) * 1024 * 1024);
|
||||
Settings::Manager::setInt64(
|
||||
"max navmeshdb file size", "Navigator", static_cast<std::int64_t>(value) * 1024 * 1024);
|
||||
|
||||
QString profileName = profile;
|
||||
|
||||
if (profileName.isEmpty())
|
||||
profileName = ui.profilesComboBox->currentText();
|
||||
|
||||
//retrieve the data paths
|
||||
// retrieve the data paths
|
||||
auto dirList = selectedDirectoriesPaths();
|
||||
|
||||
//retrieve the files selected for the profile
|
||||
// retrieve the files selected for the profile
|
||||
ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
|
||||
|
||||
//set the value of the current profile (not necessarily the profile being saved!)
|
||||
// set the value of the current profile (not necessarily the profile being saved!)
|
||||
mLauncherSettings.setCurrentContentListName(ui.profilesComboBox->currentText());
|
||||
|
||||
QStringList fileNames;
|
||||
for (const ContentSelectorModel::EsmFile *item : items)
|
||||
for (const ContentSelectorModel::EsmFile* item : items)
|
||||
{
|
||||
fileNames.append(item->fileName());
|
||||
}
|
||||
@ -361,49 +346,49 @@ void Launcher::DataFilesPage::saveSettings(const QString &profile)
|
||||
|
||||
QStringList Launcher::DataFilesPage::selectedDirectoriesPaths() const
|
||||
{
|
||||
QStringList dirList;
|
||||
for (int i = 0; i < ui.directoryListWidget->count(); ++i)
|
||||
{
|
||||
if (ui.directoryListWidget->item(i)->flags() & Qt::ItemIsEnabled)
|
||||
dirList.append(ui.directoryListWidget->item(i)->text());
|
||||
}
|
||||
return dirList;
|
||||
QStringList dirList;
|
||||
for (int i = 0; i < ui.directoryListWidget->count(); ++i)
|
||||
{
|
||||
if (ui.directoryListWidget->item(i)->flags() & Qt::ItemIsEnabled)
|
||||
dirList.append(ui.directoryListWidget->item(i)->text());
|
||||
}
|
||||
return dirList;
|
||||
}
|
||||
|
||||
QStringList Launcher::DataFilesPage::selectedArchivePaths(bool all) const
|
||||
{
|
||||
QStringList archiveList;
|
||||
for (int i = 0; i < ui.archiveListWidget->count(); ++i)
|
||||
{
|
||||
const auto* item = ui.archiveListWidget->item(i);
|
||||
const auto archive = ui.archiveListWidget->item(i)->text();
|
||||
QStringList archiveList;
|
||||
for (int i = 0; i < ui.archiveListWidget->count(); ++i)
|
||||
{
|
||||
const auto* item = ui.archiveListWidget->item(i);
|
||||
const auto archive = ui.archiveListWidget->item(i)->text();
|
||||
|
||||
if (all ||item->checkState() == Qt::Checked)
|
||||
archiveList.append(item->text());
|
||||
}
|
||||
return archiveList;
|
||||
if (all || item->checkState() == Qt::Checked)
|
||||
archiveList.append(item->text());
|
||||
}
|
||||
return archiveList;
|
||||
}
|
||||
|
||||
QStringList Launcher::DataFilesPage::selectedFilePaths() const
|
||||
{
|
||||
//retrieve the files selected for the profile
|
||||
// retrieve the files selected for the profile
|
||||
ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
|
||||
QStringList filePaths;
|
||||
for (const ContentSelectorModel::EsmFile *item : items)
|
||||
for (const ContentSelectorModel::EsmFile* item : items)
|
||||
{
|
||||
QFile file(item->filePath());
|
||||
if(file.exists())
|
||||
if (file.exists())
|
||||
filePaths.append(item->filePath());
|
||||
}
|
||||
return filePaths;
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::removeProfile(const QString &profile)
|
||||
void Launcher::DataFilesPage::removeProfile(const QString& profile)
|
||||
{
|
||||
mLauncherSettings.removeContentList(profile);
|
||||
}
|
||||
|
||||
QAbstractItemModel *Launcher::DataFilesPage::profilesModel() const
|
||||
QAbstractItemModel* Launcher::DataFilesPage::profilesModel() const
|
||||
{
|
||||
return ui.profilesComboBox->model();
|
||||
}
|
||||
@ -422,20 +407,20 @@ void Launcher::DataFilesPage::setProfile(int index, bool savePrevious)
|
||||
|
||||
mPreviousProfile = current;
|
||||
|
||||
setProfile (previous, current, savePrevious);
|
||||
setProfile(previous, current, savePrevious);
|
||||
}
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::setProfile (const QString &previous, const QString ¤t, bool savePrevious)
|
||||
void Launcher::DataFilesPage::setProfile(const QString& previous, const QString& current, bool savePrevious)
|
||||
{
|
||||
//abort if no change (poss. duplicate signal)
|
||||
// abort if no change (poss. duplicate signal)
|
||||
if (previous == current)
|
||||
return;
|
||||
return;
|
||||
|
||||
if (!previous.isEmpty() && savePrevious)
|
||||
saveSettings (previous);
|
||||
saveSettings(previous);
|
||||
|
||||
ui.profilesComboBox->setCurrentProfile (ui.profilesComboBox->findText (current));
|
||||
ui.profilesComboBox->setCurrentProfile(ui.profilesComboBox->findText(current));
|
||||
|
||||
mNewDataDirs.clear();
|
||||
mKnownArchives.clear();
|
||||
@ -451,30 +436,30 @@ void Launcher::DataFilesPage::setProfile (const QString &previous, const QString
|
||||
checkForDefaultProfile();
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::slotProfileDeleted (const QString &item)
|
||||
void Launcher::DataFilesPage::slotProfileDeleted(const QString& item)
|
||||
{
|
||||
removeProfile (item);
|
||||
removeProfile(item);
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage:: refreshDataFilesView ()
|
||||
void Launcher::DataFilesPage::refreshDataFilesView()
|
||||
{
|
||||
QString currentProfile = ui.profilesComboBox->currentText();
|
||||
saveSettings(currentProfile);
|
||||
populateFileViews(currentProfile);
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::slotRefreshButtonClicked ()
|
||||
void Launcher::DataFilesPage::slotRefreshButtonClicked()
|
||||
{
|
||||
refreshDataFilesView();
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::slotProfileChangedByUser(const QString &previous, const QString ¤t)
|
||||
void Launcher::DataFilesPage::slotProfileChangedByUser(const QString& previous, const QString& current)
|
||||
{
|
||||
setProfile(previous, current, true);
|
||||
emit signalProfileChanged (ui.profilesComboBox->findText(current));
|
||||
emit signalProfileChanged(ui.profilesComboBox->findText(current));
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::slotProfileRenamed(const QString &previous, const QString ¤t)
|
||||
void Launcher::DataFilesPage::slotProfileRenamed(const QString& previous, const QString& current)
|
||||
{
|
||||
if (previous.isEmpty())
|
||||
return;
|
||||
@ -483,7 +468,7 @@ void Launcher::DataFilesPage::slotProfileRenamed(const QString &previous, const
|
||||
saveSettings();
|
||||
|
||||
// Remove the old one
|
||||
removeProfile (previous);
|
||||
removeProfile(previous);
|
||||
|
||||
loadSettings();
|
||||
}
|
||||
@ -494,7 +479,7 @@ void Launcher::DataFilesPage::slotProfileChanged(int index)
|
||||
if (ui.profilesComboBox->currentIndex() != index)
|
||||
ui.profilesComboBox->setCurrentIndex(index);
|
||||
|
||||
setProfile (index, true);
|
||||
setProfile(index, true);
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::on_newProfileAction_triggered()
|
||||
@ -514,16 +499,16 @@ void Launcher::DataFilesPage::on_newProfileAction_triggered()
|
||||
addProfile(profile, true);
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::addProfile (const QString &profile, bool setAsCurrent)
|
||||
void Launcher::DataFilesPage::addProfile(const QString& profile, bool setAsCurrent)
|
||||
{
|
||||
if (profile.isEmpty())
|
||||
return;
|
||||
|
||||
if (ui.profilesComboBox->findText (profile) == -1)
|
||||
ui.profilesComboBox->addItem (profile);
|
||||
if (ui.profilesComboBox->findText(profile) == -1)
|
||||
ui.profilesComboBox->addItem(profile);
|
||||
|
||||
if (setAsCurrent)
|
||||
setProfile (ui.profilesComboBox->findText (profile), false);
|
||||
setProfile(ui.profilesComboBox->findText(profile), false);
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::on_cloneProfileAction_triggered()
|
||||
@ -547,11 +532,11 @@ void Launcher::DataFilesPage::on_deleteProfileAction_triggered()
|
||||
if (profile.isEmpty())
|
||||
return;
|
||||
|
||||
if (!showDeleteMessageBox (profile))
|
||||
if (!showDeleteMessageBox(profile))
|
||||
return;
|
||||
|
||||
// this should work since the Default profile can't be deleted and is always index 0
|
||||
int next = ui.profilesComboBox->currentIndex()-1;
|
||||
int next = ui.profilesComboBox->currentIndex() - 1;
|
||||
|
||||
// changing the profile forces a reload of plugin file views.
|
||||
ui.profilesComboBox->setCurrentIndex(next);
|
||||
@ -562,13 +547,13 @@ void Launcher::DataFilesPage::on_deleteProfileAction_triggered()
|
||||
checkForDefaultProfile();
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::updateNewProfileOkButton(const QString &text)
|
||||
void Launcher::DataFilesPage::updateNewProfileOkButton(const QString& text)
|
||||
{
|
||||
// We do this here because we need the profiles combobox text
|
||||
mNewProfileDialog->setOkButtonEnabled(!text.isEmpty() && ui.profilesComboBox->findText(text) == -1);
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::updateCloneProfileOkButton(const QString &text)
|
||||
void Launcher::DataFilesPage::updateCloneProfileOkButton(const QString& text)
|
||||
{
|
||||
// We do this here because we need the profiles combobox text
|
||||
mCloneProfileDialog->setOkButtonEnabled(!text.isEmpty() && ui.profilesComboBox->findText(text) == -1);
|
||||
@ -584,7 +569,6 @@ QString Launcher::DataFilesPage::selectDirectory()
|
||||
return {};
|
||||
|
||||
return QDir(fileDialog.selectedFiles()[0]).canonicalPath();
|
||||
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::addSubdirectories(bool append)
|
||||
@ -634,12 +618,12 @@ void Launcher::DataFilesPage::addSubdirectories(bool append)
|
||||
|
||||
for (int i = 0; i < select.dirListWidget->count(); ++i)
|
||||
{
|
||||
const auto* dir = select.dirListWidget->item(i);
|
||||
if (dir->checkState() == Qt::Checked)
|
||||
{
|
||||
ui.directoryListWidget->insertItem(selectedRow++, dir->text());
|
||||
mNewDataDirs.push_back(dir->text());
|
||||
}
|
||||
const auto* dir = select.dirListWidget->item(i);
|
||||
if (dir->checkState() == Qt::Checked)
|
||||
{
|
||||
ui.directoryListWidget->insertItem(selectedRow++, dir->text());
|
||||
mNewDataDirs.push_back(dir->text());
|
||||
}
|
||||
}
|
||||
|
||||
refreshDataFilesView();
|
||||
@ -650,8 +634,8 @@ void Launcher::DataFilesPage::sortDirectories()
|
||||
// Ensure disabled entries (aka default directories) are always at the top.
|
||||
for (auto i = 1; i < ui.directoryListWidget->count(); ++i)
|
||||
{
|
||||
if (!(ui.directoryListWidget->item(i)->flags() & Qt::ItemIsEnabled) &&
|
||||
(ui.directoryListWidget->item(i - 1)->flags() & Qt::ItemIsEnabled))
|
||||
if (!(ui.directoryListWidget->item(i)->flags() & Qt::ItemIsEnabled)
|
||||
&& (ui.directoryListWidget->item(i - 1)->flags() & Qt::ItemIsEnabled))
|
||||
{
|
||||
const auto item = ui.directoryListWidget->takeItem(i);
|
||||
ui.directoryListWidget->insertItem(i - 1, item);
|
||||
@ -728,14 +712,14 @@ void Launcher::DataFilesPage::addArchivesFromDir(const QString& path)
|
||||
|
||||
void Launcher::DataFilesPage::checkForDefaultProfile()
|
||||
{
|
||||
//don't allow deleting "Default" profile
|
||||
// don't allow deleting "Default" profile
|
||||
bool success = (ui.profilesComboBox->currentText() != mDefaultContentListName);
|
||||
|
||||
ui.deleteProfileAction->setEnabled (success);
|
||||
ui.profilesComboBox->setEditEnabled (success);
|
||||
ui.deleteProfileAction->setEnabled(success);
|
||||
ui.profilesComboBox->setEditEnabled(success);
|
||||
}
|
||||
|
||||
bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text)
|
||||
bool Launcher::DataFilesPage::showDeleteMessageBox(const QString& text)
|
||||
{
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setWindowTitle(tr("Delete Content List"));
|
||||
@ -743,8 +727,7 @@ bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text)
|
||||
msgBox.setStandardButtons(QMessageBox::Cancel);
|
||||
msgBox.setText(tr("Are you sure you want to delete <b>%1</b>?").arg(text));
|
||||
|
||||
QAbstractButton *deleteButton =
|
||||
msgBox.addButton(tr("Delete"), QMessageBox::ActionRole);
|
||||
QAbstractButton* deleteButton = msgBox.addButton(tr("Delete"), QMessageBox::ActionRole);
|
||||
|
||||
msgBox.exec();
|
||||
|
||||
@ -754,7 +737,8 @@ bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text)
|
||||
void Launcher::DataFilesPage::slotAddonDataChanged()
|
||||
{
|
||||
QStringList selectedFiles = selectedFilePaths();
|
||||
if (previousSelectedFiles != selectedFiles) {
|
||||
if (previousSelectedFiles != selectedFiles)
|
||||
{
|
||||
previousSelectedFiles = selectedFiles;
|
||||
// Loading cells for core Morrowind + Expansions takes about 0.2 seconds, which is enough to cause a
|
||||
// barely perceptible UI lag. Splitting into its own thread to alleviate that.
|
||||
@ -774,7 +758,7 @@ void Launcher::DataFilesPage::reloadCells(QStringList selectedFiles)
|
||||
|
||||
// The following code will run only if there is not another thread currently running it
|
||||
CellNameLoader cellNameLoader;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QSet<QString> set = cellNameLoader.getCellNames(selectedFiles);
|
||||
QStringList cellNamesList(set.begin(), set.end());
|
||||
#else
|
||||
@ -792,9 +776,9 @@ void Launcher::DataFilesPage::startNavMeshTool()
|
||||
ui.navMeshProgressBar->setValue(0);
|
||||
ui.navMeshProgressBar->setMaximum(1);
|
||||
|
||||
mNavMeshToolProgress = NavMeshToolProgress {};
|
||||
mNavMeshToolProgress = NavMeshToolProgress{};
|
||||
|
||||
QStringList arguments({"--write-binary-log"});
|
||||
QStringList arguments({ "--write-binary-log" });
|
||||
if (ui.navMeshRemoveUnusedTilesCheckBox->checkState() == Qt::Checked)
|
||||
arguments.append("--remove-unused-tiles");
|
||||
|
||||
@ -824,7 +808,7 @@ void Launcher::DataFilesPage::updateNavMeshProgress(int minDataSize)
|
||||
const std::byte* const begin = reinterpret_cast<const std::byte*>(mNavMeshToolProgress.mMessagesData.constData());
|
||||
const std::byte* const end = begin + mNavMeshToolProgress.mMessagesData.size();
|
||||
const std::byte* position = begin;
|
||||
HandleNavMeshToolMessage handle {
|
||||
HandleNavMeshToolMessage handle{
|
||||
mNavMeshToolProgress.mCellsCount,
|
||||
mNavMeshToolProgress.mExpectedMaxProgress,
|
||||
ui.navMeshProgressBar->maximum(),
|
||||
@ -863,7 +847,8 @@ void Launcher::DataFilesPage::readNavMeshToolStdout()
|
||||
void Launcher::DataFilesPage::navMeshToolFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
updateNavMeshProgress(0);
|
||||
ui.navMeshLogPlainTextEdit->appendPlainText(QString::fromUtf8(mNavMeshToolInvoker->getProcess()->readAllStandardOutput()));
|
||||
ui.navMeshLogPlainTextEdit->appendPlainText(
|
||||
QString::fromUtf8(mNavMeshToolInvoker->getProcess()->readAllStandardOutput()));
|
||||
if (exitCode == 0 && exitStatus == QProcess::ExitStatus::NormalExit)
|
||||
ui.navMeshProgressBar->setValue(ui.navMeshProgressBar->maximum());
|
||||
ui.cancelNavMeshButton->setEnabled(false);
|
||||
|
@ -5,18 +5,27 @@
|
||||
|
||||
#include <components/process/processinvoker.hpp>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDir>
|
||||
#include <QStringList>
|
||||
#include <QWidget>
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
class QAbstractItemModel;
|
||||
class QMenu;
|
||||
|
||||
namespace Files { struct ConfigurationManager; }
|
||||
namespace ContentSelectorView { class ContentSelector; }
|
||||
namespace Config { class GameSettings;
|
||||
class LauncherSettings; }
|
||||
namespace Files
|
||||
{
|
||||
struct ConfigurationManager;
|
||||
}
|
||||
namespace ContentSelectorView
|
||||
{
|
||||
class ContentSelector;
|
||||
}
|
||||
namespace Config
|
||||
{
|
||||
class GameSettings;
|
||||
class LauncherSettings;
|
||||
}
|
||||
|
||||
namespace Launcher
|
||||
{
|
||||
@ -28,38 +37,38 @@ namespace Launcher
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
ContentSelectorView::ContentSelector *mSelector;
|
||||
ContentSelectorView::ContentSelector* mSelector;
|
||||
Ui::DataFilesPage ui;
|
||||
|
||||
public:
|
||||
explicit DataFilesPage (Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings,
|
||||
Config::LauncherSettings &launcherSettings, MainDialog *parent = nullptr);
|
||||
explicit DataFilesPage(Files::ConfigurationManager& cfg, Config::GameSettings& gameSettings,
|
||||
Config::LauncherSettings& launcherSettings, MainDialog* parent = nullptr);
|
||||
|
||||
QAbstractItemModel* profilesModel() const;
|
||||
|
||||
int profilesIndex() const;
|
||||
|
||||
//void writeConfig(QString profile = QString());
|
||||
void saveSettings(const QString &profile = "");
|
||||
// void writeConfig(QString profile = QString());
|
||||
void saveSettings(const QString& profile = "");
|
||||
bool loadSettings();
|
||||
|
||||
signals:
|
||||
void signalProfileChanged (int index);
|
||||
void signalProfileChanged(int index);
|
||||
void signalLoadedCellsChanged(QStringList selectedFiles);
|
||||
|
||||
public slots:
|
||||
void slotProfileChanged (int index);
|
||||
void slotProfileChanged(int index);
|
||||
|
||||
private slots:
|
||||
|
||||
void slotProfileChangedByUser(const QString &previous, const QString ¤t);
|
||||
void slotProfileRenamed(const QString &previous, const QString ¤t);
|
||||
void slotProfileDeleted(const QString &item);
|
||||
void slotAddonDataChanged ();
|
||||
void slotRefreshButtonClicked ();
|
||||
void slotProfileChangedByUser(const QString& previous, const QString& current);
|
||||
void slotProfileRenamed(const QString& previous, const QString& current);
|
||||
void slotProfileDeleted(const QString& item);
|
||||
void slotAddonDataChanged();
|
||||
void slotRefreshButtonClicked();
|
||||
|
||||
void updateNewProfileOkButton(const QString &text);
|
||||
void updateCloneProfileOkButton(const QString &text);
|
||||
void updateNewProfileOkButton(const QString& text);
|
||||
void updateCloneProfileOkButton(const QString& text);
|
||||
void addSubdirectories(bool append);
|
||||
void sortDirectories();
|
||||
void removeDirectory();
|
||||
@ -78,7 +87,7 @@ namespace Launcher
|
||||
|
||||
public:
|
||||
/// Content List that is always present
|
||||
const static char *mDefaultContentListName;
|
||||
const static char* mDefaultContentListName;
|
||||
|
||||
private:
|
||||
struct NavMeshToolProgress
|
||||
@ -90,14 +99,14 @@ namespace Launcher
|
||||
int mExpectedMaxProgress = 0;
|
||||
};
|
||||
|
||||
MainDialog *mMainDialog;
|
||||
TextInputDialog *mNewProfileDialog;
|
||||
TextInputDialog *mCloneProfileDialog;
|
||||
MainDialog* mMainDialog;
|
||||
TextInputDialog* mNewProfileDialog;
|
||||
TextInputDialog* mCloneProfileDialog;
|
||||
|
||||
Files::ConfigurationManager &mCfgMgr;
|
||||
Files::ConfigurationManager& mCfgMgr;
|
||||
|
||||
Config::GameSettings &mGameSettings;
|
||||
Config::LauncherSettings &mLauncherSettings;
|
||||
Config::GameSettings& mGameSettings;
|
||||
Config::LauncherSettings& mLauncherSettings;
|
||||
|
||||
QString mPreviousProfile;
|
||||
QStringList previousSelectedFiles;
|
||||
@ -111,15 +120,15 @@ namespace Launcher
|
||||
void addArchive(const QString& name, Qt::CheckState selected, int row = -1);
|
||||
void addArchivesFromDir(const QString& dir);
|
||||
void buildView();
|
||||
void setProfile (int index, bool savePrevious);
|
||||
void setProfile (const QString &previous, const QString ¤t, bool savePrevious);
|
||||
void removeProfile (const QString &profile);
|
||||
bool showDeleteMessageBox (const QString &text);
|
||||
void addProfile (const QString &profile, bool setAsCurrent);
|
||||
void setProfile(int index, bool savePrevious);
|
||||
void setProfile(const QString& previous, const QString& current, bool savePrevious);
|
||||
void removeProfile(const QString& profile);
|
||||
bool showDeleteMessageBox(const QString& text);
|
||||
void addProfile(const QString& profile, bool setAsCurrent);
|
||||
void checkForDefaultProfile();
|
||||
void populateFileViews(const QString& contentModelName);
|
||||
void reloadCells(QStringList selectedFiles);
|
||||
void refreshDataFilesView ();
|
||||
void refreshDataFilesView();
|
||||
void updateNavMeshProgress(int minDataSize);
|
||||
QString selectDirectory();
|
||||
|
||||
@ -128,7 +137,7 @@ namespace Launcher
|
||||
* @return the file paths of all selected content files
|
||||
*/
|
||||
QStringList selectedFilePaths() const;
|
||||
QStringList selectedArchivePaths(bool all=false) const;
|
||||
QStringList selectedArchivePaths(bool all = false) const;
|
||||
QStringList selectedDirectoriesPaths() const;
|
||||
|
||||
class PathIterator
|
||||
@ -140,25 +149,24 @@ namespace Launcher
|
||||
QString mFilePath;
|
||||
|
||||
public:
|
||||
PathIterator (const QStringList &list)
|
||||
PathIterator(const QStringList& list)
|
||||
{
|
||||
mCitBegin = list.constBegin();
|
||||
mCitCurrent = mCitBegin;
|
||||
mCitEnd = list.constEnd();
|
||||
}
|
||||
|
||||
QString findFirstPath (const QString &file)
|
||||
QString findFirstPath(const QString& file)
|
||||
{
|
||||
mCitCurrent = mCitBegin;
|
||||
mFile = file;
|
||||
return path();
|
||||
}
|
||||
|
||||
QString findNextPath () { return path(); }
|
||||
QString findNextPath() { return path(); }
|
||||
|
||||
private:
|
||||
|
||||
QString path ()
|
||||
QString path()
|
||||
{
|
||||
bool success = false;
|
||||
QDir dir;
|
||||
@ -169,8 +177,8 @@ namespace Launcher
|
||||
if (mCitCurrent == mCitEnd)
|
||||
break;
|
||||
|
||||
dir.setPath (*(mCitCurrent++));
|
||||
file.setFile (dir.absoluteFilePath (mFile));
|
||||
dir.setPath(*(mCitCurrent++));
|
||||
file.setFile(dir.absoluteFilePath(mFile));
|
||||
|
||||
success = file.exists();
|
||||
}
|
||||
@ -180,7 +188,6 @@ namespace Launcher
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
QStringList filesInProfile(const QString& profileName, PathIterator& pathIterator);
|
||||
|
@ -13,12 +13,12 @@
|
||||
|
||||
#include <SDL_video.h>
|
||||
|
||||
#include <numeric>
|
||||
#include <array>
|
||||
#include <numeric>
|
||||
|
||||
QString getAspect(int x, int y)
|
||||
{
|
||||
int gcd = std::gcd (x, y);
|
||||
int gcd = std::gcd(x, y);
|
||||
if (gcd == 0)
|
||||
return QString();
|
||||
|
||||
@ -31,10 +31,10 @@ QString getAspect(int x, int y)
|
||||
return QString(QString::number(xaspect) + ":" + QString::number(yaspect));
|
||||
}
|
||||
|
||||
Launcher::GraphicsPage::GraphicsPage(QWidget *parent)
|
||||
Launcher::GraphicsPage::GraphicsPage(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setObjectName ("GraphicsPage");
|
||||
setObjectName("GraphicsPage");
|
||||
setupUi(this);
|
||||
|
||||
// Set the maximum res we can set in windowed mode
|
||||
@ -42,7 +42,8 @@ Launcher::GraphicsPage::GraphicsPage(QWidget *parent)
|
||||
customWidthSpinBox->setMaximum(res.width());
|
||||
customHeightSpinBox->setMaximum(res.height());
|
||||
|
||||
connect(windowModeComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this, &GraphicsPage::slotFullScreenChanged);
|
||||
connect(windowModeComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
&GraphicsPage::slotFullScreenChanged);
|
||||
connect(standardRadioButton, &QRadioButton::toggled, this, &GraphicsPage::slotStandardToggled);
|
||||
connect(screenComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this, &GraphicsPage::screenChanged);
|
||||
connect(framerateLimitCheckBox, &QCheckBox::toggled, this, &GraphicsPage::slotFramerateLimitToggled);
|
||||
@ -65,7 +66,8 @@ bool Launcher::GraphicsPage::setupSDL()
|
||||
msgBox.setWindowTitle(tr("Error receiving number of screens"));
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>SDL_GetNumVideoDisplays failed:</b><br><br>") + QString::fromUtf8(SDL_GetError()) + "<br>");
|
||||
msgBox.setText(
|
||||
tr("<br><b>SDL_GetNumVideoDisplays failed:</b><br><br>") + QString::fromUtf8(SDL_GetError()) + "<br>");
|
||||
msgBox.exec();
|
||||
return false;
|
||||
}
|
||||
@ -116,10 +118,13 @@ bool Launcher::GraphicsPage::loadSettings()
|
||||
|
||||
int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith);
|
||||
|
||||
if (resIndex != -1) {
|
||||
if (resIndex != -1)
|
||||
{
|
||||
standardRadioButton->toggle();
|
||||
resolutionComboBox->setCurrentIndex(resIndex);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
customRadioButton->toggle();
|
||||
customWidthSpinBox->setValue(width);
|
||||
customHeightSpinBox->setValue(height);
|
||||
@ -152,9 +157,8 @@ bool Launcher::GraphicsPage::loadSettings()
|
||||
if (Settings::Manager::getBool("enable indoor shadows", "Shadows"))
|
||||
indoorShadowsCheckBox->setCheckState(Qt::Checked);
|
||||
|
||||
shadowComputeSceneBoundsComboBox->setCurrentIndex(
|
||||
shadowComputeSceneBoundsComboBox->findText(
|
||||
QString(tr(Settings::Manager::getString("compute scene bounds", "Shadows").c_str()))));
|
||||
shadowComputeSceneBoundsComboBox->setCurrentIndex(shadowComputeSceneBoundsComboBox->findText(
|
||||
QString(tr(Settings::Manager::getString("compute scene bounds", "Shadows").c_str()))));
|
||||
|
||||
int shadowDistLimit = Settings::Manager::getInt("maximum shadow map distance", "Shadows");
|
||||
if (shadowDistLimit > 0)
|
||||
@ -199,13 +203,17 @@ void Launcher::GraphicsPage::saveSettings()
|
||||
|
||||
int cWidth = 0;
|
||||
int cHeight = 0;
|
||||
if (standardRadioButton->isChecked()) {
|
||||
if (standardRadioButton->isChecked())
|
||||
{
|
||||
QRegExp resolutionRe(QString("(\\d+) x (\\d+).*"));
|
||||
if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) {
|
||||
if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified()))
|
||||
{
|
||||
cWidth = resolutionRe.cap(1).toInt();
|
||||
cHeight = resolutionRe.cap(2).toInt();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
cWidth = customWidthSpinBox->value();
|
||||
cHeight = customHeightSpinBox->value();
|
||||
}
|
||||
@ -232,7 +240,7 @@ void Launcher::GraphicsPage::saveSettings()
|
||||
}
|
||||
|
||||
// Lighting
|
||||
static std::array<std::string, 3> lightingMethodMap = {"legacy", "shaders compatibility", "shaders"};
|
||||
static std::array<std::string, 3> lightingMethodMap = { "legacy", "shaders compatibility", "shaders" };
|
||||
const std::string& cLightingMethod = lightingMethodMap[lightingMethodComboBox->currentIndex()];
|
||||
if (cLightingMethod != Settings::Manager::getString("lighting method", "Shaders"))
|
||||
Settings::Manager::setString("lighting method", "Shaders", cLightingMethod);
|
||||
@ -301,7 +309,8 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
|
||||
msgBox.setWindowTitle(tr("Error receiving resolutions"));
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>SDL_GetNumDisplayModes failed:</b><br><br>") + QString::fromUtf8(SDL_GetError()) + "<br>");
|
||||
msgBox.setText(
|
||||
tr("<br><b>SDL_GetNumDisplayModes failed:</b><br><br>") + QString::fromUtf8(SDL_GetError()) + "<br>");
|
||||
msgBox.exec();
|
||||
return result;
|
||||
}
|
||||
@ -314,7 +323,8 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
|
||||
msgBox.setWindowTitle(tr("Error receiving resolutions"));
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>SDL_GetDisplayMode failed:</b><br><br>") + QString::fromUtf8(SDL_GetError()) + "<br>");
|
||||
msgBox.setText(
|
||||
tr("<br><b>SDL_GetDisplayMode failed:</b><br><br>") + QString::fromUtf8(SDL_GetError()) + "<br>");
|
||||
msgBox.exec();
|
||||
return result;
|
||||
}
|
||||
@ -322,10 +332,12 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
|
||||
QString resolution = QString::number(mode.w) + QString(" x ") + QString::number(mode.h);
|
||||
|
||||
QString aspect = getAspect(mode.w, mode.h);
|
||||
if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) {
|
||||
if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10"))
|
||||
{
|
||||
resolution.append(tr("\t(Wide ") + aspect + ")");
|
||||
|
||||
} else if (aspect == QLatin1String("4:3")) {
|
||||
}
|
||||
else if (aspect == QLatin1String("4:3"))
|
||||
{
|
||||
resolution.append(tr("\t(Standard 4:3)"));
|
||||
}
|
||||
|
||||
@ -353,7 +365,8 @@ QRect Launcher::GraphicsPage::getMaximumResolution()
|
||||
|
||||
void Launcher::GraphicsPage::screenChanged(int screen)
|
||||
{
|
||||
if (screen >= 0) {
|
||||
if (screen >= 0)
|
||||
{
|
||||
resolutionComboBox->clear();
|
||||
resolutionComboBox->addItems(mResolutionsPerScreen[screen]);
|
||||
}
|
||||
@ -361,13 +374,17 @@ void Launcher::GraphicsPage::screenChanged(int screen)
|
||||
|
||||
void Launcher::GraphicsPage::slotFullScreenChanged(int mode)
|
||||
{
|
||||
if (mode == static_cast<int>(Settings::WindowMode::Fullscreen) || mode == static_cast<int>(Settings::WindowMode::WindowedFullscreen)) {
|
||||
if (mode == static_cast<int>(Settings::WindowMode::Fullscreen)
|
||||
|| mode == static_cast<int>(Settings::WindowMode::WindowedFullscreen))
|
||||
{
|
||||
standardRadioButton->toggle();
|
||||
customRadioButton->setEnabled(false);
|
||||
customWidthSpinBox->setEnabled(false);
|
||||
customHeightSpinBox->setEnabled(false);
|
||||
windowBorderCheckBox->setEnabled(false);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
customRadioButton->setEnabled(true);
|
||||
customWidthSpinBox->setEnabled(true);
|
||||
customHeightSpinBox->setEnabled(true);
|
||||
@ -377,11 +394,14 @@ void Launcher::GraphicsPage::slotFullScreenChanged(int mode)
|
||||
|
||||
void Launcher::GraphicsPage::slotStandardToggled(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
if (checked)
|
||||
{
|
||||
resolutionComboBox->setEnabled(true);
|
||||
customWidthSpinBox->setEnabled(false);
|
||||
customHeightSpinBox->setEnabled(false);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
resolutionComboBox->setEnabled(false);
|
||||
customWidthSpinBox->setEnabled(true);
|
||||
customHeightSpinBox->setEnabled(true);
|
||||
|
@ -5,7 +5,10 @@
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
namespace Files { struct ConfigurationManager; }
|
||||
namespace Files
|
||||
{
|
||||
struct ConfigurationManager;
|
||||
}
|
||||
|
||||
namespace Launcher
|
||||
{
|
||||
@ -16,7 +19,7 @@ namespace Launcher
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GraphicsPage(QWidget *parent = nullptr);
|
||||
explicit GraphicsPage(QWidget* parent = nullptr);
|
||||
|
||||
void saveSettings();
|
||||
bool loadSettings();
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <QTranslator>
|
||||
#include <QDir>
|
||||
#include <QTranslator>
|
||||
|
||||
#include <components/debug/debugging.hpp>
|
||||
#include <components/platform/platform.hpp>
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
#include "maindialog.hpp"
|
||||
|
||||
int runLauncher(int argc, char *argv[])
|
||||
int runLauncher(int argc, char* argv[])
|
||||
{
|
||||
Platform::init();
|
||||
|
||||
@ -22,7 +22,7 @@ int runLauncher(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// Internationalization
|
||||
// Internationalization
|
||||
QString locale = QLocale::system().name().section('_', 0, 0);
|
||||
|
||||
QTranslator appTranslator;
|
||||
@ -54,7 +54,7 @@ int runLauncher(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
return wrapApplication(runLauncher, argc, argv, "Launcher");
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
#include "maindialog.hpp"
|
||||
|
||||
#include <components/version/version.hpp>
|
||||
#include <components/misc/helpviewer.hpp>
|
||||
#include <components/version/version.hpp>
|
||||
|
||||
#include <QTime>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QMessageBox>
|
||||
#include <QCloseEvent>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QTextCodec>
|
||||
#include <QTime>
|
||||
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
@ -23,7 +23,8 @@
|
||||
|
||||
using namespace Process;
|
||||
|
||||
void cfgError(const QString& title, const QString& msg) {
|
||||
void cfgError(const QString& title, const QString& msg)
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(title);
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
@ -32,19 +33,19 @@ void cfgError(const QString& title, const QString& msg) {
|
||||
msgBox.exec();
|
||||
}
|
||||
|
||||
Launcher::MainDialog::MainDialog(QWidget *parent)
|
||||
: QMainWindow(parent), mGameSettings (mCfgMgr)
|
||||
Launcher::MainDialog::MainDialog(QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
, mGameSettings(mCfgMgr)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
mGameInvoker = new ProcessInvoker();
|
||||
mWizardInvoker = new ProcessInvoker();
|
||||
|
||||
connect(mWizardInvoker->getProcess(), &QProcess::started,
|
||||
this, &MainDialog::wizardStarted);
|
||||
connect(mWizardInvoker->getProcess(), &QProcess::started, this, &MainDialog::wizardStarted);
|
||||
|
||||
connect(mWizardInvoker->getProcess(), qOverload<int,QProcess::ExitStatus>(&QProcess::finished),
|
||||
this, &MainDialog::wizardFinished);
|
||||
connect(mWizardInvoker->getProcess(), qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
|
||||
&MainDialog::wizardFinished);
|
||||
|
||||
iconWidget->setViewMode(QListView::IconMode);
|
||||
iconWidget->setWrapping(false);
|
||||
@ -56,8 +57,8 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
|
||||
iconWidget->setCurrentRow(0);
|
||||
iconWidget->setFlow(QListView::LeftToRight);
|
||||
|
||||
auto *helpButton = new QPushButton(tr("Help"));
|
||||
auto *playButton = new QPushButton(tr("Play"));
|
||||
auto* helpButton = new QPushButton(tr("Help"));
|
||||
auto* playButton = new QPushButton(tr("Play"));
|
||||
buttonBox->button(QDialogButtonBox::Close)->setText(tr("Close"));
|
||||
buttonBox->addButton(helpButton, QDialogButtonBox::HelpRole);
|
||||
buttonBox->addButton(playButton, QDialogButtonBox::AcceptRole);
|
||||
@ -83,38 +84,37 @@ void Launcher::MainDialog::createIcons()
|
||||
if (!QIcon::hasThemeIcon("document-new"))
|
||||
QIcon::setThemeName("tango");
|
||||
|
||||
auto *playButton = new QListWidgetItem(iconWidget);
|
||||
auto* playButton = new QListWidgetItem(iconWidget);
|
||||
playButton->setIcon(QIcon(":/images/openmw.png"));
|
||||
playButton->setText(tr("Play"));
|
||||
playButton->setTextAlignment(Qt::AlignCenter);
|
||||
playButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||
|
||||
auto *dataFilesButton = new QListWidgetItem(iconWidget);
|
||||
auto* dataFilesButton = new QListWidgetItem(iconWidget);
|
||||
dataFilesButton->setIcon(QIcon(":/images/openmw-plugin.png"));
|
||||
dataFilesButton->setText(tr("Data Files"));
|
||||
dataFilesButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
||||
dataFilesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||
|
||||
auto *graphicsButton = new QListWidgetItem(iconWidget);
|
||||
auto* graphicsButton = new QListWidgetItem(iconWidget);
|
||||
graphicsButton->setIcon(QIcon(":/images/preferences-video.png"));
|
||||
graphicsButton->setText(tr("Graphics"));
|
||||
graphicsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom | Qt::AlignAbsolute);
|
||||
graphicsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||
|
||||
auto *settingsButton = new QListWidgetItem(iconWidget);
|
||||
auto* settingsButton = new QListWidgetItem(iconWidget);
|
||||
settingsButton->setIcon(QIcon(":/images/preferences.png"));
|
||||
settingsButton->setText(tr("Settings"));
|
||||
settingsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
||||
settingsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||
|
||||
auto *advancedButton = new QListWidgetItem(iconWidget);
|
||||
auto* advancedButton = new QListWidgetItem(iconWidget);
|
||||
advancedButton->setIcon(QIcon(":/images/preferences-advanced.png"));
|
||||
advancedButton->setText(tr("Advanced"));
|
||||
advancedButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
||||
advancedButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||
|
||||
connect(iconWidget, &QListWidget::currentItemChanged, this, &MainDialog::changePage);
|
||||
|
||||
}
|
||||
|
||||
void Launcher::MainDialog::createPages()
|
||||
@ -148,7 +148,8 @@ void Launcher::MainDialog::createPages()
|
||||
connect(mPlayPage, &PlayPage::signalProfileChanged, mDataFilesPage, &DataFilesPage::slotProfileChanged);
|
||||
connect(mDataFilesPage, &DataFilesPage::signalProfileChanged, mPlayPage, &PlayPage::setProfilesIndex);
|
||||
// Using Qt::QueuedConnection because signal is emitted in a subthread and slot is in the main thread
|
||||
connect(mDataFilesPage, &DataFilesPage::signalLoadedCellsChanged, mAdvancedPage, &AdvancedPage::slotLoadedCellsChanged, Qt::QueuedConnection);
|
||||
connect(mDataFilesPage, &DataFilesPage::signalLoadedCellsChanged, mAdvancedPage,
|
||||
&AdvancedPage::slotLoadedCellsChanged, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
||||
@ -158,14 +159,15 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
||||
|
||||
// Dialog wizard and setup will fail if the config directory does not already exist
|
||||
const auto& userConfigDir = mCfgMgr.getUserConfigPath();
|
||||
if ( ! exists(userConfigDir) ) {
|
||||
if ( ! create_directories(userConfigDir) )
|
||||
if (!exists(userConfigDir))
|
||||
{
|
||||
if (!create_directories(userConfigDir))
|
||||
{
|
||||
cfgError(tr("Error opening OpenMW configuration file"),
|
||||
tr("<br><b>Could not create directory %0</b><br><br> \
|
||||
tr("<br><b>Could not create directory %0</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>").arg(Files::pathToQString(canonical(userConfigDir)))
|
||||
);
|
||||
and try again.<br>")
|
||||
.arg(Files::pathToQString(canonical(userConfigDir))));
|
||||
return FirstRunDialogResultFailure;
|
||||
}
|
||||
}
|
||||
@ -176,15 +178,15 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
||||
msgBox.setWindowTitle(tr("First run"));
|
||||
msgBox.setIcon(QMessageBox::Question);
|
||||
msgBox.setStandardButtons(QMessageBox::NoButton);
|
||||
msgBox.setText(tr("<html><head/><body><p><b>Welcome to OpenMW!</b></p> \
|
||||
msgBox.setText(
|
||||
tr("<html><head/><body><p><b>Welcome to OpenMW!</b></p> \
|
||||
<p>It is recommended to run the Installation Wizard.</p> \
|
||||
<p>The Wizard will let you select an existing Morrowind installation, \
|
||||
or install Morrowind for OpenMW to use.</p></body></html>"));
|
||||
|
||||
QAbstractButton *wizardButton =
|
||||
msgBox.addButton(tr("Run &Installation Wizard"), QMessageBox::AcceptRole); // ActionRole doesn't work?!
|
||||
QAbstractButton *skipButton =
|
||||
msgBox.addButton(tr("Skip"), QMessageBox::RejectRole);
|
||||
QAbstractButton* wizardButton
|
||||
= msgBox.addButton(tr("Run &Installation Wizard"), QMessageBox::AcceptRole); // ActionRole doesn't work?!
|
||||
QAbstractButton* skipButton = msgBox.addButton(tr("Skip"), QMessageBox::RejectRole);
|
||||
|
||||
msgBox.exec();
|
||||
|
||||
@ -202,7 +204,8 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
||||
return FirstRunDialogResultFailure;
|
||||
}
|
||||
|
||||
if (!setup() || !setupGameData()) {
|
||||
if (!setup() || !setupGameData())
|
||||
{
|
||||
return FirstRunDialogResultFailure;
|
||||
}
|
||||
return FirstRunDialogResultContinue;
|
||||
@ -225,8 +228,9 @@ void Launcher::MainDialog::setVersionLabel()
|
||||
// Add the compile date and time
|
||||
auto compileDate = QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), QLatin1String("MMM d yyyy"));
|
||||
auto compileTime = QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), QLatin1String("hh:mm:ss"));
|
||||
versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale::system().toString(compileDate, QLocale::LongFormat),
|
||||
QLocale::system().toString(compileTime, QLocale::ShortFormat)));
|
||||
versionLabel->setToolTip(tr("Compiled on %1 %2")
|
||||
.arg(QLocale::system().toString(compileDate, QLocale::LongFormat),
|
||||
QLocale::system().toString(compileTime, QLocale::ShortFormat)));
|
||||
}
|
||||
|
||||
bool Launcher::MainDialog::setup()
|
||||
@ -281,7 +285,7 @@ bool Launcher::MainDialog::reloadSettings()
|
||||
return true;
|
||||
}
|
||||
|
||||
void Launcher::MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
|
||||
void Launcher::MainDialog::changePage(QListWidgetItem* current, QListWidgetItem* previous)
|
||||
{
|
||||
if (!current)
|
||||
current = previous;
|
||||
@ -303,16 +307,19 @@ bool Launcher::MainDialog::setupLauncherSettings()
|
||||
paths.append(QString(Config::LauncherSettings::sLauncherConfigFileName));
|
||||
paths.append(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName));
|
||||
|
||||
for (const QString &path : paths)
|
||||
for (const QString& path : paths)
|
||||
{
|
||||
qDebug() << "Loading config file:" << path.toUtf8().constData();
|
||||
QFile file(path);
|
||||
if (file.exists()) {
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
if (file.exists())
|
||||
{
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
cfgError(tr("Error opening OpenMW configuration file"),
|
||||
tr("<br><b>Could not open %0 for reading</b><br><br> \
|
||||
tr("<br><b>Could not open %0 for reading</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>").arg(file.fileName()));
|
||||
and try again.<br>")
|
||||
.arg(file.fileName()));
|
||||
return false;
|
||||
}
|
||||
QTextStream stream(&file);
|
||||
@ -336,16 +343,19 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||
|
||||
QFile file;
|
||||
|
||||
auto loadFile = [&] (const QString& path, bool(Config::GameSettings::*reader)(QTextStream&, bool), bool ignoreContent = false) -> std::optional<bool>
|
||||
{
|
||||
auto loadFile = [&](const QString& path, bool (Config::GameSettings::*reader)(QTextStream&, bool),
|
||||
bool ignoreContent = false) -> std::optional<bool> {
|
||||
qDebug() << "Loading config file:" << path.toUtf8().constData();
|
||||
file.setFileName(path);
|
||||
if (file.exists()) {
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
if (file.exists())
|
||||
{
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
cfgError(tr("Error opening OpenMW configuration file"),
|
||||
tr("<br><b>Could not open %0 for reading</b><br><br> \
|
||||
tr("<br><b>Could not open %0 for reading</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>").arg(file.fileName()));
|
||||
and try again.<br>")
|
||||
.arg(file.fileName()));
|
||||
return {};
|
||||
}
|
||||
QTextStream stream(&file);
|
||||
@ -360,19 +370,19 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||
|
||||
// Load the user config file first, separately
|
||||
// So we can write it properly, uncontaminated
|
||||
if(!loadFile(userPath + QLatin1String("openmw.cfg"), &Config::GameSettings::readUserFile))
|
||||
if (!loadFile(userPath + QLatin1String("openmw.cfg"), &Config::GameSettings::readUserFile))
|
||||
return false;
|
||||
|
||||
// Now the rest - priority: user > local > global
|
||||
if(auto result = loadFile(localPath + QString("openmw.cfg"), &Config::GameSettings::readFile, true))
|
||||
if (auto result = loadFile(localPath + QString("openmw.cfg"), &Config::GameSettings::readFile, true))
|
||||
{
|
||||
// Load global if local wasn't found
|
||||
if(!*result && !loadFile(globalPath + QString("openmw.cfg"), &Config::GameSettings::readFile, true))
|
||||
if (!*result && !loadFile(globalPath + QString("openmw.cfg"), &Config::GameSettings::readFile, true))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
if(!loadFile(userPath + QString("openmw.cfg"), &Config::GameSettings::readFile))
|
||||
if (!loadFile(userPath + QString("openmw.cfg"), &Config::GameSettings::readFile))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -387,7 +397,10 @@ bool Launcher::MainDialog::setupGameData()
|
||||
{
|
||||
QDir dir(path3);
|
||||
QStringList filters;
|
||||
filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon";
|
||||
filters << "*.esp"
|
||||
<< "*.esm"
|
||||
<< "*.omwgame"
|
||||
<< "*.omwaddon";
|
||||
|
||||
if (!dir.entryList(filters).isEmpty())
|
||||
dataDirs.append(path3);
|
||||
@ -399,13 +412,12 @@ bool Launcher::MainDialog::setupGameData()
|
||||
msgBox.setWindowTitle(tr("Error detecting Morrowind installation"));
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.setStandardButtons(QMessageBox::NoButton);
|
||||
msgBox.setText(tr("<br><b>Could not find the Data Files location</b><br><br> \
|
||||
msgBox.setText(
|
||||
tr("<br><b>Could not find the Data Files location</b><br><br> \
|
||||
The directory containing the data files was not found."));
|
||||
|
||||
QAbstractButton *wizardButton =
|
||||
msgBox.addButton(tr("Run &Installation Wizard..."), QMessageBox::ActionRole);
|
||||
QAbstractButton *skipButton =
|
||||
msgBox.addButton(tr("Skip"), QMessageBox::RejectRole);
|
||||
QAbstractButton* wizardButton = msgBox.addButton(tr("Run &Installation Wizard..."), QMessageBox::ActionRole);
|
||||
QAbstractButton* skipButton = msgBox.addButton(tr("Skip"), QMessageBox::RejectRole);
|
||||
|
||||
Q_UNUSED(skipButton); // Suppress compiler unused warning
|
||||
|
||||
@ -423,7 +435,7 @@ bool Launcher::MainDialog::setupGameData()
|
||||
|
||||
bool Launcher::MainDialog::setupGraphicsSettings()
|
||||
{
|
||||
Settings::Manager::clear(); // Ensure to clear previous settings in case we had already loaded settings.
|
||||
Settings::Manager::clear(); // Ensure to clear previous settings in case we had already loaded settings.
|
||||
try
|
||||
{
|
||||
boost::program_options::variables_map variables;
|
||||
@ -436,8 +448,9 @@ bool Launcher::MainDialog::setupGraphicsSettings()
|
||||
catch (std::exception& e)
|
||||
{
|
||||
cfgError(tr("Error reading OpenMW configuration files"),
|
||||
tr("<br>The problem may be due to an incomplete installation of OpenMW.<br> \
|
||||
Reinstalling OpenMW may resolve the problem.<br>") + e.what());
|
||||
tr("<br>The problem may be due to an incomplete installation of OpenMW.<br> \
|
||||
Reinstalling OpenMW may resolve the problem.<br>")
|
||||
+ e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -469,7 +482,6 @@ void Launcher::MainDialog::saveSettings()
|
||||
mLauncherSettings.setValue(QString("General/MainWindow/posy"), posY);
|
||||
|
||||
mLauncherSettings.setValue(QString("General/firstrun"), QString("false"));
|
||||
|
||||
}
|
||||
|
||||
bool Launcher::MainDialog::writeSettings()
|
||||
@ -483,12 +495,15 @@ bool Launcher::MainDialog::writeSettings()
|
||||
|
||||
const auto& userPath = mCfgMgr.getUserConfigPath();
|
||||
|
||||
if (!exists(userPath)) {
|
||||
if (!create_directories(userPath)) {
|
||||
if (!exists(userPath))
|
||||
{
|
||||
if (!create_directories(userPath))
|
||||
{
|
||||
cfgError(tr("Error creating OpenMW configuration directory"),
|
||||
tr("<br><b>Could not create %0</b><br><br> \
|
||||
tr("<br><b>Could not create %0</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>").arg(Files::pathToQString(userPath)));
|
||||
and try again.<br>")
|
||||
.arg(Files::pathToQString(userPath)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -500,27 +515,30 @@ bool Launcher::MainDialog::writeSettings()
|
||||
QFile file(Files::pathToQString(userPath / "openmw.cfg"));
|
||||
#endif
|
||||
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Text))
|
||||
{
|
||||
// File cannot be opened or created
|
||||
cfgError(tr("Error writing OpenMW configuration file"),
|
||||
tr("<br><b>Could not open or create %0 for writing</b><br><br> \
|
||||
tr("<br><b>Could not open or create %0 for writing</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>").arg(file.fileName()));
|
||||
and try again.<br>")
|
||||
.arg(file.fileName()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
mGameSettings.writeFileWithComments(file);
|
||||
file.close();
|
||||
|
||||
// Graphics settings
|
||||
const auto settingsPath = mCfgMgr.getUserConfigPath() / "settings.cfg";
|
||||
try {
|
||||
try
|
||||
{
|
||||
Settings::Manager::saveUser(settingsPath);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
std::string msg = "<br><b>Error writing settings.cfg</b><br><br>" +
|
||||
Files::pathToUnicodeString(settingsPath) + "<br><br>" + e.what();
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::string msg = "<br><b>Error writing settings.cfg</b><br><br>" + Files::pathToUnicodeString(settingsPath)
|
||||
+ "<br><br>" + e.what();
|
||||
cfgError(tr("Error writing user settings file"), tr(msg.c_str()));
|
||||
return false;
|
||||
}
|
||||
@ -528,12 +546,14 @@ bool Launcher::MainDialog::writeSettings()
|
||||
// Launcher settings
|
||||
file.setFileName(Files::pathToQString(userPath / Config::LauncherSettings::sLauncherConfigFileName));
|
||||
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate))
|
||||
{
|
||||
// File cannot be opened or created
|
||||
cfgError(tr("Error writing Launcher configuration file"),
|
||||
tr("<br><b>Could not open or create %0 for writing</b><br><br> \
|
||||
tr("<br><b>Could not open or create %0 for writing</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>").arg(file.fileName()));
|
||||
and try again.<br>")
|
||||
.arg(file.fileName()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -547,7 +567,7 @@ bool Launcher::MainDialog::writeSettings()
|
||||
return true;
|
||||
}
|
||||
|
||||
void Launcher::MainDialog::closeEvent(QCloseEvent *event)
|
||||
void Launcher::MainDialog::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
writeSettings();
|
||||
event->accept();
|
||||
@ -575,12 +595,14 @@ void Launcher::MainDialog::play()
|
||||
if (!writeSettings())
|
||||
return qApp->quit();
|
||||
|
||||
if (!mGameSettings.hasMaster()) {
|
||||
if (!mGameSettings.hasMaster())
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(tr("No game file selected"));
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>You do not have a game file selected.</b><br><br> \
|
||||
msgBox.setText(
|
||||
tr("<br><b>You do not have a game file selected.</b><br><br> \
|
||||
OpenMW will not start without a game file selected.<br>"));
|
||||
msgBox.exec();
|
||||
return;
|
||||
|
@ -1,7 +1,6 @@
|
||||
#ifndef MAINDIALOG_H
|
||||
#define MAINDIALOG_H
|
||||
|
||||
|
||||
#ifndef Q_MOC_RUN
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
@ -44,7 +43,7 @@ namespace Launcher
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainDialog(QWidget *parent = nullptr);
|
||||
explicit MainDialog(QWidget* parent = nullptr);
|
||||
~MainDialog() override;
|
||||
|
||||
FirstRunDialogResult showFirstRunDialog();
|
||||
@ -53,7 +52,7 @@ namespace Launcher
|
||||
bool writeSettings();
|
||||
|
||||
public slots:
|
||||
void changePage(QListWidgetItem *current, QListWidgetItem *previous);
|
||||
void changePage(QListWidgetItem* current, QListWidgetItem* previous);
|
||||
void play();
|
||||
void help();
|
||||
|
||||
@ -77,25 +76,27 @@ namespace Launcher
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
inline bool startProgram(const QString &name, bool detached = false) { return startProgram(name, QStringList(), detached); }
|
||||
bool startProgram(const QString &name, const QStringList &arguments, bool detached = false);
|
||||
inline bool startProgram(const QString& name, bool detached = false)
|
||||
{
|
||||
return startProgram(name, QStringList(), detached);
|
||||
}
|
||||
bool startProgram(const QString& name, const QStringList& arguments, bool detached = false);
|
||||
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
|
||||
PlayPage *mPlayPage;
|
||||
GraphicsPage *mGraphicsPage;
|
||||
DataFilesPage *mDataFilesPage;
|
||||
SettingsPage *mSettingsPage;
|
||||
AdvancedPage *mAdvancedPage;
|
||||
PlayPage* mPlayPage;
|
||||
GraphicsPage* mGraphicsPage;
|
||||
DataFilesPage* mDataFilesPage;
|
||||
SettingsPage* mSettingsPage;
|
||||
AdvancedPage* mAdvancedPage;
|
||||
|
||||
Process::ProcessInvoker *mGameInvoker;
|
||||
Process::ProcessInvoker *mWizardInvoker;
|
||||
Process::ProcessInvoker* mGameInvoker;
|
||||
Process::ProcessInvoker* mWizardInvoker;
|
||||
|
||||
Files::ConfigurationManager mCfgMgr;
|
||||
|
||||
Config::GameSettings mGameSettings;
|
||||
Config::LauncherSettings mLauncherSettings;
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -2,19 +2,19 @@
|
||||
|
||||
#include <QListView>
|
||||
|
||||
Launcher::PlayPage::PlayPage(QWidget *parent) : QWidget(parent)
|
||||
Launcher::PlayPage::PlayPage(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setObjectName ("PlayPage");
|
||||
setObjectName("PlayPage");
|
||||
setupUi(this);
|
||||
|
||||
profilesComboBox->setView(new QListView());
|
||||
|
||||
connect(profilesComboBox, qOverload<int>(&QComboBox::activated), this, &PlayPage::signalProfileChanged);
|
||||
connect(playButton, &QPushButton::clicked, this, &PlayPage::slotPlayClicked);
|
||||
|
||||
}
|
||||
|
||||
void Launcher::PlayPage::setProfilesModel(QAbstractItemModel *model)
|
||||
void Launcher::PlayPage::setProfilesModel(QAbstractItemModel* model)
|
||||
{
|
||||
profilesComboBox->setModel(model);
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ namespace Launcher
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PlayPage(QWidget *parent = nullptr);
|
||||
void setProfilesModel(QAbstractItemModel *model);
|
||||
PlayPage(QWidget* parent = nullptr);
|
||||
void setProfilesModel(QAbstractItemModel* model);
|
||||
|
||||
signals:
|
||||
void signalProfileChanged(int index);
|
||||
@ -26,9 +26,6 @@ namespace Launcher
|
||||
|
||||
private slots:
|
||||
void slotPlayClicked();
|
||||
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -1,21 +1,20 @@
|
||||
#include "settingspage.hpp"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <components/files/conversion.hpp>
|
||||
#include <components/files/qtconversion.hpp>
|
||||
|
||||
#include "utils/textinputdialog.hpp"
|
||||
#include "datafilespage.hpp"
|
||||
#include "utils/textinputdialog.hpp"
|
||||
|
||||
using namespace Process;
|
||||
|
||||
Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg,
|
||||
Config::GameSettings &gameSettings,
|
||||
Config::LauncherSettings &launcherSettings, MainDialog *parent)
|
||||
Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager& cfg, Config::GameSettings& gameSettings,
|
||||
Config::LauncherSettings& launcherSettings, MainDialog* parent)
|
||||
: QWidget(parent)
|
||||
, mCfgMgr(cfg)
|
||||
, mGameSettings(gameSettings)
|
||||
@ -25,12 +24,7 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg,
|
||||
setupUi(this);
|
||||
|
||||
QStringList languages;
|
||||
languages << tr("English")
|
||||
<< tr("French")
|
||||
<< tr("German")
|
||||
<< tr("Italian")
|
||||
<< tr("Polish")
|
||||
<< tr("Russian")
|
||||
languages << tr("English") << tr("French") << tr("German") << tr("Italian") << tr("Polish") << tr("Russian")
|
||||
<< tr("Spanish");
|
||||
|
||||
languageComboBox->addItems(languages);
|
||||
@ -39,27 +33,24 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg,
|
||||
mImporterInvoker = new ProcessInvoker();
|
||||
resetProgressBar();
|
||||
|
||||
connect(mWizardInvoker->getProcess(), &QProcess::started,
|
||||
this, &SettingsPage::wizardStarted);
|
||||
connect(mWizardInvoker->getProcess(), &QProcess::started, this, &SettingsPage::wizardStarted);
|
||||
|
||||
connect(mWizardInvoker->getProcess(), qOverload<int,QProcess::ExitStatus>(&QProcess::finished),
|
||||
this, &SettingsPage::wizardFinished);
|
||||
connect(mWizardInvoker->getProcess(), qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
|
||||
&SettingsPage::wizardFinished);
|
||||
|
||||
connect(mImporterInvoker->getProcess(), &QProcess::started,
|
||||
this, &SettingsPage::importerStarted);
|
||||
connect(mImporterInvoker->getProcess(), &QProcess::started, this, &SettingsPage::importerStarted);
|
||||
|
||||
connect(mImporterInvoker->getProcess(), qOverload<int,QProcess::ExitStatus>(&QProcess::finished),
|
||||
this, &SettingsPage::importerFinished);
|
||||
connect(mImporterInvoker->getProcess(), qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
|
||||
&SettingsPage::importerFinished);
|
||||
|
||||
mProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this);
|
||||
|
||||
connect(mProfileDialog->lineEdit(), &LineEdit::textChanged,
|
||||
this, &SettingsPage::updateOkButton);
|
||||
connect(mProfileDialog->lineEdit(), &LineEdit::textChanged, this, &SettingsPage::updateOkButton);
|
||||
|
||||
// Detect Morrowind configuration files
|
||||
QStringList iniPaths;
|
||||
|
||||
for (const QString &path : mGameSettings.getDataDirs())
|
||||
for (const QString& path : mGameSettings.getDataDirs())
|
||||
{
|
||||
QDir dir(path);
|
||||
dir.setPath(dir.canonicalPath()); // Resolve symlinks
|
||||
@ -76,10 +67,13 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg,
|
||||
}
|
||||
}
|
||||
|
||||
if (!iniPaths.isEmpty()) {
|
||||
if (!iniPaths.isEmpty())
|
||||
{
|
||||
settingsComboBox->addItems(iniPaths);
|
||||
importerButton->setEnabled(true);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
importerButton->setEnabled(false);
|
||||
}
|
||||
|
||||
@ -113,16 +107,20 @@ void Launcher::SettingsPage::on_importerButton_clicked()
|
||||
QFile file(Files::pathToQString(path));
|
||||
#endif
|
||||
|
||||
if (!file.exists()) {
|
||||
if (!file.open(QIODevice::ReadWrite)) {
|
||||
if (!file.exists())
|
||||
{
|
||||
if (!file.open(QIODevice::ReadWrite))
|
||||
{
|
||||
// File cannot be created
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<html><head/><body><p><b>Could not open or create %1 for writing </b></p> \
|
||||
msgBox.setText(
|
||||
tr("<html><head/><body><p><b>Could not open or create %1 for writing </b></p> \
|
||||
<p>Please make sure you have the right permissions \
|
||||
and try again.</p></body></html>").arg(file.fileName()));
|
||||
and try again.</p></body></html>")
|
||||
.arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
return;
|
||||
}
|
||||
@ -159,12 +157,8 @@ void Launcher::SettingsPage::on_importerButton_clicked()
|
||||
|
||||
void Launcher::SettingsPage::on_browseButton_clicked()
|
||||
{
|
||||
QString iniFile = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
QObject::tr("Select configuration file"),
|
||||
QDir::currentPath(),
|
||||
QString(tr("Morrowind configuration file (*.ini)")));
|
||||
|
||||
QString iniFile = QFileDialog::getOpenFileName(this, QObject::tr("Select configuration file"), QDir::currentPath(),
|
||||
QString(tr("Morrowind configuration file (*.ini)")));
|
||||
|
||||
if (iniFile.isEmpty())
|
||||
return;
|
||||
@ -176,7 +170,8 @@ void Launcher::SettingsPage::on_browseButton_clicked()
|
||||
|
||||
const QString path(QDir::toNativeSeparators(info.absoluteFilePath()));
|
||||
|
||||
if (settingsComboBox->findText(path) == -1) {
|
||||
if (settingsComboBox->findText(path) == -1)
|
||||
{
|
||||
settingsComboBox->addItem(path);
|
||||
settingsComboBox->setCurrentIndex(settingsComboBox->findText(path));
|
||||
importerButton->setEnabled(true);
|
||||
@ -238,19 +233,18 @@ void Launcher::SettingsPage::resetProgressBar()
|
||||
progressBar->reset();
|
||||
}
|
||||
|
||||
void Launcher::SettingsPage::updateOkButton(const QString &text)
|
||||
void Launcher::SettingsPage::updateOkButton(const QString& text)
|
||||
{
|
||||
// We do this here because we need to access the profiles
|
||||
if (text.isEmpty()) {
|
||||
mProfileDialog->setOkButtonEnabled(false);
|
||||
return;
|
||||
if (text.isEmpty())
|
||||
{
|
||||
mProfileDialog->setOkButtonEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const QStringList profiles(mLauncherSettings.getContentLists());
|
||||
|
||||
(profiles.contains(text))
|
||||
? mProfileDialog->setOkButtonEnabled(false)
|
||||
: mProfileDialog->setOkButtonEnabled(true);
|
||||
(profiles.contains(text)) ? mProfileDialog->setOkButtonEnabled(false) : mProfileDialog->setOkButtonEnabled(true);
|
||||
}
|
||||
|
||||
void Launcher::SettingsPage::saveSettings()
|
||||
@ -259,11 +253,16 @@ void Launcher::SettingsPage::saveSettings()
|
||||
|
||||
mLauncherSettings.setValue(QLatin1String("Settings/language"), language);
|
||||
|
||||
if (language == QLatin1String("Polish")) {
|
||||
if (language == QLatin1String("Polish"))
|
||||
{
|
||||
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1250"));
|
||||
} else if (language == QLatin1String("Russian")) {
|
||||
}
|
||||
else if (language == QLatin1String("Russian"))
|
||||
{
|
||||
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1251"));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252"));
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,15 @@
|
||||
|
||||
#include "maindialog.hpp"
|
||||
|
||||
namespace Files { struct ConfigurationManager; }
|
||||
namespace Config { class GameSettings;
|
||||
class LauncherSettings; }
|
||||
namespace Files
|
||||
{
|
||||
struct ConfigurationManager;
|
||||
}
|
||||
namespace Config
|
||||
{
|
||||
class GameSettings;
|
||||
class LauncherSettings;
|
||||
}
|
||||
|
||||
namespace Launcher
|
||||
{
|
||||
@ -20,13 +26,13 @@ namespace Launcher
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SettingsPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings,
|
||||
Config::LauncherSettings &launcherSettings, MainDialog *parent = nullptr);
|
||||
SettingsPage(Files::ConfigurationManager& cfg, Config::GameSettings& gameSettings,
|
||||
Config::LauncherSettings& launcherSettings, MainDialog* parent = nullptr);
|
||||
~SettingsPage() override;
|
||||
|
||||
void saveSettings();
|
||||
bool loadSettings();
|
||||
|
||||
|
||||
/// set progress bar on page to 0%
|
||||
void resetProgressBar();
|
||||
|
||||
@ -42,21 +48,19 @@ namespace Launcher
|
||||
void importerStarted();
|
||||
void importerFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
||||
void updateOkButton(const QString &text);
|
||||
void updateOkButton(const QString& text);
|
||||
|
||||
private:
|
||||
Process::ProcessInvoker* mWizardInvoker;
|
||||
Process::ProcessInvoker* mImporterInvoker;
|
||||
|
||||
Process::ProcessInvoker *mWizardInvoker;
|
||||
Process::ProcessInvoker *mImporterInvoker;
|
||||
Files::ConfigurationManager& mCfgMgr;
|
||||
|
||||
Files::ConfigurationManager &mCfgMgr;
|
||||
|
||||
Config::GameSettings &mGameSettings;
|
||||
Config::LauncherSettings &mLauncherSettings;
|
||||
|
||||
MainDialog *mMain;
|
||||
TextInputDialog *mProfileDialog;
|
||||
Config::GameSettings& mGameSettings;
|
||||
Config::LauncherSettings& mLauncherSettings;
|
||||
|
||||
MainDialog* mMain;
|
||||
TextInputDialog* mProfileDialog;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -7,9 +7,9 @@ namespace Launcher
|
||||
{
|
||||
class TextSlotMsgBox : public QMessageBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
void setTextSlot(const QString& string);
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
void setTextSlot(const QString& string);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -1,28 +1,31 @@
|
||||
#include "cellnameloader.hpp"
|
||||
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/contentselector/view/contentselector.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
|
||||
QSet<QString> CellNameLoader::getCellNames(QStringList &contentPaths)
|
||||
QSet<QString> CellNameLoader::getCellNames(QStringList& contentPaths)
|
||||
{
|
||||
QSet<QString> cellNames;
|
||||
ESM::ESMReader esmReader;
|
||||
|
||||
// Loop through all content files
|
||||
for (auto &contentPath : contentPaths) {
|
||||
for (auto& contentPath : contentPaths)
|
||||
{
|
||||
if (contentPath.endsWith(".omwscripts", Qt::CaseInsensitive))
|
||||
continue;
|
||||
esmReader.open(contentPath.toStdString());
|
||||
|
||||
// Loop through all records
|
||||
while(esmReader.hasMoreRecs())
|
||||
while (esmReader.hasMoreRecs())
|
||||
{
|
||||
ESM::NAME recordName = esmReader.getRecName();
|
||||
esmReader.getRecHeader();
|
||||
|
||||
if (isCellRecord(recordName)) {
|
||||
if (isCellRecord(recordName))
|
||||
{
|
||||
QString cellName = getCellName(esmReader);
|
||||
if (!cellName.isEmpty()) {
|
||||
if (!cellName.isEmpty())
|
||||
{
|
||||
cellNames.insert(cellName);
|
||||
}
|
||||
}
|
||||
@ -35,12 +38,12 @@ QSet<QString> CellNameLoader::getCellNames(QStringList &contentPaths)
|
||||
return cellNames;
|
||||
}
|
||||
|
||||
bool CellNameLoader::isCellRecord(ESM::NAME &recordName)
|
||||
bool CellNameLoader::isCellRecord(ESM::NAME& recordName)
|
||||
{
|
||||
return recordName.toInt() == ESM::REC_CELL;
|
||||
}
|
||||
|
||||
QString CellNameLoader::getCellName(ESM::ESMReader &esmReader)
|
||||
QString CellNameLoader::getCellName(ESM::ESMReader& esmReader)
|
||||
{
|
||||
ESM::Cell cell;
|
||||
bool isDeleted = false;
|
||||
@ -48,4 +51,3 @@ QString CellNameLoader::getCellName(ESM::ESMReader &esmReader)
|
||||
|
||||
return QString::fromStdString(cell.mName);
|
||||
}
|
||||
|
||||
|
@ -6,19 +6,26 @@
|
||||
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
|
||||
namespace ESM {class ESMReader; struct Cell;}
|
||||
namespace ContentSelectorView {class ContentSelector;}
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
struct Cell;
|
||||
}
|
||||
namespace ContentSelectorView
|
||||
{
|
||||
class ContentSelector;
|
||||
}
|
||||
|
||||
class CellNameLoader {
|
||||
class CellNameLoader
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Returns the names of all cells contained within the given content files
|
||||
* @param contentPaths the file paths of each content file to be examined
|
||||
* @return the names of all cells
|
||||
*/
|
||||
QSet<QString> getCellNames(QStringList &contentPaths);
|
||||
QSet<QString> getCellNames(QStringList& contentPaths);
|
||||
|
||||
private:
|
||||
/**
|
||||
@ -26,15 +33,14 @@ private:
|
||||
* @param name The name associated with the record
|
||||
* @return whether or not the given record is of type "Cell"
|
||||
*/
|
||||
bool isCellRecord(ESM::NAME &name);
|
||||
bool isCellRecord(ESM::NAME& name);
|
||||
|
||||
/**
|
||||
* Returns the name of the cell
|
||||
* @param esmReader the reader currently pointed to a loaded cell
|
||||
* @return the name of the cell
|
||||
*/
|
||||
QString getCellName(ESM::ESMReader &esmReader);
|
||||
QString getCellName(ESM::ESMReader& esmReader);
|
||||
};
|
||||
|
||||
|
||||
#endif //OPENMW_CELLNAMELOADER_H
|
||||
#endif // OPENMW_CELLNAMELOADER_H
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "lineedit.hpp"
|
||||
|
||||
LineEdit::LineEdit(QWidget *parent)
|
||||
LineEdit::LineEdit(QWidget* parent)
|
||||
: QLineEdit(parent)
|
||||
{
|
||||
setupClearButton();
|
||||
@ -19,12 +19,11 @@ void LineEdit::setupClearButton()
|
||||
connect(this, &LineEdit::textChanged, this, &LineEdit::updateClearButton);
|
||||
}
|
||||
|
||||
void LineEdit::resizeEvent(QResizeEvent *)
|
||||
void LineEdit::resizeEvent(QResizeEvent*)
|
||||
{
|
||||
QSize sz = mClearButton->sizeHint();
|
||||
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||
mClearButton->move(rect().right() - frameWidth - sz.width(),
|
||||
(rect().bottom() + 1 - sz.height())/2);
|
||||
mClearButton->move(rect().right() - frameWidth - sz.width(), (rect().bottom() + 1 - sz.height()) / 2);
|
||||
}
|
||||
|
||||
void LineEdit::updateClearButton(const QString& text)
|
||||
|
@ -23,19 +23,18 @@ class LineEdit : public QLineEdit
|
||||
QString mPlaceholderText;
|
||||
|
||||
public:
|
||||
LineEdit(QWidget *parent = nullptr);
|
||||
LineEdit(QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *) override;
|
||||
void resizeEvent(QResizeEvent*) override;
|
||||
|
||||
private slots:
|
||||
void updateClearButton(const QString &text);
|
||||
void updateClearButton(const QString& text);
|
||||
|
||||
protected:
|
||||
QToolButton *mClearButton;
|
||||
QToolButton* mClearButton;
|
||||
|
||||
void setupClearButton();
|
||||
};
|
||||
|
||||
#endif // LIENEDIT_H
|
||||
|
||||
|
@ -12,9 +12,9 @@
|
||||
std::vector<std::string> Launcher::enumerateOpenALDevices()
|
||||
{
|
||||
std::vector<std::string> devlist;
|
||||
const ALCchar *devnames;
|
||||
const ALCchar* devnames;
|
||||
|
||||
if(alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
|
||||
if (alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
|
||||
{
|
||||
devnames = alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
|
||||
}
|
||||
@ -23,10 +23,10 @@ std::vector<std::string> Launcher::enumerateOpenALDevices()
|
||||
devnames = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
|
||||
}
|
||||
|
||||
while(devnames && *devnames)
|
||||
while (devnames && *devnames)
|
||||
{
|
||||
devlist.emplace_back(devnames);
|
||||
devnames += strlen(devnames)+1;
|
||||
devnames += strlen(devnames) + 1;
|
||||
}
|
||||
return devlist;
|
||||
}
|
||||
@ -35,10 +35,10 @@ std::vector<std::string> Launcher::enumerateOpenALDevicesHrtf()
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
||||
ALCdevice *device = alcOpenDevice(nullptr);
|
||||
if(device)
|
||||
ALCdevice* device = alcOpenDevice(nullptr);
|
||||
if (device)
|
||||
{
|
||||
if(alcIsExtensionPresent(device, "ALC_SOFT_HRTF"))
|
||||
if (alcIsExtensionPresent(device, "ALC_SOFT_HRTF"))
|
||||
{
|
||||
LPALCGETSTRINGISOFT alcGetStringiSOFT = nullptr;
|
||||
void* funcPtr = alcGetProcAddress(device, "alcGetStringiSOFT");
|
||||
@ -46,10 +46,10 @@ std::vector<std::string> Launcher::enumerateOpenALDevicesHrtf()
|
||||
ALCint num_hrtf;
|
||||
alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf);
|
||||
ret.reserve(num_hrtf);
|
||||
for(ALCint i = 0;i < num_hrtf;++i)
|
||||
for (ALCint i = 0; i < num_hrtf; ++i)
|
||||
{
|
||||
const ALCchar *entry = alcGetStringiSOFT(device, ALC_HRTF_SPECIFIER_SOFT, i);
|
||||
if(strcmp(entry, "") == 0)
|
||||
const ALCchar* entry = alcGetStringiSOFT(device, ALC_HRTF_SPECIFIER_SOFT, i);
|
||||
if (strcmp(entry, "") == 0)
|
||||
break;
|
||||
ret.emplace_back(entry);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Launcher
|
||||
{
|
||||
|
@ -1,13 +1,12 @@
|
||||
#include <QString>
|
||||
#include <QApplication>
|
||||
#include <QString>
|
||||
|
||||
#include "profilescombobox.hpp"
|
||||
|
||||
ProfilesComboBox::ProfilesComboBox(QWidget *parent) :
|
||||
ContentSelectorView::ComboBox(parent)
|
||||
ProfilesComboBox::ProfilesComboBox(QWidget* parent)
|
||||
: ContentSelectorView::ComboBox(parent)
|
||||
{
|
||||
connect(this, qOverload<int>(&ProfilesComboBox::activated),
|
||||
this, &ProfilesComboBox::slotIndexChangedByUser);
|
||||
connect(this, qOverload<int>(&ProfilesComboBox::activated), this, &ProfilesComboBox::slotIndexChangedByUser);
|
||||
|
||||
setInsertPolicy(QComboBox::NoInsert);
|
||||
}
|
||||
@ -17,7 +16,8 @@ void ProfilesComboBox::setEditEnabled(bool editable)
|
||||
if (isEditable() == editable)
|
||||
return;
|
||||
|
||||
if (!editable) {
|
||||
if (!editable)
|
||||
{
|
||||
disconnect(lineEdit(), &QLineEdit::editingFinished, this, &ProfilesComboBox::slotEditingFinished);
|
||||
disconnect(lineEdit(), &QLineEdit::textChanged, this, &ProfilesComboBox::slotTextChanged);
|
||||
return setEditable(false);
|
||||
@ -27,7 +27,7 @@ void ProfilesComboBox::setEditEnabled(bool editable)
|
||||
setEditable(true);
|
||||
setValidator(mValidator);
|
||||
|
||||
auto *edit = new ComboBoxLineEdit(this);
|
||||
auto* edit = new ComboBoxLineEdit(this);
|
||||
|
||||
setLineEdit(edit);
|
||||
setCompleter(nullptr);
|
||||
@ -39,16 +39,19 @@ void ProfilesComboBox::setEditEnabled(bool editable)
|
||||
connect(lineEdit(), &QLineEdit::textChanged, this, &ProfilesComboBox::signalProfileTextChanged);
|
||||
}
|
||||
|
||||
void ProfilesComboBox::slotTextChanged(const QString &text)
|
||||
void ProfilesComboBox::slotTextChanged(const QString& text)
|
||||
{
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::Text,Qt::red);
|
||||
palette.setColor(QPalette::Text, Qt::red);
|
||||
|
||||
int index = findText(text);
|
||||
|
||||
if (text.isEmpty() || (index != -1 && index != currentIndex())) {
|
||||
if (text.isEmpty() || (index != -1 && index != currentIndex()))
|
||||
{
|
||||
lineEdit()->setPalette(palette);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
lineEdit()->setPalette(QApplication::palette());
|
||||
}
|
||||
}
|
||||
@ -83,11 +86,12 @@ void ProfilesComboBox::slotIndexChangedByUser(int index)
|
||||
mOldProfile = currentText();
|
||||
}
|
||||
|
||||
ProfilesComboBox::ComboBoxLineEdit::ComboBoxLineEdit (QWidget *parent)
|
||||
: LineEdit (parent)
|
||||
ProfilesComboBox::ComboBoxLineEdit::ComboBoxLineEdit(QWidget* parent)
|
||||
: LineEdit(parent)
|
||||
{
|
||||
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||
|
||||
setObjectName(QString("ComboBoxLineEdit"));
|
||||
setStyleSheet(QString("ComboBoxLineEdit { background-color: transparent; padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1));
|
||||
setStyleSheet(QString("ComboBoxLineEdit { background-color: transparent; padding-right: %1px; } ")
|
||||
.arg(mClearButton->sizeHint().width() + frameWidth + 1));
|
||||
}
|
||||
|
@ -16,12 +16,11 @@ public:
|
||||
class ComboBoxLineEdit : public LineEdit
|
||||
{
|
||||
public:
|
||||
explicit ComboBoxLineEdit (QWidget *parent = nullptr);
|
||||
explicit ComboBoxLineEdit(QWidget* parent = nullptr);
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
explicit ProfilesComboBox(QWidget *parent = nullptr);
|
||||
explicit ProfilesComboBox(QWidget* parent = nullptr);
|
||||
void setEditEnabled(bool editable);
|
||||
void setCurrentProfile(int index)
|
||||
{
|
||||
@ -30,16 +29,16 @@ public:
|
||||
}
|
||||
|
||||
signals:
|
||||
void signalProfileTextChanged(const QString &item);
|
||||
void signalProfileChanged(const QString &previous, const QString ¤t);
|
||||
void signalProfileTextChanged(const QString& item);
|
||||
void signalProfileChanged(const QString& previous, const QString& current);
|
||||
void signalProfileChanged(int index);
|
||||
void profileRenamed(const QString &oldName, const QString &newName);
|
||||
void profileRenamed(const QString& oldName, const QString& newName);
|
||||
|
||||
private slots:
|
||||
|
||||
void slotEditingFinished();
|
||||
void slotIndexChangedByUser(int index);
|
||||
void slotTextChanged(const QString &text);
|
||||
void slotTextChanged(const QString& text);
|
||||
|
||||
private:
|
||||
QString mOldProfile;
|
||||
|
@ -1,31 +1,31 @@
|
||||
#include "textinputdialog.hpp"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QApplication>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QValidator>
|
||||
#include <QLabel>
|
||||
|
||||
Launcher::TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWidget *parent) :
|
||||
QDialog(parent)
|
||||
Launcher::TextInputDialog::TextInputDialog(const QString& title, const QString& text, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
mButtonBox = new QDialogButtonBox(this);
|
||||
mButtonBox->addButton(QDialogButtonBox::Ok);
|
||||
mButtonBox->addButton(QDialogButtonBox::Cancel);
|
||||
mButtonBox->button(QDialogButtonBox::Ok)->setEnabled (false);
|
||||
mButtonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||
|
||||
auto *label = new QLabel(this);
|
||||
auto* label = new QLabel(this);
|
||||
label->setText(text);
|
||||
|
||||
// Line edit
|
||||
QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
|
||||
QValidator* validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
|
||||
mLineEdit = new LineEdit(this);
|
||||
mLineEdit->setValidator(validator);
|
||||
mLineEdit->setCompleter(nullptr);
|
||||
|
||||
auto *dialogLayout = new QVBoxLayout(this);
|
||||
auto* dialogLayout = new QVBoxLayout(this);
|
||||
dialogLayout->addWidget(label);
|
||||
dialogLayout->addWidget(mLineEdit);
|
||||
dialogLayout->addWidget(mButtonBox);
|
||||
@ -43,9 +43,7 @@ Launcher::TextInputDialog::TextInputDialog(const QString& title, const QString &
|
||||
connect(mButtonBox, &QDialogButtonBox::rejected, this, &TextInputDialog::reject);
|
||||
}
|
||||
|
||||
Launcher::TextInputDialog::~TextInputDialog()
|
||||
{
|
||||
}
|
||||
Launcher::TextInputDialog::~TextInputDialog() {}
|
||||
|
||||
int Launcher::TextInputDialog::exec()
|
||||
{
|
||||
@ -56,15 +54,18 @@ int Launcher::TextInputDialog::exec()
|
||||
|
||||
void Launcher::TextInputDialog::setOkButtonEnabled(bool enabled)
|
||||
{
|
||||
QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok);
|
||||
QPushButton* okButton = mButtonBox->button(QDialogButtonBox::Ok);
|
||||
okButton->setEnabled(enabled);
|
||||
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::Text, Qt::red);
|
||||
|
||||
if (enabled) {
|
||||
if (enabled)
|
||||
{
|
||||
mLineEdit->setPalette(QApplication::palette());
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Existing profile name, make the text red
|
||||
mLineEdit->setPalette(palette);
|
||||
}
|
||||
|
@ -14,20 +14,17 @@ namespace Launcher
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TextInputDialog(const QString& title, const QString& text, QWidget* parent = nullptr);
|
||||
~TextInputDialog() override;
|
||||
|
||||
explicit TextInputDialog(const QString& title, const QString &text, QWidget *parent = nullptr);
|
||||
~TextInputDialog () override;
|
||||
|
||||
inline LineEdit *lineEdit() { return mLineEdit; }
|
||||
inline LineEdit* lineEdit() { return mLineEdit; }
|
||||
void setOkButtonEnabled(bool enabled);
|
||||
|
||||
int exec() override;
|
||||
|
||||
private:
|
||||
|
||||
QDialogButtonBox *mButtonBox;
|
||||
LineEdit *mLineEdit;
|
||||
|
||||
QDialogButtonBox* mButtonBox;
|
||||
LineEdit* mLineEdit;
|
||||
};
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,40 +1,41 @@
|
||||
#ifndef MWINIIMPORTER_IMPORTER
|
||||
#define MWINIIMPORTER_IMPORTER 1
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
#include <iosfwd>
|
||||
#include <filesystem>
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
|
||||
class MwIniImporter {
|
||||
public:
|
||||
class MwIniImporter
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string, std::string> strmap;
|
||||
typedef std::map<std::string, std::vector<std::string> > multistrmap;
|
||||
typedef std::vector< std::pair< std::string, std::vector<std::string> > > dependencyList;
|
||||
typedef std::map<std::string, std::vector<std::string>> multistrmap;
|
||||
typedef std::vector<std::pair<std::string, std::vector<std::string>>> dependencyList;
|
||||
|
||||
MwIniImporter();
|
||||
void setInputEncoding(const ToUTF8::FromType& encoding);
|
||||
void setVerbose(bool verbose);
|
||||
multistrmap loadIniFile(const std::filesystem::path& filename) const;
|
||||
static multistrmap loadCfgFile(const std::filesystem::path& filename);
|
||||
void merge(multistrmap &cfg, const multistrmap &ini) const;
|
||||
void mergeFallback(multistrmap &cfg, const multistrmap &ini) const;
|
||||
void importGameFiles(multistrmap &cfg, const multistrmap &ini,
|
||||
const std::filesystem::path& iniFilename) const;
|
||||
void importArchives(multistrmap &cfg, const multistrmap &ini) const;
|
||||
static void writeToFile(std::ostream &out, const multistrmap &cfg);
|
||||
void setInputEncoding(const ToUTF8::FromType& encoding);
|
||||
void setVerbose(bool verbose);
|
||||
multistrmap loadIniFile(const std::filesystem::path& filename) const;
|
||||
static multistrmap loadCfgFile(const std::filesystem::path& filename);
|
||||
void merge(multistrmap& cfg, const multistrmap& ini) const;
|
||||
void mergeFallback(multistrmap& cfg, const multistrmap& ini) const;
|
||||
void importGameFiles(multistrmap& cfg, const multistrmap& ini, const std::filesystem::path& iniFilename) const;
|
||||
void importArchives(multistrmap& cfg, const multistrmap& ini) const;
|
||||
static void writeToFile(std::ostream& out, const multistrmap& cfg);
|
||||
|
||||
static std::vector<std::string> dependencySort(MwIniImporter::dependencyList source);
|
||||
|
||||
private:
|
||||
static void dependencySortStep(std::string& element, MwIniImporter::dependencyList& source, std::vector<std::string>& result);
|
||||
private:
|
||||
static void dependencySortStep(
|
||||
std::string& element, MwIniImporter::dependencyList& source, std::vector<std::string>& result);
|
||||
static std::vector<std::string>::iterator findString(std::vector<std::string>& source, const std::string& string);
|
||||
|
||||
static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value);
|
||||
static void insertMultistrmap(multistrmap& cfg, const std::string& key, const std::string& value);
|
||||
static void addPaths(std::vector<std::filesystem::path>& output, std::vector<std::string> input);
|
||||
|
||||
/// \return file's "last modified time", used in original MW to determine plug-in load order
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "importer.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
@ -13,7 +13,8 @@ namespace bpo = boost::program_options;
|
||||
namespace sfs = std::filesystem;
|
||||
|
||||
#ifndef _WIN32
|
||||
int main(int argc, char *argv[]) {
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
#else
|
||||
|
||||
// Include on Windows only
|
||||
@ -22,26 +23,26 @@ int main(int argc, char *argv[]) {
|
||||
class utf8argv
|
||||
{
|
||||
public:
|
||||
|
||||
utf8argv(int argc, wchar_t *wargv[])
|
||||
utf8argv(int argc, wchar_t* wargv[])
|
||||
{
|
||||
args.reserve(argc);
|
||||
argv = new const char *[argc];
|
||||
argv = new const char*[argc];
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
args.push_back(boost::locale::conv::utf_to_utf<char>(wargv[i]));
|
||||
argv[i] = args.back().c_str();
|
||||
}
|
||||
}
|
||||
|
||||
~utf8argv() { delete[] argv; }
|
||||
char **get() const { return const_cast<char **>(argv); }
|
||||
char** get() const { return const_cast<char**>(argv); }
|
||||
|
||||
private:
|
||||
utf8argv(const utf8argv&);
|
||||
utf8argv& operator=(const utf8argv&);
|
||||
|
||||
const char **argv;
|
||||
const char** argv;
|
||||
std::vector<std::string> args;
|
||||
};
|
||||
|
||||
@ -52,9 +53,10 @@ private:
|
||||
|
||||
For boost::filesystem::path::imbue see components/files/windowspath.cpp
|
||||
*/
|
||||
int wmain(int argc, wchar_t *wargv[]) {
|
||||
int wmain(int argc, wchar_t* wargv[])
|
||||
{
|
||||
utf8argv converter(argc, wargv);
|
||||
char **argv = converter.get();
|
||||
char** argv = converter.get();
|
||||
#endif
|
||||
|
||||
try
|
||||
@ -70,43 +72,54 @@ int wmain(int argc, wchar_t *wargv[]) {
|
||||
addOption("game-files,g", "import esm and esp files");
|
||||
addOption("fonts,f", "import bitmap fonts");
|
||||
addOption("no-archives,A", "disable bsa archives import");
|
||||
addOption("encoding,e", bpo::value<std::string>()-> default_value("win1252"),
|
||||
"Character encoding used in OpenMW game messages:\n"
|
||||
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
|
||||
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
|
||||
"\n\twin1252 - Western European (Latin) alphabet, used by default");
|
||||
;
|
||||
addOption("encoding,e", bpo::value<std::string>()->default_value("win1252"),
|
||||
"Character encoding used in OpenMW game messages:\n"
|
||||
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, "
|
||||
"Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
|
||||
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
|
||||
"\n\twin1252 - Western European (Latin) alphabet, used by default");
|
||||
;
|
||||
p_desc.add("ini", 1).add("cfg", 1);
|
||||
|
||||
bpo::variables_map vm;
|
||||
|
||||
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
|
||||
.options(desc)
|
||||
.positional(p_desc)
|
||||
.run();
|
||||
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv).options(desc).positional(p_desc).run();
|
||||
bpo::store(parsed, vm);
|
||||
|
||||
if(vm.count("help") || !vm.count("ini") || !vm.count("cfg")) {
|
||||
if (vm.count("help") || !vm.count("ini") || !vm.count("cfg"))
|
||||
{
|
||||
std::cout << desc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bpo::notify(vm);
|
||||
|
||||
std::filesystem::path iniFile(vm["ini"].as<Files::MaybeQuotedPath>().u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
|
||||
std::filesystem::path cfgFile(vm["cfg"].as<Files::MaybeQuotedPath>().u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
|
||||
std::filesystem::path iniFile(
|
||||
vm["ini"].as<Files::MaybeQuotedPath>().u8string()); // This call to u8string is redundant, but required to
|
||||
// build on MSVC 14.26 due to implementation bugs.
|
||||
std::filesystem::path cfgFile(
|
||||
vm["cfg"].as<Files::MaybeQuotedPath>().u8string()); // This call to u8string is redundant, but required to
|
||||
// build on MSVC 14.26 due to implementation bugs.
|
||||
|
||||
// if no output is given, write back to cfg file
|
||||
std::filesystem::path outputFile = vm["output"].as<Files::MaybeQuotedPath>().u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
|
||||
if(vm["output"].defaulted()) {
|
||||
outputFile = vm["cfg"].as<Files::MaybeQuotedPath>().u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
|
||||
std::filesystem::path outputFile = vm["output"]
|
||||
.as<Files::MaybeQuotedPath>()
|
||||
.u8string(); // This call to u8string is redundant, but required to build
|
||||
// on MSVC 14.26 due to implementation bugs.
|
||||
if (vm["output"].defaulted())
|
||||
{
|
||||
outputFile = vm["cfg"]
|
||||
.as<Files::MaybeQuotedPath>()
|
||||
.u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due
|
||||
// to implementation bugs.
|
||||
}
|
||||
|
||||
if(!std::filesystem::exists(iniFile)) {
|
||||
if (!std::filesystem::exists(iniFile))
|
||||
{
|
||||
std::cerr << "ini file does not exist" << std::endl;
|
||||
return -3;
|
||||
}
|
||||
if(!std::filesystem::exists(cfgFile))
|
||||
if (!std::filesystem::exists(cfgFile))
|
||||
std::cerr << "cfg file does not exist" << std::endl;
|
||||
|
||||
MwIniImporter importer;
|
||||
@ -129,11 +142,13 @@ int wmain(int argc, wchar_t *wargv[]) {
|
||||
importer.merge(cfg, ini);
|
||||
importer.mergeFallback(cfg, ini);
|
||||
|
||||
if(vm.count("game-files")) {
|
||||
if (vm.count("game-files"))
|
||||
{
|
||||
importer.importGameFiles(cfg, ini, iniFile);
|
||||
}
|
||||
|
||||
if(!vm.count("no-archives")) {
|
||||
if (!vm.count("no-archives"))
|
||||
{
|
||||
importer.importArchives(cfg, ini);
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,21 @@
|
||||
#include "worldspacedata.hpp"
|
||||
#include "navmesh.hpp"
|
||||
#include "worldspacedata.hpp"
|
||||
|
||||
#include <components/debug/debugging.hpp>
|
||||
#include <components/detournavigator/agentbounds.hpp>
|
||||
#include <components/detournavigator/navmeshdb.hpp>
|
||||
#include <components/detournavigator/recastglobalallocator.hpp>
|
||||
#include <components/detournavigator/settings.hpp>
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <components/esm3/readerscache.hpp>
|
||||
#include <components/esm3/variant.hpp>
|
||||
#include <components/esmloader/esmdata.hpp>
|
||||
#include <components/esmloader/load.hpp>
|
||||
#include <components/fallback/fallback.hpp>
|
||||
#include <components/fallback/validate.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/files/conversion.hpp>
|
||||
#include <components/platform/platform.hpp>
|
||||
#include <components/resource/bulletshapemanager.hpp>
|
||||
#include <components/resource/imagemanager.hpp>
|
||||
#include <components/resource/niffilemanager.hpp>
|
||||
@ -21,10 +25,6 @@
|
||||
#include <components/version/version.hpp>
|
||||
#include <components/vfs/manager.hpp>
|
||||
#include <components/vfs/registerarchives.hpp>
|
||||
#include <components/esm3/readerscache.hpp>
|
||||
#include <components/platform/platform.hpp>
|
||||
#include <components/detournavigator/agentbounds.hpp>
|
||||
#include <components/files/conversion.hpp>
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
@ -40,7 +40,6 @@
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace NavMeshTool
|
||||
{
|
||||
namespace
|
||||
@ -59,59 +58,76 @@ namespace NavMeshTool
|
||||
|
||||
addOption("version", "print version information and quit");
|
||||
|
||||
addOption("data", bpo::value<Files::MaybeQuotedPathContainer>()->default_value(Files::MaybeQuotedPathContainer(), "data")
|
||||
->multitoken()->composing(), "set data directories (later directories have higher priority)");
|
||||
addOption("data",
|
||||
bpo::value<Files::MaybeQuotedPathContainer>()
|
||||
->default_value(Files::MaybeQuotedPathContainer(), "data")
|
||||
->multitoken()
|
||||
->composing(),
|
||||
"set data directories (later directories have higher priority)");
|
||||
|
||||
addOption("data-local", bpo::value<Files::MaybeQuotedPathContainer::value_type>()->default_value(Files::MaybeQuotedPathContainer::value_type(), ""),
|
||||
"set local data directory (highest priority)");
|
||||
addOption("data-local",
|
||||
bpo::value<Files::MaybeQuotedPathContainer::value_type>()->default_value(
|
||||
Files::MaybeQuotedPathContainer::value_type(), ""),
|
||||
"set local data directory (highest priority)");
|
||||
|
||||
addOption("fallback-archive", bpo::value<StringsVector>()->default_value(StringsVector(), "fallback-archive")
|
||||
->multitoken()->composing(), "set fallback BSA archives (later archives have higher priority)");
|
||||
addOption("fallback-archive",
|
||||
bpo::value<StringsVector>()
|
||||
->default_value(StringsVector(), "fallback-archive")
|
||||
->multitoken()
|
||||
->composing(),
|
||||
"set fallback BSA archives (later archives have higher priority)");
|
||||
|
||||
addOption("resources", bpo::value<Files::MaybeQuotedPath>()->default_value(Files::MaybeQuotedPath(), "resources"),
|
||||
"set resources directory");
|
||||
addOption("resources",
|
||||
bpo::value<Files::MaybeQuotedPath>()->default_value(Files::MaybeQuotedPath(), "resources"),
|
||||
"set resources directory");
|
||||
|
||||
addOption("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
|
||||
->multitoken()->composing(), "content file(s): esm/esp, or omwgame/omwaddon/omwscripts");
|
||||
addOption("content",
|
||||
bpo::value<StringsVector>()->default_value(StringsVector(), "")->multitoken()->composing(),
|
||||
"content file(s): esm/esp, or omwgame/omwaddon/omwscripts");
|
||||
|
||||
addOption("fs-strict", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "strict file system handling (no case folding)");
|
||||
addOption("fs-strict", bpo::value<bool>()->implicit_value(true)->default_value(false),
|
||||
"strict file system handling (no case folding)");
|
||||
|
||||
addOption("encoding", bpo::value<std::string>()->
|
||||
default_value("win1252"),
|
||||
"Character encoding used in OpenMW game messages:\n"
|
||||
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
|
||||
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
|
||||
"\n\twin1252 - Western European (Latin) alphabet, used by default");
|
||||
addOption("encoding", bpo::value<std::string>()->default_value("win1252"),
|
||||
"Character encoding used in OpenMW game messages:\n"
|
||||
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, "
|
||||
"Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
|
||||
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
|
||||
"\n\twin1252 - Western European (Latin) alphabet, used by default");
|
||||
|
||||
addOption("fallback", bpo::value<Fallback::FallbackMap>()->default_value(Fallback::FallbackMap(), "")
|
||||
->multitoken()->composing(), "fallback values");
|
||||
addOption("fallback",
|
||||
bpo::value<Fallback::FallbackMap>()
|
||||
->default_value(Fallback::FallbackMap(), "")
|
||||
->multitoken()
|
||||
->composing(),
|
||||
"fallback values");
|
||||
|
||||
addOption("threads", bpo::value<std::size_t>()->default_value(std::max<std::size_t>(std::thread::hardware_concurrency() - 1, 1)),
|
||||
"number of threads for parallel processing");
|
||||
addOption("threads",
|
||||
bpo::value<std::size_t>()->default_value(
|
||||
std::max<std::size_t>(std::thread::hardware_concurrency() - 1, 1)),
|
||||
"number of threads for parallel processing");
|
||||
|
||||
addOption("process-interior-cells", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "build navmesh for interior cells");
|
||||
addOption("process-interior-cells", bpo::value<bool>()->implicit_value(true)->default_value(false),
|
||||
"build navmesh for interior cells");
|
||||
|
||||
addOption("remove-unused-tiles", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "remove tiles from cache that will not be used with current content profile");
|
||||
addOption("remove-unused-tiles", bpo::value<bool>()->implicit_value(true)->default_value(false),
|
||||
"remove tiles from cache that will not be used with current content profile");
|
||||
|
||||
addOption("write-binary-log", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "write progress in binary messages to be consumed by the launcher");
|
||||
addOption("write-binary-log", bpo::value<bool>()->implicit_value(true)->default_value(false),
|
||||
"write progress in binary messages to be consumed by the launcher");
|
||||
|
||||
Files::ConfigurationManager::addCommonOptions(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int runNavMeshTool(int argc, char *argv[])
|
||||
int runNavMeshTool(int argc, char* argv[])
|
||||
{
|
||||
Platform::init();
|
||||
|
||||
bpo::options_description desc = makeOptionsDescription();
|
||||
|
||||
bpo::parsed_options options = bpo::command_line_parser(argc, argv)
|
||||
.options(desc).allow_unregistered().run();
|
||||
bpo::parsed_options options = bpo::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
|
||||
bpo::variables_map variables;
|
||||
|
||||
bpo::store(options, variables);
|
||||
@ -175,10 +191,13 @@ namespace NavMeshTool
|
||||
Settings::Manager settings;
|
||||
settings.load(config);
|
||||
|
||||
const auto agentCollisionShape = DetourNavigator::toCollisionShapeType(Settings::Manager::getInt("actor collision shape type", "Game"));
|
||||
const osg::Vec3f agentHalfExtents = Settings::Manager::getVector3("default actor pathfind half extents", "Game");
|
||||
const DetourNavigator::AgentBounds agentBounds {agentCollisionShape, agentHalfExtents};
|
||||
const std::uint64_t maxDbFileSize = static_cast<std::uint64_t>(Settings::Manager::getInt64("max navmeshdb file size", "Navigator"));
|
||||
const auto agentCollisionShape = DetourNavigator::toCollisionShapeType(
|
||||
Settings::Manager::getInt("actor collision shape type", "Game"));
|
||||
const osg::Vec3f agentHalfExtents
|
||||
= Settings::Manager::getVector3("default actor pathfind half extents", "Game");
|
||||
const DetourNavigator::AgentBounds agentBounds{ agentCollisionShape, agentHalfExtents };
|
||||
const std::uint64_t maxDbFileSize
|
||||
= static_cast<std::uint64_t>(Settings::Manager::getInt64("max navmeshdb file size", "Navigator"));
|
||||
const auto dbPath = Files::pathToUnicodeString(config.getUserDataPath() / "navmesh.db");
|
||||
|
||||
DetourNavigator::NavMeshDb db(dbPath, maxDbFileSize);
|
||||
@ -192,7 +211,8 @@ namespace NavMeshTool
|
||||
query.mLoadGameSettings = true;
|
||||
query.mLoadLands = true;
|
||||
query.mLoadStatics = true;
|
||||
const EsmLoader::EsmData esmData = EsmLoader::loadEsmData(query, contentFiles, fileCollections, readers, &encoder);
|
||||
const EsmLoader::EsmData esmData
|
||||
= EsmLoader::loadEsmData(query, contentFiles, fileCollections, readers, &encoder);
|
||||
|
||||
Resource::ImageManager imageManager(&vfs);
|
||||
Resource::NifFileManager nifFileManager(&vfs);
|
||||
@ -200,10 +220,11 @@ namespace NavMeshTool
|
||||
Resource::BulletShapeManager bulletShapeManager(&vfs, &sceneManager, &nifFileManager);
|
||||
DetourNavigator::RecastGlobalAllocator::init();
|
||||
DetourNavigator::Settings navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager();
|
||||
navigatorSettings.mRecast.mSwimHeightScale = EsmLoader::getGameSetting(esmData.mGameSettings, "fSwimHeightScale").getFloat();
|
||||
navigatorSettings.mRecast.mSwimHeightScale
|
||||
= EsmLoader::getGameSetting(esmData.mGameSettings, "fSwimHeightScale").getFloat();
|
||||
|
||||
WorldspaceData cellsData = gatherWorldspaceData(navigatorSettings, readers, vfs, bulletShapeManager,
|
||||
esmData, processInteriorCells, writeBinaryLog);
|
||||
WorldspaceData cellsData = gatherWorldspaceData(
|
||||
navigatorSettings, readers, vfs, bulletShapeManager, esmData, processInteriorCells, writeBinaryLog);
|
||||
|
||||
const Status status = generateAllNavMeshTiles(agentBounds, navigatorSettings, threadsNumber,
|
||||
removeUnusedTiles, writeBinaryLog, cellsData, std::move(db));
|
||||
@ -217,10 +238,12 @@ namespace NavMeshTool
|
||||
Log(Debug::Warning) << "Cancelled";
|
||||
break;
|
||||
case Status::NotEnoughSpace:
|
||||
Log(Debug::Warning) << "Navmesh generation is cancelled due to running out of disk space or limits "
|
||||
Log(Debug::Warning)
|
||||
<< "Navmesh generation is cancelled due to running out of disk space or limits "
|
||||
<< "for navmesh db. Check disk space at the db location \"" << dbPath
|
||||
<< "\". If there is enough space, adjust \"max navmeshdb file size\" setting (see "
|
||||
<< "https://openmw.readthedocs.io/en/latest/reference/modding/settings/navigator.html?highlight=navmesh#max-navmeshdb-file-size).";
|
||||
<< "https://openmw.readthedocs.io/en/latest/reference/modding/settings/"
|
||||
"navigator.html?highlight=navmesh#max-navmeshdb-file-size).";
|
||||
break;
|
||||
}
|
||||
|
||||
@ -229,7 +252,7 @@ namespace NavMeshTool
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
return wrapApplication(NavMeshTool::runNavMeshTool, argc, argv, "NavMeshTool");
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "worldspacedata.hpp"
|
||||
|
||||
#include <components/debug/debugging.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/detournavigator/generatenavmeshtile.hpp>
|
||||
#include <components/detournavigator/gettilespositions.hpp>
|
||||
@ -14,20 +15,19 @@
|
||||
#include <components/detournavigator/settings.hpp>
|
||||
#include <components/detournavigator/tileposition.hpp>
|
||||
#include <components/misc/progressreporter.hpp>
|
||||
#include <components/navmeshtool/protocol.hpp>
|
||||
#include <components/sceneutil/workqueue.hpp>
|
||||
#include <components/sqlite3/transaction.hpp>
|
||||
#include <components/debug/debugging.hpp>
|
||||
#include <components/navmeshtool/protocol.hpp>
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace NavMeshTool
|
||||
{
|
||||
@ -35,50 +35,48 @@ namespace NavMeshTool
|
||||
{
|
||||
using DetourNavigator::AgentBounds;
|
||||
using DetourNavigator::GenerateNavMeshTile;
|
||||
using DetourNavigator::MeshSource;
|
||||
using DetourNavigator::NavMeshDb;
|
||||
using DetourNavigator::NavMeshTileInfo;
|
||||
using DetourNavigator::PreparedNavMeshData;
|
||||
using DetourNavigator::RecastMeshProvider;
|
||||
using DetourNavigator::MeshSource;
|
||||
using DetourNavigator::Settings;
|
||||
using DetourNavigator::ShapeId;
|
||||
using DetourNavigator::TileId;
|
||||
using DetourNavigator::TilePosition;
|
||||
using DetourNavigator::TileVersion;
|
||||
using DetourNavigator::TilesPositionsRange;
|
||||
using DetourNavigator::TileVersion;
|
||||
using Sqlite3::Transaction;
|
||||
|
||||
void logGeneratedTiles(std::size_t provided, std::size_t expected)
|
||||
{
|
||||
Log(Debug::Info) << provided << "/" << expected << " ("
|
||||
<< (static_cast<double>(provided) / static_cast<double>(expected) * 100)
|
||||
<< "%) navmesh tiles are generated";
|
||||
<< (static_cast<double>(provided) / static_cast<double>(expected) * 100)
|
||||
<< "%) navmesh tiles are generated";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void serializeToStderr(const T& value)
|
||||
{
|
||||
const std::vector<std::byte> data = serialize(value);
|
||||
getLockedRawStderr()->write(reinterpret_cast<const char*>(data.data()), static_cast<std::streamsize>(data.size()));
|
||||
getLockedRawStderr()->write(
|
||||
reinterpret_cast<const char*>(data.data()), static_cast<std::streamsize>(data.size()));
|
||||
}
|
||||
|
||||
void logGeneratedTilesMessage(std::size_t number)
|
||||
{
|
||||
serializeToStderr(GeneratedTiles {static_cast<std::uint64_t>(number)});
|
||||
serializeToStderr(GeneratedTiles{ static_cast<std::uint64_t>(number) });
|
||||
}
|
||||
|
||||
struct LogGeneratedTiles
|
||||
{
|
||||
void operator()(std::size_t provided, std::size_t expected) const
|
||||
{
|
||||
logGeneratedTiles(provided, expected);
|
||||
}
|
||||
void operator()(std::size_t provided, std::size_t expected) const { logGeneratedTiles(provided, expected); }
|
||||
};
|
||||
|
||||
class NavMeshTileConsumer final : public DetourNavigator::NavMeshTileConsumer
|
||||
{
|
||||
public:
|
||||
std::atomic_size_t mExpected {0};
|
||||
std::atomic_size_t mExpected{ 0 };
|
||||
|
||||
explicit NavMeshTileConsumer(NavMeshDb&& db, bool removeUnusedTiles, bool writeBinaryLog)
|
||||
: mDb(std::move(db))
|
||||
@ -87,7 +85,8 @@ namespace NavMeshTool
|
||||
, mTransaction(mDb.startTransaction(Sqlite3::TransactionMode::Immediate))
|
||||
, mNextTileId(mDb.getMaxTileId() + 1)
|
||||
, mNextShapeId(mDb.getMaxShapeId() + 1)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t getProvided() const { return mProvided.load(); }
|
||||
|
||||
@ -107,8 +106,8 @@ namespace NavMeshTool
|
||||
return DetourNavigator::resolveMeshSource(mDb, source, mNextShapeId);
|
||||
}
|
||||
|
||||
std::optional<NavMeshTileInfo> find(std::string_view worldspace, const TilePosition &tilePosition,
|
||||
const std::vector<std::byte> &input) override
|
||||
std::optional<NavMeshTileInfo> find(std::string_view worldspace, const TilePosition& tilePosition,
|
||||
const std::vector<std::byte>& input) override
|
||||
{
|
||||
std::optional<NavMeshTileInfo> result;
|
||||
std::lock_guard lock(mMutex);
|
||||
@ -137,35 +136,38 @@ namespace NavMeshTool
|
||||
if (mRemoveUnusedTiles)
|
||||
{
|
||||
std::lock_guard lock(mMutex);
|
||||
mDeleted += static_cast<std::size_t>(mDb.deleteTilesAtExcept(worldspace, tilePosition, TileId {tileId}));
|
||||
mDeleted += static_cast<std::size_t>(
|
||||
mDb.deleteTilesAtExcept(worldspace, tilePosition, TileId{ tileId }));
|
||||
}
|
||||
report();
|
||||
}
|
||||
|
||||
void insert(std::string_view worldspace, const TilePosition& tilePosition,
|
||||
std::int64_t version, const std::vector<std::byte>& input, PreparedNavMeshData& data) override
|
||||
void insert(std::string_view worldspace, const TilePosition& tilePosition, std::int64_t version,
|
||||
const std::vector<std::byte>& input, PreparedNavMeshData& data) override
|
||||
{
|
||||
{
|
||||
std::lock_guard lock(mMutex);
|
||||
if (mRemoveUnusedTiles)
|
||||
mDeleted += static_cast<std::size_t>(mDb.deleteTilesAt(worldspace, tilePosition));
|
||||
data.mUserId = static_cast<unsigned>(mNextTileId);
|
||||
mDb.insertTile(mNextTileId, worldspace, tilePosition, TileVersion {version}, input, serialize(data));
|
||||
mDb.insertTile(
|
||||
mNextTileId, worldspace, tilePosition, TileVersion{ version }, input, serialize(data));
|
||||
++mNextTileId;
|
||||
}
|
||||
++mInserted;
|
||||
report();
|
||||
}
|
||||
|
||||
void update(std::string_view worldspace, const TilePosition& tilePosition,
|
||||
std::int64_t tileId, std::int64_t version, PreparedNavMeshData& data) override
|
||||
void update(std::string_view worldspace, const TilePosition& tilePosition, std::int64_t tileId,
|
||||
std::int64_t version, PreparedNavMeshData& data) override
|
||||
{
|
||||
data.mUserId = static_cast<unsigned>(tileId);
|
||||
{
|
||||
std::lock_guard lock(mMutex);
|
||||
if (mRemoveUnusedTiles)
|
||||
mDeleted += static_cast<std::size_t>(mDb.deleteTilesAtExcept(worldspace, tilePosition, TileId {tileId}));
|
||||
mDb.updateTile(TileId {tileId}, TileVersion {version}, serialize(data));
|
||||
mDeleted += static_cast<std::size_t>(
|
||||
mDb.deleteTilesAtExcept(worldspace, tilePosition, TileId{ tileId }));
|
||||
mDb.updateTile(TileId{ tileId }, TileVersion{ version }, serialize(data));
|
||||
}
|
||||
++mUpdated;
|
||||
report();
|
||||
@ -225,9 +227,9 @@ namespace NavMeshTool
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_size_t mProvided {0};
|
||||
std::atomic_size_t mInserted {0};
|
||||
std::atomic_size_t mUpdated {0};
|
||||
std::atomic_size_t mProvided{ 0 };
|
||||
std::atomic_size_t mInserted{ 0 };
|
||||
std::atomic_size_t mUpdated{ 0 };
|
||||
std::size_t mDeleted = 0;
|
||||
Status mStatus = Status::Ok;
|
||||
mutable std::mutex mMutex;
|
||||
@ -252,51 +254,43 @@ namespace NavMeshTool
|
||||
};
|
||||
}
|
||||
|
||||
Status generateAllNavMeshTiles(const AgentBounds& agentBounds, const Settings& settings,
|
||||
std::size_t threadsNumber, bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& data,
|
||||
NavMeshDb&& db)
|
||||
Status generateAllNavMeshTiles(const AgentBounds& agentBounds, const Settings& settings, std::size_t threadsNumber,
|
||||
bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& data, NavMeshDb&& db)
|
||||
{
|
||||
Log(Debug::Info) << "Generating navmesh tiles by " << threadsNumber << " parallel workers...";
|
||||
|
||||
SceneUtil::WorkQueue workQueue(threadsNumber);
|
||||
auto navMeshTileConsumer = std::make_shared<NavMeshTileConsumer>(std::move(db), removeUnusedTiles, writeBinaryLog);
|
||||
auto navMeshTileConsumer
|
||||
= std::make_shared<NavMeshTileConsumer>(std::move(db), removeUnusedTiles, writeBinaryLog);
|
||||
std::size_t tiles = 0;
|
||||
std::mt19937_64 random;
|
||||
|
||||
for (const std::unique_ptr<WorldspaceNavMeshInput>& input : data.mNavMeshInputs)
|
||||
{
|
||||
const auto range = DetourNavigator::makeTilesPositionsRange(
|
||||
Misc::Convert::toOsgXY(input->mAabb.m_min),
|
||||
Misc::Convert::toOsgXY(input->mAabb.m_max),
|
||||
settings.mRecast
|
||||
);
|
||||
const auto range = DetourNavigator::makeTilesPositionsRange(Misc::Convert::toOsgXY(input->mAabb.m_min),
|
||||
Misc::Convert::toOsgXY(input->mAabb.m_max), settings.mRecast);
|
||||
|
||||
if (removeUnusedTiles)
|
||||
navMeshTileConsumer->removeTilesOutsideRange(input->mWorldspace, range);
|
||||
|
||||
std::vector<TilePosition> worldspaceTiles;
|
||||
|
||||
DetourNavigator::getTilesPositions(range,
|
||||
[&] (const TilePosition& tilePosition) { worldspaceTiles.push_back(tilePosition); });
|
||||
DetourNavigator::getTilesPositions(
|
||||
range, [&](const TilePosition& tilePosition) { worldspaceTiles.push_back(tilePosition); });
|
||||
|
||||
tiles += worldspaceTiles.size();
|
||||
|
||||
if (writeBinaryLog)
|
||||
serializeToStderr(ExpectedTiles {static_cast<std::uint64_t>(tiles)});
|
||||
serializeToStderr(ExpectedTiles{ static_cast<std::uint64_t>(tiles) });
|
||||
|
||||
navMeshTileConsumer->mExpected = tiles;
|
||||
|
||||
std::shuffle(worldspaceTiles.begin(), worldspaceTiles.end(), random);
|
||||
|
||||
for (const TilePosition& tilePosition : worldspaceTiles)
|
||||
workQueue.addWorkItem(new GenerateNavMeshTile(
|
||||
input->mWorldspace,
|
||||
tilePosition,
|
||||
RecastMeshProvider(input->mTileCachedRecastMeshManager),
|
||||
agentBounds,
|
||||
settings,
|
||||
navMeshTileConsumer
|
||||
));
|
||||
workQueue.addWorkItem(new GenerateNavMeshTile(input->mWorldspace, tilePosition,
|
||||
RecastMeshProvider(input->mTileCachedRecastMeshManager), agentBounds, settings,
|
||||
navMeshTileConsumer));
|
||||
}
|
||||
|
||||
const Status status = navMeshTileConsumer->wait();
|
||||
@ -307,10 +301,8 @@ namespace NavMeshTool
|
||||
const auto updated = navMeshTileConsumer->getUpdated();
|
||||
const auto deleted = navMeshTileConsumer->getDeleted();
|
||||
|
||||
Log(Debug::Info) << "Generated navmesh for " << navMeshTileConsumer->getProvided() << " tiles, "
|
||||
<< inserted << " are inserted, "
|
||||
<< updated << " updated and "
|
||||
<< deleted << " deleted";
|
||||
Log(Debug::Info) << "Generated navmesh for " << navMeshTileConsumer->getProvided() << " tiles, " << inserted
|
||||
<< " are inserted, " << updated << " updated and " << deleted << " deleted";
|
||||
|
||||
if (inserted + updated + deleted > 0)
|
||||
{
|
||||
|
@ -23,9 +23,9 @@ namespace NavMeshTool
|
||||
NotEnoughSpace,
|
||||
};
|
||||
|
||||
Status generateAllNavMeshTiles(const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Settings& settings,
|
||||
std::size_t threadsNumber, bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& cellsData,
|
||||
DetourNavigator::NavMeshDb&& db);
|
||||
Status generateAllNavMeshTiles(const DetourNavigator::AgentBounds& agentBounds,
|
||||
const DetourNavigator::Settings& settings, std::size_t threadsNumber, bool removeUnusedTiles,
|
||||
bool writeBinaryLog, WorldspaceData& cellsData, DetourNavigator::NavMeshDb&& db);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,27 +1,27 @@
|
||||
#include "worldspacedata.hpp"
|
||||
|
||||
#include <components/bullethelpers/aabb.hpp>
|
||||
#include <components/debug/debugging.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/detournavigator/gettilespositions.hpp>
|
||||
#include <components/detournavigator/objectid.hpp>
|
||||
#include <components/detournavigator/recastmesh.hpp>
|
||||
#include <components/detournavigator/tilecachedrecastmeshmanager.hpp>
|
||||
#include <components/detournavigator/settings.hpp>
|
||||
#include <components/detournavigator/tilecachedrecastmeshmanager.hpp>
|
||||
#include <components/esm3/cellref.hpp>
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/esm3/loadland.hpp>
|
||||
#include <components/esm3/readerscache.hpp>
|
||||
#include <components/esmloader/esmdata.hpp>
|
||||
#include <components/esmloader/lessbyid.hpp>
|
||||
#include <components/esmloader/record.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
#include <components/misc/strings/lower.hpp>
|
||||
#include <components/navmeshtool/protocol.hpp>
|
||||
#include <components/resource/bulletshapemanager.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/vfs/manager.hpp>
|
||||
#include <components/debug/debugging.hpp>
|
||||
#include <components/navmeshtool/protocol.hpp>
|
||||
#include <components/esm3/readerscache.hpp>
|
||||
|
||||
#include <LinearMath/btVector3.h>
|
||||
|
||||
@ -56,21 +56,28 @@ namespace NavMeshTool
|
||||
float mScale;
|
||||
ESM::Position mPos;
|
||||
|
||||
CellRef(ESM::RecNameInts type, ESM::RefNum refNum, std::string&& refId, float scale, const ESM::Position& pos)
|
||||
: mType(type), mRefNum(refNum), mRefId(std::move(refId)), mScale(scale), mPos(pos) {}
|
||||
CellRef(
|
||||
ESM::RecNameInts type, ESM::RefNum refNum, std::string&& refId, float scale, const ESM::Position& pos)
|
||||
: mType(type)
|
||||
, mRefNum(refNum)
|
||||
, mRefId(std::move(refId))
|
||||
, mScale(scale)
|
||||
, mPos(pos)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
ESM::RecNameInts getType(const EsmLoader::EsmData& esmData, std::string_view refId)
|
||||
{
|
||||
const auto it = std::lower_bound(esmData.mRefIdTypes.begin(), esmData.mRefIdTypes.end(),
|
||||
refId, EsmLoader::LessById {});
|
||||
const auto it = std::lower_bound(
|
||||
esmData.mRefIdTypes.begin(), esmData.mRefIdTypes.end(), refId, EsmLoader::LessById{});
|
||||
if (it == esmData.mRefIdTypes.end() || it->mId != refId)
|
||||
return {};
|
||||
return it->mType;
|
||||
}
|
||||
|
||||
std::vector<CellRef> loadCellRefs(const ESM::Cell& cell, const EsmLoader::EsmData& esmData,
|
||||
ESM::ReadersCache& readers)
|
||||
std::vector<CellRef> loadCellRefs(
|
||||
const ESM::Cell& cell, const EsmLoader::EsmData& esmData, ESM::ReadersCache& readers)
|
||||
{
|
||||
std::vector<EsmLoader::Record<CellRef>> cellRefs;
|
||||
|
||||
@ -84,16 +91,17 @@ namespace NavMeshTool
|
||||
{
|
||||
Misc::StringUtils::lowerCaseInPlace(cellRef.mRefID);
|
||||
const ESM::RecNameInts type = getType(esmData, cellRef.mRefID);
|
||||
if (type == ESM::RecNameInts {})
|
||||
if (type == ESM::RecNameInts{})
|
||||
continue;
|
||||
cellRefs.emplace_back(deleted, type, cellRef.mRefNum, std::move(cellRef.mRefID),
|
||||
cellRef.mScale, cellRef.mPos);
|
||||
cellRefs.emplace_back(
|
||||
deleted, type, cellRef.mRefNum, std::move(cellRef.mRefID), cellRef.mScale, cellRef.mPos);
|
||||
}
|
||||
}
|
||||
|
||||
Log(Debug::Debug) << "Loaded " << cellRefs.size() << " cell refs";
|
||||
|
||||
const auto getKey = [] (const EsmLoader::Record<CellRef>& v) -> const ESM::RefNum& { return v.mValue.mRefNum; };
|
||||
const auto getKey
|
||||
= [](const EsmLoader::Record<CellRef>& v) -> const ESM::RefNum& { return v.mValue.mRefNum; };
|
||||
std::vector<CellRef> result = prepareRecords(cellRefs, getKey);
|
||||
|
||||
Log(Debug::Debug) << "Prepared " << result.size() << " unique cell refs";
|
||||
@ -103,8 +111,7 @@ namespace NavMeshTool
|
||||
|
||||
template <class F>
|
||||
void forEachObject(const ESM::Cell& cell, const EsmLoader::EsmData& esmData, const VFS::Manager& vfs,
|
||||
Resource::BulletShapeManager& bulletShapeManager, ESM::ReadersCache& readers,
|
||||
F&& f)
|
||||
Resource::BulletShapeManager& bulletShapeManager, ESM::ReadersCache& readers, F&& f)
|
||||
{
|
||||
std::vector<CellRef> cellRefs = loadCellRefs(cell, esmData, readers);
|
||||
|
||||
@ -119,23 +126,24 @@ namespace NavMeshTool
|
||||
if (cellRef.mType != ESM::REC_STAT)
|
||||
model = Misc::ResourceHelpers::correctActorModelPath(model, &vfs);
|
||||
|
||||
osg::ref_ptr<const Resource::BulletShape> shape = [&]
|
||||
{
|
||||
osg::ref_ptr<const Resource::BulletShape> shape = [&] {
|
||||
try
|
||||
{
|
||||
return bulletShapeManager.getShape(Misc::ResourceHelpers::correctMeshPath(model, &vfs));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Log(Debug::Warning) << "Failed to load cell ref \"" << cellRef.mRefId << "\" model \"" << model << "\": " << e.what();
|
||||
Log(Debug::Warning) << "Failed to load cell ref \"" << cellRef.mRefId << "\" model \"" << model
|
||||
<< "\": " << e.what();
|
||||
return osg::ref_ptr<const Resource::BulletShape>();
|
||||
}
|
||||
} ();
|
||||
}();
|
||||
|
||||
if (shape == nullptr || shape->mCollisionShape == nullptr)
|
||||
continue;
|
||||
|
||||
osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance(new Resource::BulletShapeInstance(std::move(shape)));
|
||||
osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance(
|
||||
new Resource::BulletShapeInstance(std::move(shape)));
|
||||
|
||||
switch (cellRef.mType)
|
||||
{
|
||||
@ -158,35 +166,20 @@ namespace NavMeshTool
|
||||
|
||||
struct LessByXY
|
||||
{
|
||||
bool operator ()(const ESM::Land& lhs, const ESM::Land& rhs) const
|
||||
{
|
||||
return GetXY {}(lhs) < GetXY {}(rhs);
|
||||
}
|
||||
bool operator()(const ESM::Land& lhs, const ESM::Land& rhs) const { return GetXY{}(lhs) < GetXY{}(rhs); }
|
||||
|
||||
bool operator ()(const ESM::Land& lhs, const osg::Vec2i& rhs) const
|
||||
{
|
||||
return GetXY {}(lhs) < rhs;
|
||||
}
|
||||
bool operator()(const ESM::Land& lhs, const osg::Vec2i& rhs) const { return GetXY{}(lhs) < rhs; }
|
||||
|
||||
bool operator ()(const osg::Vec2i& lhs, const ESM::Land& rhs) const
|
||||
{
|
||||
return lhs < GetXY {}(rhs);
|
||||
}
|
||||
bool operator()(const osg::Vec2i& lhs, const ESM::Land& rhs) const { return lhs < GetXY{}(rhs); }
|
||||
};
|
||||
|
||||
btAABB getAabb(const osg::Vec2i& cellPosition, btScalar minHeight, btScalar maxHeight)
|
||||
{
|
||||
btAABB aabb;
|
||||
aabb.m_min = btVector3(
|
||||
static_cast<btScalar>(cellPosition.x() * ESM::Land::REAL_SIZE),
|
||||
static_cast<btScalar>(cellPosition.y() * ESM::Land::REAL_SIZE),
|
||||
minHeight
|
||||
);
|
||||
aabb.m_max = btVector3(
|
||||
static_cast<btScalar>((cellPosition.x() + 1) * ESM::Land::REAL_SIZE),
|
||||
static_cast<btScalar>((cellPosition.y() + 1) * ESM::Land::REAL_SIZE),
|
||||
maxHeight
|
||||
);
|
||||
aabb.m_min = btVector3(static_cast<btScalar>(cellPosition.x() * ESM::Land::REAL_SIZE),
|
||||
static_cast<btScalar>(cellPosition.y() * ESM::Land::REAL_SIZE), minHeight);
|
||||
aabb.m_max = btVector3(static_cast<btScalar>((cellPosition.x() + 1) * ESM::Land::REAL_SIZE),
|
||||
static_cast<btScalar>((cellPosition.y() + 1) * ESM::Land::REAL_SIZE), maxHeight);
|
||||
return aabb;
|
||||
}
|
||||
|
||||
@ -205,8 +198,9 @@ namespace NavMeshTool
|
||||
std::vector<std::unique_ptr<ESM::Land::LandData>>& landDatas)
|
||||
{
|
||||
if (!land.has_value() || osg::Vec2i(land->mX, land->mY) != cellPosition
|
||||
|| (land->mDataTypes & ESM::Land::DATA_VHGT) == 0)
|
||||
return {HeightfieldPlane {ESM::Land::DEFAULT_HEIGHT}, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT};
|
||||
|| (land->mDataTypes & ESM::Land::DATA_VHGT) == 0)
|
||||
return { HeightfieldPlane{ ESM::Land::DEFAULT_HEIGHT }, ESM::Land::DEFAULT_HEIGHT,
|
||||
ESM::Land::DEFAULT_HEIGHT };
|
||||
|
||||
ESM::Land::LandData& landData = *landDatas.emplace_back(std::make_unique<ESM::Land::LandData>());
|
||||
land->loadData(ESM::Land::DATA_VHGT, &landData);
|
||||
@ -216,7 +210,7 @@ namespace NavMeshTool
|
||||
surface.mMinHeight = landData.mMinHeight;
|
||||
surface.mMaxHeight = landData.mMaxHeight;
|
||||
surface.mSize = static_cast<std::size_t>(ESM::Land::LAND_SIZE);
|
||||
return {surface, landData.mMinHeight, landData.mMaxHeight};
|
||||
return { surface, landData.mMinHeight, landData.mMaxHeight };
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@ -227,7 +221,8 @@ namespace NavMeshTool
|
||||
}
|
||||
}
|
||||
|
||||
WorldspaceNavMeshInput::WorldspaceNavMeshInput(std::string worldspace, const DetourNavigator::RecastSettings& settings)
|
||||
WorldspaceNavMeshInput::WorldspaceNavMeshInput(
|
||||
std::string worldspace, const DetourNavigator::RecastSettings& settings)
|
||||
: mWorldspace(std::move(worldspace))
|
||||
, mTileCachedRecastMeshManager(settings)
|
||||
{
|
||||
@ -247,7 +242,7 @@ namespace NavMeshTool
|
||||
std::size_t objectsCounter = 0;
|
||||
|
||||
if (writeBinaryLog)
|
||||
serializeToStderr(ExpectedCells {static_cast<std::uint64_t>(esmData.mCells.size())});
|
||||
serializeToStderr(ExpectedCells{ static_cast<std::uint64_t>(esmData.mCells.size()) });
|
||||
|
||||
for (std::size_t i = 0; i < esmData.mCells.size(); ++i)
|
||||
{
|
||||
@ -257,97 +252,100 @@ namespace NavMeshTool
|
||||
if (!exterior && !processInteriorCells)
|
||||
{
|
||||
if (writeBinaryLog)
|
||||
serializeToStderr(ProcessedCells {static_cast<std::uint64_t>(i + 1)});
|
||||
serializeToStderr(ProcessedCells{ static_cast<std::uint64_t>(i + 1) });
|
||||
Log(Debug::Info) << "Skipped interior"
|
||||
<< " cell (" << (i + 1) << "/" << esmData.mCells.size() << ") \"" << cell.getDescription() << "\"";
|
||||
<< " cell (" << (i + 1) << "/" << esmData.mCells.size() << ") \""
|
||||
<< cell.getDescription() << "\"";
|
||||
continue;
|
||||
}
|
||||
|
||||
Log(Debug::Debug) << "Processing " << (exterior ? "exterior" : "interior")
|
||||
<< " cell (" << (i + 1) << "/" << esmData.mCells.size() << ") \"" << cell.getDescription() << "\"";
|
||||
Log(Debug::Debug) << "Processing " << (exterior ? "exterior" : "interior") << " cell (" << (i + 1) << "/"
|
||||
<< esmData.mCells.size() << ") \"" << cell.getDescription() << "\"";
|
||||
|
||||
const osg::Vec2i cellPosition(cell.mData.mX, cell.mData.mY);
|
||||
const std::size_t cellObjectsBegin = data.mObjects.size();
|
||||
|
||||
WorldspaceNavMeshInput& navMeshInput = [&] () -> WorldspaceNavMeshInput&
|
||||
{
|
||||
WorldspaceNavMeshInput& navMeshInput = [&]() -> WorldspaceNavMeshInput& {
|
||||
auto it = navMeshInputs.find(cell.mCellId.mWorldspace);
|
||||
if (it == navMeshInputs.end())
|
||||
{
|
||||
it = navMeshInputs.emplace(cell.mCellId.mWorldspace,
|
||||
std::make_unique<WorldspaceNavMeshInput>(cell.mCellId.mWorldspace, settings.mRecast)).first;
|
||||
it = navMeshInputs
|
||||
.emplace(cell.mCellId.mWorldspace,
|
||||
std::make_unique<WorldspaceNavMeshInput>(cell.mCellId.mWorldspace, settings.mRecast))
|
||||
.first;
|
||||
it->second->mTileCachedRecastMeshManager.setWorldspace(cell.mCellId.mWorldspace, nullptr);
|
||||
}
|
||||
return *it->second;
|
||||
} ();
|
||||
}();
|
||||
|
||||
const TileCachedRecastMeshManager::UpdateGuard guard(navMeshInput.mTileCachedRecastMeshManager);
|
||||
|
||||
if (exterior)
|
||||
{
|
||||
const auto it = std::lower_bound(esmData.mLands.begin(), esmData.mLands.end(), cellPosition, LessByXY {});
|
||||
const auto [heightfieldShape, minHeight, maxHeight] = makeHeightfieldShape(
|
||||
it == esmData.mLands.end() ? std::optional<ESM::Land>() : *it,
|
||||
cellPosition, data.mHeightfields, data.mLandData
|
||||
);
|
||||
const auto it
|
||||
= std::lower_bound(esmData.mLands.begin(), esmData.mLands.end(), cellPosition, LessByXY{});
|
||||
const auto [heightfieldShape, minHeight, maxHeight]
|
||||
= makeHeightfieldShape(it == esmData.mLands.end() ? std::optional<ESM::Land>() : *it, cellPosition,
|
||||
data.mHeightfields, data.mLandData);
|
||||
|
||||
mergeOrAssign(getAabb(cellPosition, minHeight, maxHeight),
|
||||
navMeshInput.mAabb, navMeshInput.mAabbInitialized);
|
||||
mergeOrAssign(
|
||||
getAabb(cellPosition, minHeight, maxHeight), navMeshInput.mAabb, navMeshInput.mAabbInitialized);
|
||||
|
||||
navMeshInput.mTileCachedRecastMeshManager.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, heightfieldShape, &guard);
|
||||
navMeshInput.mTileCachedRecastMeshManager.addHeightfield(
|
||||
cellPosition, ESM::Land::REAL_SIZE, heightfieldShape, &guard);
|
||||
|
||||
navMeshInput.mTileCachedRecastMeshManager.addWater(cellPosition, ESM::Land::REAL_SIZE, -1, &guard);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((cell.mData.mFlags & ESM::Cell::HasWater) != 0)
|
||||
navMeshInput.mTileCachedRecastMeshManager.addWater(cellPosition, std::numeric_limits<int>::max(), cell.mWater, &guard);
|
||||
navMeshInput.mTileCachedRecastMeshManager.addWater(
|
||||
cellPosition, std::numeric_limits<int>::max(), cell.mWater, &guard);
|
||||
}
|
||||
|
||||
forEachObject(cell, esmData, vfs, bulletShapeManager, readers,
|
||||
[&] (BulletObject object)
|
||||
forEachObject(cell, esmData, vfs, bulletShapeManager, readers, [&](BulletObject object) {
|
||||
if (object.getShapeInstance()->mVisualCollisionType != Resource::VisualCollisionType::None)
|
||||
return;
|
||||
|
||||
const btTransform& transform = object.getCollisionObject().getWorldTransform();
|
||||
const btAABB aabb = BulletHelpers::getAabb(*object.getCollisionObject().getCollisionShape(), transform);
|
||||
mergeOrAssign(aabb, navMeshInput.mAabb, navMeshInput.mAabbInitialized);
|
||||
if (const btCollisionShape* avoid = object.getShapeInstance()->mAvoidCollisionShape.get())
|
||||
navMeshInput.mAabb.merge(BulletHelpers::getAabb(*avoid, transform));
|
||||
|
||||
const ObjectId objectId(++objectsCounter);
|
||||
const CollisionShape shape(object.getShapeInstance(), *object.getCollisionObject().getCollisionShape(),
|
||||
object.getObjectTransform());
|
||||
|
||||
navMeshInput.mTileCachedRecastMeshManager.addObject(
|
||||
objectId, shape, transform, DetourNavigator::AreaType_ground, &guard);
|
||||
|
||||
if (const btCollisionShape* avoid = object.getShapeInstance()->mAvoidCollisionShape.get())
|
||||
{
|
||||
if (object.getShapeInstance()->mVisualCollisionType != Resource::VisualCollisionType::None)
|
||||
return;
|
||||
const CollisionShape avoidShape(object.getShapeInstance(), *avoid, object.getObjectTransform());
|
||||
navMeshInput.mTileCachedRecastMeshManager.addObject(
|
||||
objectId, avoidShape, transform, DetourNavigator::AreaType_null, &guard);
|
||||
}
|
||||
|
||||
const btTransform& transform = object.getCollisionObject().getWorldTransform();
|
||||
const btAABB aabb = BulletHelpers::getAabb(*object.getCollisionObject().getCollisionShape(), transform);
|
||||
mergeOrAssign(aabb, navMeshInput.mAabb, navMeshInput.mAabbInitialized);
|
||||
if (const btCollisionShape* avoid = object.getShapeInstance()->mAvoidCollisionShape.get())
|
||||
navMeshInput.mAabb.merge(BulletHelpers::getAabb(*avoid, transform));
|
||||
|
||||
const ObjectId objectId(++objectsCounter);
|
||||
const CollisionShape shape(object.getShapeInstance(), *object.getCollisionObject().getCollisionShape(), object.getObjectTransform());
|
||||
|
||||
navMeshInput.mTileCachedRecastMeshManager.addObject(objectId, shape, transform,
|
||||
DetourNavigator::AreaType_ground, &guard);
|
||||
|
||||
if (const btCollisionShape* avoid = object.getShapeInstance()->mAvoidCollisionShape.get())
|
||||
{
|
||||
const CollisionShape avoidShape(object.getShapeInstance(), *avoid, object.getObjectTransform());
|
||||
navMeshInput.mTileCachedRecastMeshManager.addObject(objectId, avoidShape, transform,
|
||||
DetourNavigator::AreaType_null, &guard);
|
||||
}
|
||||
|
||||
data.mObjects.emplace_back(std::move(object));
|
||||
});
|
||||
data.mObjects.emplace_back(std::move(object));
|
||||
});
|
||||
|
||||
const auto cellDescription = cell.getDescription();
|
||||
|
||||
if (writeBinaryLog)
|
||||
serializeToStderr(ProcessedCells {static_cast<std::uint64_t>(i + 1)});
|
||||
serializeToStderr(ProcessedCells{ static_cast<std::uint64_t>(i + 1) });
|
||||
|
||||
Log(Debug::Info) << "Processed " << (exterior ? "exterior" : "interior")
|
||||
<< " cell (" << (i + 1) << "/" << esmData.mCells.size() << ") " << cellDescription
|
||||
<< " with " << (data.mObjects.size() - cellObjectsBegin) << " objects";
|
||||
Log(Debug::Info) << "Processed " << (exterior ? "exterior" : "interior") << " cell (" << (i + 1) << "/"
|
||||
<< esmData.mCells.size() << ") " << cellDescription << " with "
|
||||
<< (data.mObjects.size() - cellObjectsBegin) << " objects";
|
||||
}
|
||||
|
||||
data.mNavMeshInputs.reserve(navMeshInputs.size());
|
||||
std::transform(navMeshInputs.begin(), navMeshInputs.end(), std::back_inserter(data.mNavMeshInputs),
|
||||
[] (auto& v) { return std::move(v.second); });
|
||||
[](auto& v) { return std::move(v.second); });
|
||||
|
||||
Log(Debug::Info) << "Processed " << esmData.mCells.size() << " cells, added "
|
||||
<< data.mObjects.size() << " objects and " << data.mHeightfields.size() << " height fields";
|
||||
Log(Debug::Info) << "Processed " << esmData.mCells.size() << " cells, added " << data.mObjects.size()
|
||||
<< " objects and " << data.mHeightfields.size() << " height fields";
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -43,8 +43,8 @@ namespace DetourNavigator
|
||||
|
||||
namespace NavMeshTool
|
||||
{
|
||||
using DetourNavigator::TileCachedRecastMeshManager;
|
||||
using DetourNavigator::ObjectTransform;
|
||||
using DetourNavigator::TileCachedRecastMeshManager;
|
||||
|
||||
struct WorldspaceNavMeshInput
|
||||
{
|
||||
@ -62,12 +62,10 @@ namespace NavMeshTool
|
||||
BulletObject(osg::ref_ptr<Resource::BulletShapeInstance>&& shapeInstance, const ESM::Position& position,
|
||||
float localScaling)
|
||||
: mShapeInstance(std::move(shapeInstance))
|
||||
, mObjectTransform {position, localScaling}
|
||||
, mCollisionObject(BulletHelpers::makeCollisionObject(
|
||||
mShapeInstance->mCollisionShape.get(),
|
||||
Misc::Convert::toBullet(position.asVec3()),
|
||||
Misc::Convert::toBullet(Misc::Convert::makeOsgQuat(position))
|
||||
))
|
||||
, mObjectTransform{ position, localScaling }
|
||||
, mCollisionObject(BulletHelpers::makeCollisionObject(mShapeInstance->mCollisionShape.get(),
|
||||
Misc::Convert::toBullet(position.asVec3()),
|
||||
Misc::Convert::toBullet(Misc::Convert::makeOsgQuat(position))))
|
||||
{
|
||||
mShapeInstance->setLocalScaling(btVector3(localScaling, localScaling, localScaling));
|
||||
}
|
||||
|
@ -1,38 +1,38 @@
|
||||
///Program to test .nif files both on the FileSystem and in BSA archives.
|
||||
/// Program to test .nif files both on the FileSystem and in BSA archives.
|
||||
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/files/constrainedfilestream.hpp>
|
||||
#include <components/files/conversion.hpp>
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
#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 <components/files/configurationmanager.hpp>
|
||||
#include <components/files/conversion.hpp>
|
||||
#include <components/vfs/manager.hpp>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
// Create local aliases for brevity
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
///See if the file has the named extension
|
||||
/// See if the file has the named extension
|
||||
bool hasExtension(const std::filesystem::path& filename, const std::string& extensionToFind)
|
||||
{
|
||||
const auto extension = Files::pathToUnicodeString(filename.extension());
|
||||
return Misc::StringUtils::ciEqual(extension, extensionToFind);
|
||||
}
|
||||
|
||||
///See if the file has the "nif" extension.
|
||||
bool isNIF(const std::filesystem::path &filename)
|
||||
/// See if the file has the "nif" extension.
|
||||
bool isNIF(const std::filesystem::path& filename)
|
||||
{
|
||||
return hasExtension(filename,"nif");
|
||||
return hasExtension(filename, "nif");
|
||||
}
|
||||
///See if the file has the "bsa" extension.
|
||||
bool isBSA(const std::filesystem::path &filename)
|
||||
/// See if the file has the "bsa" extension.
|
||||
bool isBSA(const std::filesystem::path& filename)
|
||||
{
|
||||
return hasExtension(filename,"bsa");
|
||||
return hasExtension(filename, "bsa");
|
||||
}
|
||||
|
||||
/// Check all the nif files in a given VFS::Archive
|
||||
@ -43,21 +43,22 @@ void readVFS(std::unique_ptr<VFS::Archive>&& anArchive, const std::filesystem::p
|
||||
myManager.addArchive(std::move(anArchive));
|
||||
myManager.buildIndex();
|
||||
|
||||
for(const auto& name : myManager.getRecursiveDirectoryIterator(""))
|
||||
for (const auto& name : myManager.getRecursiveDirectoryIterator(""))
|
||||
{
|
||||
try{
|
||||
if(isNIF(name))
|
||||
try
|
||||
{
|
||||
if (isNIF(name))
|
||||
{
|
||||
// std::cout << "Decoding: " << name << std::endl;
|
||||
Nif::NIFFile temp_nif(myManager.get(name),archivePath / name);
|
||||
// std::cout << "Decoding: " << name << std::endl;
|
||||
Nif::NIFFile temp_nif(myManager.get(name), archivePath / name);
|
||||
}
|
||||
else if(isBSA(name))
|
||||
else if (isBSA(name))
|
||||
{
|
||||
if(!archivePath.empty() && !isBSA(archivePath))
|
||||
if (!archivePath.empty() && !isBSA(archivePath))
|
||||
{
|
||||
// std::cout << "Reading BSA File: " << name << std::endl;
|
||||
// std::cout << "Reading BSA File: " << name << std::endl;
|
||||
readVFS(std::make_unique<VFS::BsaArchive>(archivePath / name), archivePath / name);
|
||||
// std::cout << "Done with BSA File: " << name << std::endl;
|
||||
// std::cout << "Done with BSA File: " << name << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -68,7 +69,7 @@ void readVFS(std::unique_ptr<VFS::Archive>&& anArchive, const std::filesystem::p
|
||||
}
|
||||
}
|
||||
|
||||
bool parseOptions (int argc, char** argv, std::vector<Files::MaybeQuotedPath> &files)
|
||||
bool parseOptions(int argc, char** argv, std::vector<Files::MaybeQuotedPath>& files)
|
||||
{
|
||||
bpo::options_description desc(R"(Ensure that OpenMW can use the provided NIF and BSA files
|
||||
|
||||
@ -79,34 +80,32 @@ Usages:
|
||||
Allowed options)");
|
||||
auto addOption = desc.add_options();
|
||||
addOption("help,h", "print help message.");
|
||||
addOption("input-file", bpo::value< Files::MaybeQuotedPathContainer >(), "input file");
|
||||
addOption("input-file", bpo::value<Files::MaybeQuotedPathContainer>(), "input file");
|
||||
|
||||
//Default option if none provided
|
||||
// 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::parsed_options valid_opts = bpo::command_line_parser(argc, argv).options(desc).positional(p).run();
|
||||
bpo::store(valid_opts, variables);
|
||||
bpo::notify(variables);
|
||||
if (variables.count ("help"))
|
||||
if (variables.count("help"))
|
||||
{
|
||||
std::cout << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (variables.count("input-file"))
|
||||
{
|
||||
files = variables["input-file"].as< Files::MaybeQuotedPathContainer >();
|
||||
files = variables["input-file"].as<Files::MaybeQuotedPathContainer>();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch(std::exception &e)
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cout << "ERROR parsing arguments: " << e.what() << "\n\n"
|
||||
<< desc << std::endl;
|
||||
std::cout << "ERROR parsing arguments: " << e.what() << "\n\n" << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -115,42 +114,43 @@ Allowed options)");
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::vector<Files::MaybeQuotedPath> files;
|
||||
if(!parseOptions (argc, argv, files))
|
||||
if (!parseOptions(argc, argv, files))
|
||||
return 1;
|
||||
|
||||
Nif::NIFFile::setLoadUnsupportedFiles(true);
|
||||
// std::cout << "Reading Files" << std::endl;
|
||||
for(const auto& path : files)
|
||||
// std::cout << "Reading Files" << std::endl;
|
||||
for (const auto& path : files)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(isNIF(path))
|
||||
if (isNIF(path))
|
||||
{
|
||||
//std::cout << "Decoding: " << name << std::endl;
|
||||
// std::cout << "Decoding: " << name << std::endl;
|
||||
Nif::NIFFile temp_nif(Files::openConstrainedFileStream(path), path);
|
||||
}
|
||||
else if(isBSA(path))
|
||||
{
|
||||
// std::cout << "Reading BSA File: " << name << std::endl;
|
||||
}
|
||||
else if (isBSA(path))
|
||||
{
|
||||
// std::cout << "Reading BSA File: " << name << std::endl;
|
||||
readVFS(std::make_unique<VFS::BsaArchive>(path));
|
||||
}
|
||||
else if(std::filesystem::is_directory(path))
|
||||
{
|
||||
// std::cout << "Reading All Files in: " << name << std::endl;
|
||||
}
|
||||
else if (std::filesystem::is_directory(path))
|
||||
{
|
||||
// std::cout << "Reading All Files in: " << name << std::endl;
|
||||
readVFS(std::make_unique<VFS::FileSystemArchive>(path), path);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: \"" << Files::pathToUnicodeString(path) << "\" is not a nif file, bsa file, or directory!" << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: \"" << Files::pathToUnicodeString(path)
|
||||
<< "\" 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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -25,12 +25,18 @@
|
||||
|
||||
using namespace Fallback;
|
||||
|
||||
CS::Editor::Editor (int argc, char **argv)
|
||||
: mConfigVariables(readConfiguration()), mSettingsState (mCfgMgr), mDocumentManager (mCfgMgr),
|
||||
mPid(""), mLock(), mMerge (mDocumentManager),
|
||||
mIpcServerName ("org.openmw.OpenCS"), mServer(nullptr), mClientSocket(nullptr)
|
||||
CS::Editor::Editor(int argc, char** argv)
|
||||
: mConfigVariables(readConfiguration())
|
||||
, mSettingsState(mCfgMgr)
|
||||
, mDocumentManager(mCfgMgr)
|
||||
, mPid("")
|
||||
, mLock()
|
||||
, mMerge(mDocumentManager)
|
||||
, mIpcServerName("org.openmw.OpenCS")
|
||||
, mServer(nullptr)
|
||||
, mClientSocket(nullptr)
|
||||
{
|
||||
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
|
||||
std::pair<Files::PathContainer, std::vector<std::string>> config = readConfig();
|
||||
|
||||
mViewManager = new CSVDoc::ViewManager(mDocumentManager);
|
||||
if (argc > 1)
|
||||
@ -43,44 +49,42 @@ CS::Editor::Editor (int argc, char **argv)
|
||||
|
||||
mDocumentManager.setFileData(mFsStrict, config.first, config.second);
|
||||
|
||||
mNewGame.setLocalData (mLocal);
|
||||
mFileDialog.setLocalData (mLocal);
|
||||
mMerge.setLocalData (mLocal);
|
||||
mNewGame.setLocalData(mLocal);
|
||||
mFileDialog.setLocalData(mLocal);
|
||||
mMerge.setLocalData(mLocal);
|
||||
|
||||
connect (&mDocumentManager, &CSMDoc::DocumentManager::documentAdded,
|
||||
this, &Editor::documentAdded);
|
||||
connect (&mDocumentManager, &CSMDoc::DocumentManager::documentAboutToBeRemoved,
|
||||
this, &Editor::documentAboutToBeRemoved);
|
||||
connect (&mDocumentManager, &CSMDoc::DocumentManager::lastDocumentDeleted,
|
||||
this, &Editor::lastDocumentDeleted);
|
||||
connect(&mDocumentManager, &CSMDoc::DocumentManager::documentAdded, this, &Editor::documentAdded);
|
||||
connect(
|
||||
&mDocumentManager, &CSMDoc::DocumentManager::documentAboutToBeRemoved, this, &Editor::documentAboutToBeRemoved);
|
||||
connect(&mDocumentManager, &CSMDoc::DocumentManager::lastDocumentDeleted, this, &Editor::lastDocumentDeleted);
|
||||
|
||||
connect (mViewManager, &CSVDoc::ViewManager::newGameRequest, this, &Editor::createGame);
|
||||
connect (mViewManager, &CSVDoc::ViewManager::newAddonRequest, this, &Editor::createAddon);
|
||||
connect (mViewManager, &CSVDoc::ViewManager::loadDocumentRequest, this, &Editor::loadDocument);
|
||||
connect (mViewManager, &CSVDoc::ViewManager::editSettingsRequest, this, &Editor::showSettings);
|
||||
connect (mViewManager, &CSVDoc::ViewManager::mergeDocument, this, &Editor::mergeDocument);
|
||||
connect(mViewManager, &CSVDoc::ViewManager::newGameRequest, this, &Editor::createGame);
|
||||
connect(mViewManager, &CSVDoc::ViewManager::newAddonRequest, this, &Editor::createAddon);
|
||||
connect(mViewManager, &CSVDoc::ViewManager::loadDocumentRequest, this, &Editor::loadDocument);
|
||||
connect(mViewManager, &CSVDoc::ViewManager::editSettingsRequest, this, &Editor::showSettings);
|
||||
connect(mViewManager, &CSVDoc::ViewManager::mergeDocument, this, &Editor::mergeDocument);
|
||||
|
||||
connect (&mStartup, &CSVDoc::StartupDialogue::createGame, this, &Editor::createGame);
|
||||
connect (&mStartup, &CSVDoc::StartupDialogue::createAddon, this, &Editor::createAddon);
|
||||
connect (&mStartup, &CSVDoc::StartupDialogue::loadDocument, this, &Editor::loadDocument);
|
||||
connect (&mStartup, &CSVDoc::StartupDialogue::editConfig, this, &Editor::showSettings);
|
||||
connect(&mStartup, &CSVDoc::StartupDialogue::createGame, this, &Editor::createGame);
|
||||
connect(&mStartup, &CSVDoc::StartupDialogue::createAddon, this, &Editor::createAddon);
|
||||
connect(&mStartup, &CSVDoc::StartupDialogue::loadDocument, this, &Editor::loadDocument);
|
||||
connect(&mStartup, &CSVDoc::StartupDialogue::editConfig, this, &Editor::showSettings);
|
||||
|
||||
connect (&mFileDialog, &CSVDoc::FileDialog::signalOpenFiles,
|
||||
this, [this](const std::filesystem::path &savePath){ this->openFiles(savePath); });
|
||||
connect (&mFileDialog, &CSVDoc::FileDialog::signalCreateNewFile, this, &Editor::createNewFile);
|
||||
connect (&mFileDialog, &CSVDoc::FileDialog::rejected, this, &Editor::cancelFileDialog);
|
||||
connect(&mFileDialog, &CSVDoc::FileDialog::signalOpenFiles, this,
|
||||
[this](const std::filesystem::path& savePath) { this->openFiles(savePath); });
|
||||
connect(&mFileDialog, &CSVDoc::FileDialog::signalCreateNewFile, this, &Editor::createNewFile);
|
||||
connect(&mFileDialog, &CSVDoc::FileDialog::rejected, this, &Editor::cancelFileDialog);
|
||||
|
||||
connect (&mNewGame, &CSVDoc::NewGameDialogue::createRequest, this, &Editor::createNewGame);
|
||||
connect (&mNewGame, &CSVDoc::NewGameDialogue::cancelCreateGame, this, &Editor::cancelCreateGame);
|
||||
connect(&mNewGame, &CSVDoc::NewGameDialogue::createRequest, this, &Editor::createNewGame);
|
||||
connect(&mNewGame, &CSVDoc::NewGameDialogue::cancelCreateGame, this, &Editor::cancelCreateGame);
|
||||
}
|
||||
|
||||
CS::Editor::~Editor ()
|
||||
CS::Editor::~Editor()
|
||||
{
|
||||
delete mViewManager;
|
||||
|
||||
mPidFile.close();
|
||||
|
||||
if(mServer && std::filesystem::exists(mPid))
|
||||
if (mServer && std::filesystem::exists(mPid))
|
||||
std::filesystem::remove(mPid);
|
||||
}
|
||||
|
||||
@ -90,19 +94,32 @@ boost::program_options::variables_map CS::Editor::readConfiguration()
|
||||
boost::program_options::options_description desc("Syntax: openmw-cs <options>\nAllowed options");
|
||||
|
||||
auto addOption = desc.add_options();
|
||||
addOption("data", boost::program_options::value<Files::MaybeQuotedPathContainer>()->default_value(Files::MaybeQuotedPathContainer(), "data")->multitoken()->composing());
|
||||
addOption("data-local", boost::program_options::value<Files::MaybeQuotedPathContainer::value_type>()->default_value(Files::MaybeQuotedPathContainer::value_type(), ""));
|
||||
addOption("data",
|
||||
boost::program_options::value<Files::MaybeQuotedPathContainer>()
|
||||
->default_value(Files::MaybeQuotedPathContainer(), "data")
|
||||
->multitoken()
|
||||
->composing());
|
||||
addOption("data-local",
|
||||
boost::program_options::value<Files::MaybeQuotedPathContainer::value_type>()->default_value(
|
||||
Files::MaybeQuotedPathContainer::value_type(), ""));
|
||||
addOption("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false));
|
||||
addOption("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
|
||||
addOption("resources", boost::program_options::value<Files::MaybeQuotedPath>()->default_value(Files::MaybeQuotedPath(), "resources"));
|
||||
addOption("fallback-archive", boost::program_options::value<std::vector<std::string>>()->
|
||||
default_value(std::vector<std::string>(), "fallback-archive")->multitoken());
|
||||
addOption("fallback", boost::program_options::value<FallbackMap>()->default_value(FallbackMap(), "")
|
||||
->multitoken()->composing(), "fallback values");
|
||||
addOption("script-blacklist", boost::program_options::value<std::vector<std::string>>()->default_value(std::vector<std::string>(), "")
|
||||
->multitoken(), "exclude specified script from the verifier (if the use of the blacklist is enabled)");
|
||||
addOption("script-blacklist-use", boost::program_options::value<bool>()->implicit_value(true)
|
||||
->default_value(true), "enable script blacklisting");
|
||||
addOption("resources",
|
||||
boost::program_options::value<Files::MaybeQuotedPath>()->default_value(Files::MaybeQuotedPath(), "resources"));
|
||||
addOption("fallback-archive",
|
||||
boost::program_options::value<std::vector<std::string>>()
|
||||
->default_value(std::vector<std::string>(), "fallback-archive")
|
||||
->multitoken());
|
||||
addOption("fallback",
|
||||
boost::program_options::value<FallbackMap>()->default_value(FallbackMap(), "")->multitoken()->composing(),
|
||||
"fallback values");
|
||||
addOption("script-blacklist",
|
||||
boost::program_options::value<std::vector<std::string>>()
|
||||
->default_value(std::vector<std::string>(), "")
|
||||
->multitoken(),
|
||||
"exclude specified script from the verifier (if the use of the blacklist is enabled)");
|
||||
addOption("script-blacklist-use", boost::program_options::value<bool>()->implicit_value(true)->default_value(true),
|
||||
"enable script blacklisting");
|
||||
Files::ConfigurationManager::addCommonOptions(desc);
|
||||
|
||||
boost::program_options::notify(variables);
|
||||
@ -114,7 +131,7 @@ boost::program_options::variables_map CS::Editor::readConfiguration()
|
||||
return variables;
|
||||
}
|
||||
|
||||
std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfig(bool quiet)
|
||||
std::pair<Files::PathContainer, std::vector<std::string>> CS::Editor::readConfig(bool quiet)
|
||||
{
|
||||
boost::program_options::variables_map& variables = mConfigVariables;
|
||||
|
||||
@ -122,22 +139,28 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
|
||||
|
||||
mEncodingName = variables["encoding"].as<std::string>();
|
||||
mDocumentManager.setEncoding(ToUTF8::calculateEncoding(mEncodingName));
|
||||
mFileDialog.setEncoding (QString::fromUtf8(mEncodingName.c_str()));
|
||||
mFileDialog.setEncoding(QString::fromUtf8(mEncodingName.c_str()));
|
||||
|
||||
mDocumentManager.setResourceDir (mResources = variables["resources"].as<Files::MaybeQuotedPath>().u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
|
||||
mDocumentManager.setResourceDir(mResources = variables["resources"]
|
||||
.as<Files::MaybeQuotedPath>()
|
||||
.u8string()); // This call to u8string is redundant, but required
|
||||
// to build on MSVC 14.26 due to implementation bugs.
|
||||
|
||||
if (variables["script-blacklist-use"].as<bool>())
|
||||
mDocumentManager.setBlacklistedScripts (
|
||||
variables["script-blacklist"].as<std::vector<std::string>>());
|
||||
mDocumentManager.setBlacklistedScripts(variables["script-blacklist"].as<std::vector<std::string>>());
|
||||
|
||||
mFsStrict = variables["fs-strict"].as<bool>();
|
||||
|
||||
Files::PathContainer dataDirs, dataLocal;
|
||||
if (!variables["data"].empty()) {
|
||||
if (!variables["data"].empty())
|
||||
{
|
||||
dataDirs = asPathContainer(variables["data"].as<Files::MaybeQuotedPathContainer>());
|
||||
}
|
||||
|
||||
Files::PathContainer::value_type local(variables["data-local"].as<Files::MaybeQuotedPathContainer::value_type>().u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs.
|
||||
Files::PathContainer::value_type local(variables["data-local"]
|
||||
.as<Files::MaybeQuotedPathContainer::value_type>()
|
||||
.u8string()); // This call to u8string is redundant, but required to
|
||||
// build on MSVC 14.26 due to implementation bugs.
|
||||
if (!local.empty())
|
||||
{
|
||||
std::filesystem::create_directories(local);
|
||||
@ -151,21 +174,23 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
|
||||
else
|
||||
{
|
||||
QMessageBox messageBox;
|
||||
messageBox.setWindowTitle (tr ("No local data path available"));
|
||||
messageBox.setIcon (QMessageBox::Critical);
|
||||
messageBox.setStandardButtons (QMessageBox::Ok);
|
||||
messageBox.setText(tr("<br><b>OpenCS is unable to access the local data directory. This may indicate a faulty configuration or a broken install.</b>"));
|
||||
messageBox.setWindowTitle(tr("No local data path available"));
|
||||
messageBox.setIcon(QMessageBox::Critical);
|
||||
messageBox.setStandardButtons(QMessageBox::Ok);
|
||||
messageBox.setText(
|
||||
tr("<br><b>OpenCS is unable to access the local data directory. This may indicate a faulty configuration "
|
||||
"or a broken install.</b>"));
|
||||
messageBox.exec();
|
||||
|
||||
QApplication::exit (1);
|
||||
QApplication::exit(1);
|
||||
}
|
||||
|
||||
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
|
||||
dataDirs.insert(dataDirs.end(), dataLocal.begin(), dataLocal.end());
|
||||
|
||||
//iterate the data directories and add them to the file dialog for loading
|
||||
// iterate the data directories and add them to the file dialog for loading
|
||||
mFileDialog.addFiles(dataDirs);
|
||||
|
||||
return std::make_pair (dataDirs, variables["fallback-archive"].as<std::vector<std::string>>());
|
||||
return std::make_pair(dataDirs, variables["fallback-archive"].as<std::vector<std::string>>());
|
||||
}
|
||||
|
||||
void CS::Editor::createGame()
|
||||
@ -198,9 +223,9 @@ void CS::Editor::createAddon()
|
||||
mStartup.hide();
|
||||
|
||||
mFileDialog.clearFiles();
|
||||
readConfig(/*quiet*/true);
|
||||
readConfig(/*quiet*/ true);
|
||||
|
||||
mFileDialog.showDialog (CSVDoc::ContentAction_New);
|
||||
mFileDialog.showDialog(CSVDoc::ContentAction_New);
|
||||
}
|
||||
|
||||
void CS::Editor::cancelFileDialog()
|
||||
@ -222,18 +247,20 @@ void CS::Editor::loadDocument()
|
||||
mStartup.hide();
|
||||
|
||||
mFileDialog.clearFiles();
|
||||
readConfig(/*quiet*/true);
|
||||
readConfig(/*quiet*/ true);
|
||||
|
||||
mFileDialog.showDialog (CSVDoc::ContentAction_Edit);
|
||||
mFileDialog.showDialog(CSVDoc::ContentAction_Edit);
|
||||
}
|
||||
|
||||
void CS::Editor::openFiles (const std::filesystem::path &savePath, const std::vector<std::filesystem::path> &discoveredFiles)
|
||||
void CS::Editor::openFiles(
|
||||
const std::filesystem::path& savePath, const std::vector<std::filesystem::path>& discoveredFiles)
|
||||
{
|
||||
std::vector<std::filesystem::path> files;
|
||||
|
||||
if(discoveredFiles.empty())
|
||||
if (discoveredFiles.empty())
|
||||
{
|
||||
for (const QString &path : mFileDialog.selectedFilePaths()) {
|
||||
for (const QString& path : mFileDialog.selectedFilePaths())
|
||||
{
|
||||
files.emplace_back(Files::pathFromQString(path));
|
||||
}
|
||||
}
|
||||
@ -242,40 +269,41 @@ void CS::Editor::openFiles (const std::filesystem::path &savePath, const std::ve
|
||||
files = discoveredFiles;
|
||||
}
|
||||
|
||||
mDocumentManager.addDocument (files, savePath, false);
|
||||
mDocumentManager.addDocument(files, savePath, false);
|
||||
|
||||
mFileDialog.hide();
|
||||
}
|
||||
|
||||
void CS::Editor::createNewFile (const std::filesystem::path &savePath)
|
||||
void CS::Editor::createNewFile(const std::filesystem::path& savePath)
|
||||
{
|
||||
std::vector<std::filesystem::path> files;
|
||||
|
||||
for (const QString &path : mFileDialog.selectedFilePaths()) {
|
||||
for (const QString& path : mFileDialog.selectedFilePaths())
|
||||
{
|
||||
files.emplace_back(Files::pathFromQString(path));
|
||||
}
|
||||
|
||||
files.push_back (savePath);
|
||||
files.push_back(savePath);
|
||||
|
||||
mDocumentManager.addDocument (files, savePath, true);
|
||||
mDocumentManager.addDocument(files, savePath, true);
|
||||
|
||||
mFileDialog.hide();
|
||||
}
|
||||
|
||||
void CS::Editor::createNewGame (const std::filesystem::path& file)
|
||||
void CS::Editor::createNewGame(const std::filesystem::path& file)
|
||||
{
|
||||
std::vector<std::filesystem::path> files;
|
||||
|
||||
files.push_back (file);
|
||||
files.push_back(file);
|
||||
|
||||
mDocumentManager.addDocument (files, file, true);
|
||||
mDocumentManager.addDocument(files, file, true);
|
||||
|
||||
mNewGame.hide();
|
||||
}
|
||||
|
||||
void CS::Editor::showStartup()
|
||||
{
|
||||
if(mStartup.isHidden())
|
||||
if (mStartup.isHidden())
|
||||
mStartup.show();
|
||||
mStartup.raise();
|
||||
mStartup.activateWindow();
|
||||
@ -286,7 +314,7 @@ void CS::Editor::showSettings()
|
||||
if (mSettings.isHidden())
|
||||
mSettings.show();
|
||||
|
||||
mSettings.move (QCursor::pos());
|
||||
mSettings.move(QCursor::pos());
|
||||
mSettings.raise();
|
||||
mSettings.activateWindow();
|
||||
}
|
||||
@ -302,7 +330,7 @@ bool CS::Editor::makeIPCServer()
|
||||
mPidFile.open(mPid);
|
||||
|
||||
mLock = boost::interprocess::file_lock(mPid.c_str());
|
||||
if(!mLock.try_lock())
|
||||
if (!mLock.try_lock())
|
||||
{
|
||||
Log(Debug::Error) << "Error: OpenMW-CS is already running.";
|
||||
return false;
|
||||
@ -316,7 +344,7 @@ bool CS::Editor::makeIPCServer()
|
||||
|
||||
mServer = new QLocalServer(this);
|
||||
|
||||
if(pidExists)
|
||||
if (pidExists)
|
||||
{
|
||||
// hack to get the temp directory path
|
||||
mServer->listen("dummy");
|
||||
@ -325,24 +353,24 @@ bool CS::Editor::makeIPCServer()
|
||||
fullPath.remove(QRegExp("dummy$"));
|
||||
fullPath += mIpcServerName;
|
||||
const auto path = Files::pathFromQString(fullPath);
|
||||
if(exists(path))
|
||||
if (exists(path))
|
||||
{
|
||||
// TODO: compare pid of the current process with that in the file
|
||||
Log(Debug::Info) << "Detected unclean shutdown.";
|
||||
// delete the stale file
|
||||
if(remove(path))
|
||||
if (remove(path))
|
||||
Log(Debug::Error) << "Error: can not remove stale connection file.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Log(Debug::Error) << "Error: " << e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(mServer->listen(mIpcServerName))
|
||||
if (mServer->listen(mIpcServerName))
|
||||
{
|
||||
connect(mServer, &QLocalServer::newConnection, this, &Editor::showStartup);
|
||||
return true;
|
||||
@ -415,14 +443,14 @@ int CS::Editor::run()
|
||||
return QApplication::exec();
|
||||
}
|
||||
|
||||
void CS::Editor::documentAdded (CSMDoc::Document *document)
|
||||
void CS::Editor::documentAdded(CSMDoc::Document* document)
|
||||
{
|
||||
mViewManager->addView (document);
|
||||
mViewManager->addView(document);
|
||||
}
|
||||
|
||||
void CS::Editor::documentAboutToBeRemoved (CSMDoc::Document *document)
|
||||
void CS::Editor::documentAboutToBeRemoved(CSMDoc::Document* document)
|
||||
{
|
||||
if (mMerge.getDocument()==document)
|
||||
if (mMerge.getDocument() == document)
|
||||
mMerge.cancel();
|
||||
}
|
||||
|
||||
@ -431,9 +459,9 @@ void CS::Editor::lastDocumentDeleted()
|
||||
QApplication::quit();
|
||||
}
|
||||
|
||||
void CS::Editor::mergeDocument (CSMDoc::Document *document)
|
||||
void CS::Editor::mergeDocument(CSMDoc::Document* document)
|
||||
{
|
||||
mMerge.configure (document);
|
||||
mMerge.configure(document);
|
||||
mMerge.show();
|
||||
mMerge.raise();
|
||||
mMerge.activateWindow();
|
||||
|
@ -6,10 +6,10 @@
|
||||
#include <boost/interprocess/sync/file_lock.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QLocalServer>
|
||||
#include <QLocalSocket>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#ifndef Q_MOC_RUN
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
@ -21,10 +21,10 @@
|
||||
|
||||
#include "model/prefs/state.hpp"
|
||||
|
||||
#include "view/doc/viewmanager.hpp"
|
||||
#include "view/doc/startup.hpp"
|
||||
#include "view/doc/filedialog.hpp"
|
||||
#include "view/doc/newgame.hpp"
|
||||
#include "view/doc/startup.hpp"
|
||||
#include "view/doc/viewmanager.hpp"
|
||||
|
||||
#include "view/prefs/dialogue.hpp"
|
||||
|
||||
@ -39,77 +39,77 @@ namespace CS
|
||||
{
|
||||
class Editor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
Files::ConfigurationManager mCfgMgr;
|
||||
boost::program_options::variables_map mConfigVariables;
|
||||
CSMPrefs::State mSettingsState;
|
||||
CSMDoc::DocumentManager mDocumentManager;
|
||||
CSVDoc::StartupDialogue mStartup;
|
||||
CSVDoc::NewGameDialogue mNewGame;
|
||||
CSVPrefs::Dialogue mSettings;
|
||||
CSVDoc::FileDialog mFileDialog;
|
||||
std::filesystem::path mLocal;
|
||||
std::filesystem::path mResources;
|
||||
std::filesystem::path mPid;
|
||||
boost::interprocess::file_lock mLock;
|
||||
std::ofstream mPidFile;
|
||||
bool mFsStrict;
|
||||
CSVTools::Merge mMerge;
|
||||
CSVDoc::ViewManager* mViewManager;
|
||||
std::filesystem::path mFileToLoad;
|
||||
Files::PathContainer mDataDirs;
|
||||
std::string mEncodingName;
|
||||
Files::ConfigurationManager mCfgMgr;
|
||||
boost::program_options::variables_map mConfigVariables;
|
||||
CSMPrefs::State mSettingsState;
|
||||
CSMDoc::DocumentManager mDocumentManager;
|
||||
CSVDoc::StartupDialogue mStartup;
|
||||
CSVDoc::NewGameDialogue mNewGame;
|
||||
CSVPrefs::Dialogue mSettings;
|
||||
CSVDoc::FileDialog mFileDialog;
|
||||
std::filesystem::path mLocal;
|
||||
std::filesystem::path mResources;
|
||||
std::filesystem::path mPid;
|
||||
boost::interprocess::file_lock mLock;
|
||||
std::ofstream mPidFile;
|
||||
bool mFsStrict;
|
||||
CSVTools::Merge mMerge;
|
||||
CSVDoc::ViewManager* mViewManager;
|
||||
std::filesystem::path mFileToLoad;
|
||||
Files::PathContainer mDataDirs;
|
||||
std::string mEncodingName;
|
||||
|
||||
boost::program_options::variables_map readConfiguration();
|
||||
///< Calls mCfgMgr.readConfiguration; should be used before initialization of mSettingsState as it depends on the configuration.
|
||||
std::pair<Files::PathContainer, std::vector<std::string> > readConfig(bool quiet=false);
|
||||
///< \return data paths
|
||||
boost::program_options::variables_map readConfiguration();
|
||||
///< Calls mCfgMgr.readConfiguration; should be used before initialization of mSettingsState as it depends on
|
||||
///< the configuration.
|
||||
std::pair<Files::PathContainer, std::vector<std::string>> readConfig(bool quiet = false);
|
||||
///< \return data paths
|
||||
|
||||
// not implemented
|
||||
Editor (const Editor&);
|
||||
Editor& operator= (const Editor&);
|
||||
// not implemented
|
||||
Editor(const Editor&);
|
||||
Editor& operator=(const Editor&);
|
||||
|
||||
public:
|
||||
public:
|
||||
Editor(int argc, char** argv);
|
||||
~Editor();
|
||||
|
||||
Editor (int argc, char **argv);
|
||||
~Editor ();
|
||||
bool makeIPCServer();
|
||||
void connectToIPCServer();
|
||||
|
||||
bool makeIPCServer();
|
||||
void connectToIPCServer();
|
||||
int run();
|
||||
///< \return error status
|
||||
|
||||
int run();
|
||||
///< \return error status
|
||||
private slots:
|
||||
|
||||
private slots:
|
||||
void createGame();
|
||||
void createAddon();
|
||||
void cancelCreateGame();
|
||||
void cancelFileDialog();
|
||||
|
||||
void createGame();
|
||||
void createAddon();
|
||||
void cancelCreateGame();
|
||||
void cancelFileDialog();
|
||||
void loadDocument();
|
||||
void openFiles(
|
||||
const std::filesystem::path& path, const std::vector<std::filesystem::path>& discoveredFiles = {});
|
||||
void createNewFile(const std::filesystem::path& path);
|
||||
void createNewGame(const std::filesystem::path& file);
|
||||
|
||||
void loadDocument();
|
||||
void openFiles (const std::filesystem::path &path, const std::vector<std::filesystem::path> &discoveredFiles = {});
|
||||
void createNewFile (const std::filesystem::path& path);
|
||||
void createNewGame (const std::filesystem::path& file);
|
||||
void showStartup();
|
||||
|
||||
void showStartup();
|
||||
void showSettings();
|
||||
|
||||
void showSettings();
|
||||
void documentAdded(CSMDoc::Document* document);
|
||||
|
||||
void documentAdded (CSMDoc::Document *document);
|
||||
void documentAboutToBeRemoved(CSMDoc::Document* document);
|
||||
|
||||
void documentAboutToBeRemoved (CSMDoc::Document *document);
|
||||
void lastDocumentDeleted();
|
||||
|
||||
void lastDocumentDeleted();
|
||||
void mergeDocument(CSMDoc::Document* document);
|
||||
|
||||
void mergeDocument (CSMDoc::Document *document);
|
||||
|
||||
private:
|
||||
|
||||
QString mIpcServerName;
|
||||
QLocalServer *mServer;
|
||||
QLocalSocket *mClientSocket;
|
||||
private:
|
||||
QString mIpcServerName;
|
||||
QLocalServer* mServer;
|
||||
QLocalSocket* mClientSocket;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -16,32 +16,33 @@
|
||||
#include <QDir>
|
||||
#endif
|
||||
|
||||
Q_DECLARE_METATYPE (std::string)
|
||||
Q_DECLARE_METATYPE(std::string)
|
||||
|
||||
class Application : public QApplication
|
||||
{
|
||||
private:
|
||||
|
||||
bool notify (QObject *receiver, QEvent *event) override
|
||||
private:
|
||||
bool notify(QObject* receiver, QEvent* event) override
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
return QApplication::notify (receiver, event);
|
||||
}
|
||||
catch (const std::exception& exception)
|
||||
{
|
||||
Log(Debug::Error) << "An exception has been caught: " << exception.what();
|
||||
}
|
||||
|
||||
return false;
|
||||
return QApplication::notify(receiver, event);
|
||||
}
|
||||
catch (const std::exception& exception)
|
||||
{
|
||||
Log(Debug::Error) << "An exception has been caught: " << exception.what();
|
||||
}
|
||||
|
||||
public:
|
||||
return false;
|
||||
}
|
||||
|
||||
Application (int& argc, char *argv[]) : QApplication (argc, argv) {}
|
||||
public:
|
||||
Application(int& argc, char* argv[])
|
||||
: QApplication(argc, argv)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
int runApplication(int argc, char *argv[])
|
||||
int runApplication(int argc, char* argv[])
|
||||
{
|
||||
Platform::init();
|
||||
|
||||
@ -49,27 +50,27 @@ int runApplication(int argc, char *argv[])
|
||||
setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0);
|
||||
#endif
|
||||
|
||||
Q_INIT_RESOURCE (resources);
|
||||
Q_INIT_RESOURCE(resources);
|
||||
|
||||
qRegisterMetaType<std::string> ("std::string");
|
||||
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
|
||||
qRegisterMetaType<CSMDoc::Message> ("CSMDoc::Message");
|
||||
qRegisterMetaType<std::string>("std::string");
|
||||
qRegisterMetaType<CSMWorld::UniversalId>("CSMWorld::UniversalId");
|
||||
qRegisterMetaType<CSMDoc::Message>("CSMDoc::Message");
|
||||
|
||||
Application application (argc, argv);
|
||||
Application application(argc, argv);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
QDir::setCurrent(dir.absolutePath());
|
||||
#endif
|
||||
|
||||
application.setWindowIcon (QIcon (":./openmw-cs.png"));
|
||||
application.setWindowIcon(QIcon(":./openmw-cs.png"));
|
||||
|
||||
CS::Editor editor(argc, argv);
|
||||
#ifdef __linux__
|
||||
setlocale(LC_NUMERIC,"C");
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
#endif
|
||||
|
||||
if(!editor.makeIPCServer())
|
||||
if (!editor.makeIPCServer())
|
||||
{
|
||||
editor.connectToIPCServer();
|
||||
return 0;
|
||||
@ -78,8 +79,7 @@ int runApplication(int argc, char *argv[])
|
||||
return editor.run();
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
return wrapApplication(&runApplication, argc, argv, "OpenMW-CS", false);
|
||||
}
|
||||
|
@ -4,27 +4,25 @@
|
||||
|
||||
#include <components/misc/strings/lower.hpp>
|
||||
|
||||
bool CSMDoc::Blacklist::isBlacklisted (const CSMWorld::UniversalId& id) const
|
||||
bool CSMDoc::Blacklist::isBlacklisted(const CSMWorld::UniversalId& id) const
|
||||
{
|
||||
std::map<CSMWorld::UniversalId::Type, std::vector<std::string> >::const_iterator iter =
|
||||
mIds.find (id.getType());
|
||||
std::map<CSMWorld::UniversalId::Type, std::vector<std::string>>::const_iterator iter = mIds.find(id.getType());
|
||||
|
||||
if (iter==mIds.end())
|
||||
if (iter == mIds.end())
|
||||
return false;
|
||||
|
||||
return std::binary_search (iter->second.begin(), iter->second.end(),
|
||||
Misc::StringUtils::lowerCase (id.getId()));
|
||||
return std::binary_search(iter->second.begin(), iter->second.end(), Misc::StringUtils::lowerCase(id.getId()));
|
||||
}
|
||||
|
||||
void CSMDoc::Blacklist::add (CSMWorld::UniversalId::Type type,
|
||||
const std::vector<std::string>& ids)
|
||||
void CSMDoc::Blacklist::add(CSMWorld::UniversalId::Type type, const std::vector<std::string>& ids)
|
||||
{
|
||||
std::vector<std::string>& list = mIds[type];
|
||||
|
||||
size_t size = list.size();
|
||||
|
||||
list.resize (size+ids.size());
|
||||
list.resize(size + ids.size());
|
||||
|
||||
std::transform (ids.begin(), ids.end(), list.begin()+size, [](const std::string& s) { return Misc::StringUtils::lowerCase(s); } );
|
||||
std::sort (list.begin(), list.end());
|
||||
std::transform(ids.begin(), ids.end(), list.begin() + size,
|
||||
[](const std::string& s) { return Misc::StringUtils::lowerCase(s); });
|
||||
std::sort(list.begin(), list.end());
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
#define CSM_DOC_BLACKLIST_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
@ -12,13 +12,12 @@ namespace CSMDoc
|
||||
/// \brief ID blacklist sorted by UniversalId type
|
||||
class Blacklist
|
||||
{
|
||||
std::map<CSMWorld::UniversalId::Type, std::vector<std::string> > mIds;
|
||||
std::map<CSMWorld::UniversalId::Type, std::vector<std::string>> mIds;
|
||||
|
||||
public:
|
||||
public:
|
||||
bool isBlacklisted(const CSMWorld::UniversalId& id) const;
|
||||
|
||||
bool isBlacklisted (const CSMWorld::UniversalId& id) const;
|
||||
|
||||
void add (CSMWorld::UniversalId::Type type, const std::vector<std::string>& ids);
|
||||
void add(CSMWorld::UniversalId::Type type, const std::vector<std::string>& ids);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
#include "state.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "../world/defaultgmsts.hpp"
|
||||
@ -18,142 +18,140 @@
|
||||
|
||||
void CSMDoc::Document::addGmsts()
|
||||
{
|
||||
for (size_t i=0; i < CSMWorld::DefaultGmsts::FloatCount; ++i)
|
||||
for (size_t i = 0; i < CSMWorld::DefaultGmsts::FloatCount; ++i)
|
||||
{
|
||||
ESM::GameSetting gmst;
|
||||
gmst.mId = CSMWorld::DefaultGmsts::Floats[i];
|
||||
gmst.mValue.setType (ESM::VT_Float);
|
||||
gmst.mValue.setType(ESM::VT_Float);
|
||||
gmst.mRecordFlags = 0;
|
||||
gmst.mValue.setFloat (CSMWorld::DefaultGmsts::FloatsDefaultValues[i]);
|
||||
getData().getGmsts().add (gmst);
|
||||
gmst.mValue.setFloat(CSMWorld::DefaultGmsts::FloatsDefaultValues[i]);
|
||||
getData().getGmsts().add(gmst);
|
||||
}
|
||||
|
||||
for (size_t i=0; i < CSMWorld::DefaultGmsts::IntCount; ++i)
|
||||
for (size_t i = 0; i < CSMWorld::DefaultGmsts::IntCount; ++i)
|
||||
{
|
||||
ESM::GameSetting gmst;
|
||||
gmst.mId = CSMWorld::DefaultGmsts::Ints[i];
|
||||
gmst.mValue.setType (ESM::VT_Int);
|
||||
gmst.mValue.setType(ESM::VT_Int);
|
||||
gmst.mRecordFlags = 0;
|
||||
gmst.mValue.setInteger (CSMWorld::DefaultGmsts::IntsDefaultValues[i]);
|
||||
getData().getGmsts().add (gmst);
|
||||
gmst.mValue.setInteger(CSMWorld::DefaultGmsts::IntsDefaultValues[i]);
|
||||
getData().getGmsts().add(gmst);
|
||||
}
|
||||
|
||||
for (size_t i=0; i < CSMWorld::DefaultGmsts::StringCount; ++i)
|
||||
for (size_t i = 0; i < CSMWorld::DefaultGmsts::StringCount; ++i)
|
||||
{
|
||||
ESM::GameSetting gmst;
|
||||
gmst.mId = CSMWorld::DefaultGmsts::Strings[i];
|
||||
gmst.mValue.setType (ESM::VT_String);
|
||||
gmst.mValue.setType(ESM::VT_String);
|
||||
gmst.mRecordFlags = 0;
|
||||
gmst.mValue.setString ("");
|
||||
getData().getGmsts().add (gmst);
|
||||
gmst.mValue.setString("");
|
||||
getData().getGmsts().add(gmst);
|
||||
}
|
||||
}
|
||||
|
||||
void CSMDoc::Document::addOptionalGmsts()
|
||||
{
|
||||
for (size_t i=0; i < CSMWorld::DefaultGmsts::OptionalFloatCount; ++i)
|
||||
for (size_t i = 0; i < CSMWorld::DefaultGmsts::OptionalFloatCount; ++i)
|
||||
{
|
||||
ESM::GameSetting gmst;
|
||||
gmst.mId = CSMWorld::DefaultGmsts::OptionalFloats[i];
|
||||
gmst.blank();
|
||||
gmst.mValue.setType (ESM::VT_Float);
|
||||
addOptionalGmst (gmst);
|
||||
gmst.mValue.setType(ESM::VT_Float);
|
||||
addOptionalGmst(gmst);
|
||||
}
|
||||
|
||||
for (size_t i=0; i < CSMWorld::DefaultGmsts::OptionalIntCount; ++i)
|
||||
for (size_t i = 0; i < CSMWorld::DefaultGmsts::OptionalIntCount; ++i)
|
||||
{
|
||||
ESM::GameSetting gmst;
|
||||
gmst.mId = CSMWorld::DefaultGmsts::OptionalInts[i];
|
||||
gmst.blank();
|
||||
gmst.mValue.setType (ESM::VT_Int);
|
||||
addOptionalGmst (gmst);
|
||||
gmst.mValue.setType(ESM::VT_Int);
|
||||
addOptionalGmst(gmst);
|
||||
}
|
||||
|
||||
for (size_t i=0; i < CSMWorld::DefaultGmsts::OptionalStringCount; ++i)
|
||||
for (size_t i = 0; i < CSMWorld::DefaultGmsts::OptionalStringCount; ++i)
|
||||
{
|
||||
ESM::GameSetting gmst;
|
||||
gmst.mId = CSMWorld::DefaultGmsts::OptionalStrings[i];
|
||||
gmst.blank();
|
||||
gmst.mValue.setType (ESM::VT_String);
|
||||
gmst.mValue.setString ("<no text>");
|
||||
addOptionalGmst (gmst);
|
||||
gmst.mValue.setType(ESM::VT_String);
|
||||
gmst.mValue.setString("<no text>");
|
||||
addOptionalGmst(gmst);
|
||||
}
|
||||
}
|
||||
|
||||
void CSMDoc::Document::addOptionalGlobals()
|
||||
{
|
||||
static const char *sGlobals[] =
|
||||
{
|
||||
static const char* sGlobals[] = {
|
||||
"DaysPassed",
|
||||
"PCWerewolf",
|
||||
"PCYear",
|
||||
nullptr,
|
||||
};
|
||||
|
||||
for (int i=0; sGlobals[i]; ++i)
|
||||
for (int i = 0; sGlobals[i]; ++i)
|
||||
{
|
||||
ESM::Global global;
|
||||
global.mId = sGlobals[i];
|
||||
global.blank();
|
||||
global.mValue.setType (ESM::VT_Long);
|
||||
global.mValue.setType(ESM::VT_Long);
|
||||
|
||||
if (i==0)
|
||||
global.mValue.setInteger (1); // dayspassed starts counting at 1
|
||||
if (i == 0)
|
||||
global.mValue.setInteger(1); // dayspassed starts counting at 1
|
||||
|
||||
addOptionalGlobal (global);
|
||||
addOptionalGlobal(global);
|
||||
}
|
||||
}
|
||||
|
||||
void CSMDoc::Document::addOptionalMagicEffects()
|
||||
{
|
||||
for (int i=ESM::MagicEffect::SummonFabricant; i<=ESM::MagicEffect::SummonCreature05; ++i)
|
||||
for (int i = ESM::MagicEffect::SummonFabricant; i <= ESM::MagicEffect::SummonCreature05; ++i)
|
||||
{
|
||||
ESM::MagicEffect effect;
|
||||
effect.mIndex = i;
|
||||
effect.mId = ESM::MagicEffect::indexToId (i);
|
||||
effect.mId = ESM::MagicEffect::indexToId(i);
|
||||
effect.blank();
|
||||
|
||||
addOptionalMagicEffect (effect);
|
||||
addOptionalMagicEffect(effect);
|
||||
}
|
||||
}
|
||||
|
||||
void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst)
|
||||
void CSMDoc::Document::addOptionalGmst(const ESM::GameSetting& gmst)
|
||||
{
|
||||
if (getData().getGmsts().searchId (gmst.mId)==-1)
|
||||
if (getData().getGmsts().searchId(gmst.mId) == -1)
|
||||
{
|
||||
auto record = std::make_unique<CSMWorld::Record<ESM::GameSetting>>();
|
||||
record->mBase = gmst;
|
||||
record->mState = CSMWorld::RecordBase::State_BaseOnly;
|
||||
getData().getGmsts().appendRecord (std::move(record));
|
||||
getData().getGmsts().appendRecord(std::move(record));
|
||||
}
|
||||
}
|
||||
|
||||
void CSMDoc::Document::addOptionalGlobal (const ESM::Global& global)
|
||||
void CSMDoc::Document::addOptionalGlobal(const ESM::Global& global)
|
||||
{
|
||||
if (getData().getGlobals().searchId (global.mId)==-1)
|
||||
if (getData().getGlobals().searchId(global.mId) == -1)
|
||||
{
|
||||
auto record = std::make_unique<CSMWorld::Record<ESM::Global>>();
|
||||
record->mBase = global;
|
||||
record->mState = CSMWorld::RecordBase::State_BaseOnly;
|
||||
getData().getGlobals().appendRecord (std::move(record));
|
||||
getData().getGlobals().appendRecord(std::move(record));
|
||||
}
|
||||
}
|
||||
|
||||
void CSMDoc::Document::addOptionalMagicEffect (const ESM::MagicEffect& magicEffect)
|
||||
void CSMDoc::Document::addOptionalMagicEffect(const ESM::MagicEffect& magicEffect)
|
||||
{
|
||||
if (getData().getMagicEffects().searchId (magicEffect.mId)==-1)
|
||||
if (getData().getMagicEffects().searchId(magicEffect.mId) == -1)
|
||||
{
|
||||
auto record = std::make_unique<CSMWorld::Record<ESM::MagicEffect>>();
|
||||
record->mBase = magicEffect;
|
||||
record->mState = CSMWorld::RecordBase::State_BaseOnly;
|
||||
getData().getMagicEffects().appendRecord (std::move(record));
|
||||
getData().getMagicEffects().appendRecord(std::move(record));
|
||||
}
|
||||
}
|
||||
|
||||
void CSMDoc::Document::createBase()
|
||||
{
|
||||
static const char *sGlobals[] =
|
||||
{
|
||||
static const char* sGlobals[] = {
|
||||
"Day",
|
||||
"DaysPassed",
|
||||
"GameHour",
|
||||
@ -165,33 +163,32 @@ void CSMDoc::Document::createBase()
|
||||
nullptr,
|
||||
};
|
||||
|
||||
for (int i=0; sGlobals[i]; ++i)
|
||||
for (int i = 0; sGlobals[i]; ++i)
|
||||
{
|
||||
ESM::Global record;
|
||||
record.mId = sGlobals[i];
|
||||
record.mRecordFlags = 0;
|
||||
record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Long);
|
||||
record.mValue.setType(i == 2 ? ESM::VT_Float : ESM::VT_Long);
|
||||
|
||||
if (i==0 || i==1)
|
||||
record.mValue.setInteger (1);
|
||||
if (i == 0 || i == 1)
|
||||
record.mValue.setInteger(1);
|
||||
|
||||
getData().getGlobals().add (record);
|
||||
getData().getGlobals().add(record);
|
||||
}
|
||||
|
||||
addGmsts();
|
||||
|
||||
for (int i=0; i<27; ++i)
|
||||
for (int i = 0; i < 27; ++i)
|
||||
{
|
||||
ESM::Skill record;
|
||||
record.mIndex = i;
|
||||
record.mId = ESM::Skill::indexToId (record.mIndex);
|
||||
record.mId = ESM::Skill::indexToId(record.mIndex);
|
||||
record.blank();
|
||||
|
||||
getData().getSkills().add (record);
|
||||
getData().getSkills().add(record);
|
||||
}
|
||||
|
||||
static const char *sVoice[] =
|
||||
{
|
||||
static const char* sVoice[] = {
|
||||
"Intruder",
|
||||
"Attack",
|
||||
"Hello",
|
||||
@ -203,18 +200,17 @@ void CSMDoc::Document::createBase()
|
||||
nullptr,
|
||||
};
|
||||
|
||||
for (int i=0; sVoice[i]; ++i)
|
||||
for (int i = 0; sVoice[i]; ++i)
|
||||
{
|
||||
ESM::Dialogue record;
|
||||
record.mId = sVoice[i];
|
||||
record.mType = ESM::Dialogue::Voice;
|
||||
record.blank();
|
||||
|
||||
getData().getTopics().add (record);
|
||||
getData().getTopics().add(record);
|
||||
}
|
||||
|
||||
static const char *sGreetings[] =
|
||||
{
|
||||
static const char* sGreetings[] = {
|
||||
"Greeting 0",
|
||||
"Greeting 1",
|
||||
"Greeting 2",
|
||||
@ -228,18 +224,17 @@ void CSMDoc::Document::createBase()
|
||||
nullptr,
|
||||
};
|
||||
|
||||
for (int i=0; sGreetings[i]; ++i)
|
||||
for (int i = 0; sGreetings[i]; ++i)
|
||||
{
|
||||
ESM::Dialogue record;
|
||||
record.mId = sGreetings[i];
|
||||
record.mType = ESM::Dialogue::Greeting;
|
||||
record.blank();
|
||||
|
||||
getData().getTopics().add (record);
|
||||
getData().getTopics().add(record);
|
||||
}
|
||||
|
||||
static const char *sPersuasion[] =
|
||||
{
|
||||
static const char* sPersuasion[] = {
|
||||
"Intimidate Success",
|
||||
"Intimidate Fail",
|
||||
"Service Refusal",
|
||||
@ -253,47 +248,50 @@ void CSMDoc::Document::createBase()
|
||||
nullptr,
|
||||
};
|
||||
|
||||
for (int i=0; sPersuasion[i]; ++i)
|
||||
for (int i = 0; sPersuasion[i]; ++i)
|
||||
{
|
||||
ESM::Dialogue record;
|
||||
record.mId = sPersuasion[i];
|
||||
record.mType = ESM::Dialogue::Persuasion;
|
||||
record.blank();
|
||||
|
||||
getData().getTopics().add (record);
|
||||
getData().getTopics().add(record);
|
||||
}
|
||||
|
||||
for (int i=0; i<ESM::MagicEffect::Length; ++i)
|
||||
for (int i = 0; i < ESM::MagicEffect::Length; ++i)
|
||||
{
|
||||
ESM::MagicEffect record;
|
||||
|
||||
record.mIndex = i;
|
||||
record.mId = ESM::MagicEffect::indexToId (i);
|
||||
record.mId = ESM::MagicEffect::indexToId(i);
|
||||
|
||||
record.blank();
|
||||
|
||||
getData().getMagicEffects().add (record);
|
||||
getData().getMagicEffects().add(record);
|
||||
}
|
||||
}
|
||||
|
||||
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
|
||||
std::vector< std::filesystem::path > files,bool new_,
|
||||
const std::filesystem::path& savePath, const std::filesystem::path& resDir,
|
||||
ToUTF8::FromType encoding, const std::vector<std::string>& blacklistedScripts,
|
||||
bool fsStrict, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives)
|
||||
: mSavePath (savePath), mContentFiles (std::move(files)), mNew (new_), mData (encoding, fsStrict, dataPaths, archives, resDir),
|
||||
mTools (*this, encoding),
|
||||
mProjectPath ((configuration.getUserDataPath() / "projects") /
|
||||
(savePath.filename().u8string() + u8".project")),
|
||||
mSavingOperation (*this, mProjectPath, encoding),
|
||||
mSaving (&mSavingOperation),
|
||||
mResDir(resDir), mRunner (mProjectPath),
|
||||
mDirty (false), mIdCompletionManager(mData)
|
||||
CSMDoc::Document::Document(const Files::ConfigurationManager& configuration, std::vector<std::filesystem::path> files,
|
||||
bool new_, const std::filesystem::path& savePath, const std::filesystem::path& resDir, ToUTF8::FromType encoding,
|
||||
const std::vector<std::string>& blacklistedScripts, bool fsStrict, const Files::PathContainer& dataPaths,
|
||||
const std::vector<std::string>& archives)
|
||||
: mSavePath(savePath)
|
||||
, mContentFiles(std::move(files))
|
||||
, mNew(new_)
|
||||
, mData(encoding, fsStrict, dataPaths, archives, resDir)
|
||||
, mTools(*this, encoding)
|
||||
, mProjectPath((configuration.getUserDataPath() / "projects") / (savePath.filename().u8string() + u8".project"))
|
||||
, mSavingOperation(*this, mProjectPath, encoding)
|
||||
, mSaving(&mSavingOperation)
|
||||
, mResDir(resDir)
|
||||
, mRunner(mProjectPath)
|
||||
, mDirty(false)
|
||||
, mIdCompletionManager(mData)
|
||||
{
|
||||
if (mContentFiles.empty())
|
||||
throw std::runtime_error ("Empty content file sequence");
|
||||
throw std::runtime_error("Empty content file sequence");
|
||||
|
||||
if (mNew || !std::filesystem::exists (mProjectPath))
|
||||
if (mNew || !std::filesystem::exists(mProjectPath))
|
||||
{
|
||||
auto filtersPath = configuration.getUserDataPath() / "defaultfilters";
|
||||
|
||||
@ -302,7 +300,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
|
||||
throw std::runtime_error("Can not create project file: " + Files::pathToUnicodeString(mProjectPath));
|
||||
destination.exceptions(std::ios::failbit | std::ios::badbit);
|
||||
|
||||
if (!std::filesystem::exists (filtersPath))
|
||||
if (!std::filesystem::exists(filtersPath))
|
||||
filtersPath = mResDir / "defaultfilters";
|
||||
|
||||
std::ifstream source(filtersPath, std::ios::in | std::ios::binary);
|
||||
@ -315,35 +313,32 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
|
||||
|
||||
if (mNew)
|
||||
{
|
||||
if (mContentFiles.size()==1)
|
||||
if (mContentFiles.size() == 1)
|
||||
createBase();
|
||||
}
|
||||
|
||||
mBlacklist.add (CSMWorld::UniversalId::Type_Script, blacklistedScripts);
|
||||
mBlacklist.add(CSMWorld::UniversalId::Type_Script, blacklistedScripts);
|
||||
|
||||
addOptionalGmsts();
|
||||
addOptionalGlobals();
|
||||
addOptionalMagicEffects();
|
||||
|
||||
connect (&mUndoStack, &QUndoStack::cleanChanged, this, &Document::modificationStateChanged);
|
||||
connect(&mUndoStack, &QUndoStack::cleanChanged, this, &Document::modificationStateChanged);
|
||||
|
||||
connect (&mTools, &CSMTools::Tools::progress, this, qOverload<int, int, int>(&Document::progress));
|
||||
connect (&mTools, &CSMTools::Tools::done, this, &Document::operationDone);
|
||||
connect (&mTools, &CSMTools::Tools::done, this, &Document::operationDone2);
|
||||
connect (&mTools, &CSMTools::Tools::mergeDone, this, &Document::mergeDone);
|
||||
connect(&mTools, &CSMTools::Tools::progress, this, qOverload<int, int, int>(&Document::progress));
|
||||
connect(&mTools, &CSMTools::Tools::done, this, &Document::operationDone);
|
||||
connect(&mTools, &CSMTools::Tools::done, this, &Document::operationDone2);
|
||||
connect(&mTools, &CSMTools::Tools::mergeDone, this, &Document::mergeDone);
|
||||
|
||||
connect (&mSaving, &OperationHolder::progress,
|
||||
this, qOverload<int, int, int>(&Document::progress));
|
||||
connect (&mSaving, &OperationHolder::done, this, &Document::operationDone2);
|
||||
connect(&mSaving, &OperationHolder::progress, this, qOverload<int, int, int>(&Document::progress));
|
||||
connect(&mSaving, &OperationHolder::done, this, &Document::operationDone2);
|
||||
|
||||
connect (&mSaving, &OperationHolder::reportMessage, this, &Document::reportMessage);
|
||||
connect(&mSaving, &OperationHolder::reportMessage, this, &Document::reportMessage);
|
||||
|
||||
connect (&mRunner, &Runner::runStateChanged, this, &Document::runStateChanged);
|
||||
connect(&mRunner, &Runner::runStateChanged, this, &Document::runStateChanged);
|
||||
}
|
||||
|
||||
CSMDoc::Document::~Document()
|
||||
{
|
||||
}
|
||||
CSMDoc::Document::~Document() {}
|
||||
|
||||
QUndoStack& CSMDoc::Document::getUndoStack()
|
||||
{
|
||||
@ -397,64 +392,62 @@ bool CSMDoc::Document::isNew() const
|
||||
void CSMDoc::Document::save()
|
||||
{
|
||||
if (mSaving.isRunning())
|
||||
throw std::logic_error (
|
||||
"Failed to initiate save, because a save operation is already running.");
|
||||
throw std::logic_error("Failed to initiate save, because a save operation is already running.");
|
||||
|
||||
mSaving.start();
|
||||
|
||||
emit stateChanged (getState(), this);
|
||||
emit stateChanged(getState(), this);
|
||||
}
|
||||
|
||||
CSMWorld::UniversalId CSMDoc::Document::verify (const CSMWorld::UniversalId& reportId)
|
||||
CSMWorld::UniversalId CSMDoc::Document::verify(const CSMWorld::UniversalId& reportId)
|
||||
{
|
||||
CSMWorld::UniversalId id = mTools.runVerifier (reportId);
|
||||
emit stateChanged (getState(), this);
|
||||
CSMWorld::UniversalId id = mTools.runVerifier(reportId);
|
||||
emit stateChanged(getState(), this);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
CSMWorld::UniversalId CSMDoc::Document::newSearch()
|
||||
{
|
||||
return mTools.newSearch();
|
||||
}
|
||||
|
||||
void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search)
|
||||
void CSMDoc::Document::runSearch(const CSMWorld::UniversalId& searchId, const CSMTools::Search& search)
|
||||
{
|
||||
mTools.runSearch (searchId, search);
|
||||
emit stateChanged (getState(), this);
|
||||
mTools.runSearch(searchId, search);
|
||||
emit stateChanged(getState(), this);
|
||||
}
|
||||
|
||||
void CSMDoc::Document::runMerge (std::unique_ptr<CSMDoc::Document> target)
|
||||
void CSMDoc::Document::runMerge(std::unique_ptr<CSMDoc::Document> target)
|
||||
{
|
||||
mTools.runMerge (std::move(target));
|
||||
emit stateChanged (getState(), this);
|
||||
mTools.runMerge(std::move(target));
|
||||
emit stateChanged(getState(), this);
|
||||
}
|
||||
|
||||
void CSMDoc::Document::abortOperation (int type)
|
||||
void CSMDoc::Document::abortOperation(int type)
|
||||
{
|
||||
if (type==State_Saving)
|
||||
if (type == State_Saving)
|
||||
mSaving.abort();
|
||||
else
|
||||
mTools.abortOperation (type);
|
||||
mTools.abortOperation(type);
|
||||
}
|
||||
|
||||
void CSMDoc::Document::modificationStateChanged (bool clean)
|
||||
void CSMDoc::Document::modificationStateChanged(bool clean)
|
||||
{
|
||||
emit stateChanged (getState(), this);
|
||||
emit stateChanged(getState(), this);
|
||||
}
|
||||
|
||||
void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type)
|
||||
void CSMDoc::Document::reportMessage(const CSMDoc::Message& message, int type)
|
||||
{
|
||||
/// \todo find a better way to get these messages to the user.
|
||||
Log(Debug::Info) << message.mMessage;
|
||||
}
|
||||
|
||||
void CSMDoc::Document::operationDone2 (int type, bool failed)
|
||||
void CSMDoc::Document::operationDone2(int type, bool failed)
|
||||
{
|
||||
if (type==CSMDoc::State_Saving && !failed)
|
||||
if (type == CSMDoc::State_Saving && !failed)
|
||||
mDirty = false;
|
||||
|
||||
emit stateChanged (getState(), this);
|
||||
emit stateChanged(getState(), this);
|
||||
}
|
||||
|
||||
const CSMWorld::Data& CSMDoc::Document::getData() const
|
||||
@ -467,37 +460,35 @@ CSMWorld::Data& CSMDoc::Document::getData()
|
||||
return mData;
|
||||
}
|
||||
|
||||
CSMTools::ReportModel *CSMDoc::Document::getReport (const CSMWorld::UniversalId& id)
|
||||
CSMTools::ReportModel* CSMDoc::Document::getReport(const CSMWorld::UniversalId& id)
|
||||
{
|
||||
return mTools.getReport (id);
|
||||
return mTools.getReport(id);
|
||||
}
|
||||
|
||||
bool CSMDoc::Document::isBlacklisted (const CSMWorld::UniversalId& id)
|
||||
const
|
||||
bool CSMDoc::Document::isBlacklisted(const CSMWorld::UniversalId& id) const
|
||||
{
|
||||
return mBlacklist.isBlacklisted (id);
|
||||
return mBlacklist.isBlacklisted(id);
|
||||
}
|
||||
|
||||
void CSMDoc::Document::startRunning (const std::string& profile,
|
||||
const std::string& startupInstruction)
|
||||
void CSMDoc::Document::startRunning(const std::string& profile, const std::string& startupInstruction)
|
||||
{
|
||||
std::vector<std::filesystem::path> contentFiles;
|
||||
|
||||
for (const auto & mContentFile : mContentFiles) {
|
||||
for (const auto& mContentFile : mContentFiles)
|
||||
{
|
||||
contentFiles.emplace_back(mContentFile.filename());
|
||||
}
|
||||
|
||||
mRunner.configure (getData().getDebugProfiles().getRecord (profile).get(), contentFiles,
|
||||
startupInstruction);
|
||||
mRunner.configure(getData().getDebugProfiles().getRecord(profile).get(), contentFiles, startupInstruction);
|
||||
|
||||
int state = getState();
|
||||
|
||||
if (state & State_Modified)
|
||||
{
|
||||
// need to save first
|
||||
mRunner.start (true);
|
||||
mRunner.start(true);
|
||||
|
||||
new SaveWatcher (&mRunner, &mSaving); // no, that is not a memory leak. Qt is weird.
|
||||
new SaveWatcher(&mRunner, &mSaving); // no, that is not a memory leak. Qt is weird.
|
||||
|
||||
if (!(state & State_Saving))
|
||||
save();
|
||||
@ -511,22 +502,22 @@ void CSMDoc::Document::stopRunning()
|
||||
mRunner.stop();
|
||||
}
|
||||
|
||||
QTextDocument *CSMDoc::Document::getRunLog()
|
||||
QTextDocument* CSMDoc::Document::getRunLog()
|
||||
{
|
||||
return mRunner.getLog();
|
||||
}
|
||||
|
||||
void CSMDoc::Document::runStateChanged()
|
||||
{
|
||||
emit stateChanged (getState(), this);
|
||||
emit stateChanged(getState(), this);
|
||||
}
|
||||
|
||||
void CSMDoc::Document::progress (int current, int max, int type)
|
||||
void CSMDoc::Document::progress(int current, int max, int type)
|
||||
{
|
||||
emit progress (current, max, type, 1, this);
|
||||
emit progress(current, max, type, 1, this);
|
||||
}
|
||||
|
||||
CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager()
|
||||
CSMWorld::IdCompletionManager& CSMDoc::Document::getIdCompletionManager()
|
||||
{
|
||||
return mIdCompletionManager;
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <QUndoStack>
|
||||
#include <QObject>
|
||||
#include <QUndoStack>
|
||||
|
||||
#include <components/files/multidircollection.hpp>
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
@ -14,10 +14,10 @@
|
||||
|
||||
#include "../tools/tools.hpp"
|
||||
|
||||
#include "saving.hpp"
|
||||
#include "blacklist.hpp"
|
||||
#include "runner.hpp"
|
||||
#include "operationholder.hpp"
|
||||
#include "runner.hpp"
|
||||
#include "saving.hpp"
|
||||
|
||||
class QAbstractItemModel;
|
||||
|
||||
@ -52,133 +52,130 @@ namespace CSMDoc
|
||||
{
|
||||
class Document : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
private:
|
||||
std::filesystem::path mSavePath;
|
||||
std::vector<std::filesystem::path> mContentFiles;
|
||||
bool mNew;
|
||||
CSMWorld::Data mData;
|
||||
CSMTools::Tools mTools;
|
||||
std::filesystem::path mProjectPath;
|
||||
Saving mSavingOperation;
|
||||
OperationHolder mSaving;
|
||||
std::filesystem::path mResDir;
|
||||
Blacklist mBlacklist;
|
||||
Runner mRunner;
|
||||
bool mDirty;
|
||||
|
||||
std::filesystem::path mSavePath;
|
||||
std::vector<std::filesystem::path> mContentFiles;
|
||||
bool mNew;
|
||||
CSMWorld::Data mData;
|
||||
CSMTools::Tools mTools;
|
||||
std::filesystem::path mProjectPath;
|
||||
Saving mSavingOperation;
|
||||
OperationHolder mSaving;
|
||||
std::filesystem::path mResDir;
|
||||
Blacklist mBlacklist;
|
||||
Runner mRunner;
|
||||
bool mDirty;
|
||||
CSMWorld::IdCompletionManager mIdCompletionManager;
|
||||
|
||||
CSMWorld::IdCompletionManager mIdCompletionManager;
|
||||
// It is important that the undo stack is declared last, because on desctruction it fires a signal, that is
|
||||
// connected to a slot, that is using other member variables. Unfortunately this connection is cut only in the
|
||||
// QObject destructor, which is way too late.
|
||||
QUndoStack mUndoStack;
|
||||
|
||||
// It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is
|
||||
// using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late.
|
||||
QUndoStack mUndoStack;
|
||||
// not implemented
|
||||
Document(const Document&);
|
||||
Document& operator=(const Document&);
|
||||
|
||||
// not implemented
|
||||
Document (const Document&);
|
||||
Document& operator= (const Document&);
|
||||
void createBase();
|
||||
|
||||
void createBase();
|
||||
void addGmsts();
|
||||
|
||||
void addGmsts();
|
||||
void addOptionalGmsts();
|
||||
|
||||
void addOptionalGmsts();
|
||||
void addOptionalGlobals();
|
||||
|
||||
void addOptionalGlobals();
|
||||
void addOptionalMagicEffects();
|
||||
|
||||
void addOptionalMagicEffects();
|
||||
void addOptionalGmst(const ESM::GameSetting& gmst);
|
||||
|
||||
void addOptionalGmst (const ESM::GameSetting& gmst);
|
||||
void addOptionalGlobal(const ESM::Global& global);
|
||||
|
||||
void addOptionalGlobal (const ESM::Global& global);
|
||||
void addOptionalMagicEffect(const ESM::MagicEffect& effect);
|
||||
|
||||
void addOptionalMagicEffect (const ESM::MagicEffect& effect);
|
||||
public:
|
||||
Document(const Files::ConfigurationManager& configuration, std::vector<std::filesystem::path> files, bool new_,
|
||||
const std::filesystem::path& savePath, const std::filesystem::path& resDir, ToUTF8::FromType encoding,
|
||||
const std::vector<std::string>& blacklistedScripts, bool fsStrict, const Files::PathContainer& dataPaths,
|
||||
const std::vector<std::string>& archives);
|
||||
|
||||
public:
|
||||
~Document();
|
||||
|
||||
Document (const Files::ConfigurationManager& configuration,
|
||||
std::vector< std::filesystem::path > files, bool new_,
|
||||
const std::filesystem::path& savePath, const std::filesystem::path& resDir,
|
||||
ToUTF8::FromType encoding, const std::vector<std::string>& blacklistedScripts,
|
||||
bool fsStrict, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives);
|
||||
QUndoStack& getUndoStack();
|
||||
|
||||
~Document();
|
||||
int getState() const;
|
||||
|
||||
QUndoStack& getUndoStack();
|
||||
const std::filesystem::path& getResourceDir() const;
|
||||
|
||||
int getState() const;
|
||||
const std::filesystem::path& getSavePath() const;
|
||||
|
||||
const std::filesystem::path& getResourceDir() const;
|
||||
const std::filesystem::path& getProjectPath() const;
|
||||
|
||||
const std::filesystem::path& getSavePath() const;
|
||||
const std::vector<std::filesystem::path>& getContentFiles() const;
|
||||
///< \attention The last element in this collection is the file that is being edited,
|
||||
/// but with its original path instead of the save path.
|
||||
|
||||
const std::filesystem::path& getProjectPath() const;
|
||||
bool isNew() const;
|
||||
///< Is this a newly created content file?
|
||||
|
||||
const std::vector<std::filesystem::path>& getContentFiles() const;
|
||||
///< \attention The last element in this collection is the file that is being edited,
|
||||
/// but with its original path instead of the save path.
|
||||
void save();
|
||||
|
||||
bool isNew() const;
|
||||
///< Is this a newly created content file?
|
||||
CSMWorld::UniversalId verify(const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId());
|
||||
|
||||
void save();
|
||||
CSMWorld::UniversalId newSearch();
|
||||
|
||||
CSMWorld::UniversalId verify (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId());
|
||||
void runSearch(const CSMWorld::UniversalId& searchId, const CSMTools::Search& search);
|
||||
|
||||
CSMWorld::UniversalId newSearch();
|
||||
void runMerge(std::unique_ptr<CSMDoc::Document> target);
|
||||
|
||||
void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search);
|
||||
void abortOperation(int type);
|
||||
|
||||
void runMerge (std::unique_ptr<CSMDoc::Document> target);
|
||||
const CSMWorld::Data& getData() const;
|
||||
|
||||
void abortOperation (int type);
|
||||
CSMWorld::Data& getData();
|
||||
|
||||
const CSMWorld::Data& getData() const;
|
||||
CSMTools::ReportModel* getReport(const CSMWorld::UniversalId& id);
|
||||
///< The ownership of the returned report is not transferred.
|
||||
|
||||
CSMWorld::Data& getData();
|
||||
bool isBlacklisted(const CSMWorld::UniversalId& id) const;
|
||||
|
||||
CSMTools::ReportModel *getReport (const CSMWorld::UniversalId& id);
|
||||
///< The ownership of the returned report is not transferred.
|
||||
void startRunning(const std::string& profile, const std::string& startupInstruction = "");
|
||||
|
||||
bool isBlacklisted (const CSMWorld::UniversalId& id) const;
|
||||
void stopRunning();
|
||||
|
||||
void startRunning (const std::string& profile,
|
||||
const std::string& startupInstruction = "");
|
||||
QTextDocument* getRunLog();
|
||||
|
||||
void stopRunning();
|
||||
CSMWorld::IdCompletionManager& getIdCompletionManager();
|
||||
|
||||
QTextDocument *getRunLog();
|
||||
void flagAsDirty();
|
||||
|
||||
CSMWorld::IdCompletionManager &getIdCompletionManager();
|
||||
signals:
|
||||
|
||||
void flagAsDirty();
|
||||
void stateChanged(int state, CSMDoc::Document* document);
|
||||
|
||||
signals:
|
||||
void progress(int current, int max, int type, int threads, CSMDoc::Document* document);
|
||||
|
||||
void stateChanged (int state, CSMDoc::Document *document);
|
||||
/// \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);
|
||||
|
||||
void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
|
||||
void operationDone(int type, bool failed);
|
||||
|
||||
/// \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);
|
||||
private slots:
|
||||
|
||||
void operationDone (int type, bool failed);
|
||||
void modificationStateChanged(bool clean);
|
||||
|
||||
private slots:
|
||||
void reportMessage(const CSMDoc::Message& message, int type);
|
||||
|
||||
void modificationStateChanged (bool clean);
|
||||
void operationDone2(int type, bool failed);
|
||||
|
||||
void reportMessage (const CSMDoc::Message& message, int type);
|
||||
void runStateChanged();
|
||||
|
||||
void operationDone2 (int type, bool failed);
|
||||
public slots:
|
||||
|
||||
void runStateChanged();
|
||||
|
||||
public slots:
|
||||
|
||||
void progress (int current, int max, int type);
|
||||
void progress(int current, int max, int type);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -8,31 +8,26 @@
|
||||
|
||||
#include "document.hpp"
|
||||
|
||||
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
|
||||
: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252), mFsStrict(false)
|
||||
CSMDoc::DocumentManager::DocumentManager(const Files::ConfigurationManager& configuration)
|
||||
: mConfiguration(configuration)
|
||||
, mEncoding(ToUTF8::WINDOWS_1252)
|
||||
, mFsStrict(false)
|
||||
{
|
||||
std::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
|
||||
|
||||
if (!std::filesystem::is_directory (projectPath))
|
||||
std::filesystem::create_directories (projectPath);
|
||||
if (!std::filesystem::is_directory(projectPath))
|
||||
std::filesystem::create_directories(projectPath);
|
||||
|
||||
mLoader.moveToThread (&mLoaderThread);
|
||||
mLoader.moveToThread(&mLoaderThread);
|
||||
mLoaderThread.start();
|
||||
|
||||
connect (&mLoader, &Loader::documentLoaded,
|
||||
this, &DocumentManager::documentLoaded);
|
||||
connect (&mLoader, &Loader::documentNotLoaded,
|
||||
this, &DocumentManager::documentNotLoaded);
|
||||
connect (this, &DocumentManager::loadRequest,
|
||||
&mLoader, &Loader::loadDocument);
|
||||
connect (&mLoader, &Loader::nextStage,
|
||||
this, &DocumentManager::nextStage);
|
||||
connect (&mLoader, &Loader::nextRecord,
|
||||
this, &DocumentManager::nextRecord);
|
||||
connect (this, &DocumentManager::cancelLoading,
|
||||
&mLoader, &Loader::abortLoading);
|
||||
connect (&mLoader, &Loader::loadMessage,
|
||||
this, &DocumentManager::loadMessage);
|
||||
connect(&mLoader, &Loader::documentLoaded, this, &DocumentManager::documentLoaded);
|
||||
connect(&mLoader, &Loader::documentNotLoaded, this, &DocumentManager::documentNotLoaded);
|
||||
connect(this, &DocumentManager::loadRequest, &mLoader, &Loader::loadDocument);
|
||||
connect(&mLoader, &Loader::nextStage, this, &DocumentManager::nextStage);
|
||||
connect(&mLoader, &Loader::nextRecord, this, &DocumentManager::nextRecord);
|
||||
connect(this, &DocumentManager::cancelLoading, &mLoader, &Loader::abortLoading);
|
||||
connect(&mLoader, &Loader::loadMessage, this, &DocumentManager::loadMessage);
|
||||
}
|
||||
|
||||
CSMDoc::DocumentManager::~DocumentManager()
|
||||
@ -42,7 +37,7 @@ CSMDoc::DocumentManager::~DocumentManager()
|
||||
mLoader.hasThingsToDo().wakeAll();
|
||||
mLoaderThread.wait();
|
||||
|
||||
for (std::vector<Document *>::iterator iter (mDocuments.begin()); iter!=mDocuments.end(); ++iter)
|
||||
for (std::vector<Document*>::iterator iter(mDocuments.begin()); iter != mDocuments.end(); ++iter)
|
||||
delete *iter;
|
||||
}
|
||||
|
||||
@ -51,78 +46,78 @@ bool CSMDoc::DocumentManager::isEmpty()
|
||||
return mDocuments.empty();
|
||||
}
|
||||
|
||||
void CSMDoc::DocumentManager::addDocument (const std::vector<std::filesystem::path>& files, const std::filesystem::path& savePath,
|
||||
bool new_)
|
||||
void CSMDoc::DocumentManager::addDocument(
|
||||
const std::vector<std::filesystem::path>& files, const std::filesystem::path& savePath, bool new_)
|
||||
{
|
||||
Document *document = makeDocument (files, savePath, new_);
|
||||
insertDocument (document);
|
||||
Document* document = makeDocument(files, savePath, new_);
|
||||
insertDocument(document);
|
||||
}
|
||||
|
||||
CSMDoc::Document *CSMDoc::DocumentManager::makeDocument (
|
||||
const std::vector< std::filesystem::path >& files,
|
||||
const std::filesystem::path& savePath, bool new_)
|
||||
CSMDoc::Document* CSMDoc::DocumentManager::makeDocument(
|
||||
const std::vector<std::filesystem::path>& files, const std::filesystem::path& savePath, bool new_)
|
||||
{
|
||||
return new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding, mBlacklistedScripts, mFsStrict, mDataPaths, mArchives);
|
||||
return new Document(mConfiguration, files, new_, savePath, mResDir, mEncoding, mBlacklistedScripts, mFsStrict,
|
||||
mDataPaths, mArchives);
|
||||
}
|
||||
|
||||
void CSMDoc::DocumentManager::insertDocument (CSMDoc::Document *document)
|
||||
void CSMDoc::DocumentManager::insertDocument(CSMDoc::Document* document)
|
||||
{
|
||||
mDocuments.push_back (document);
|
||||
mDocuments.push_back(document);
|
||||
|
||||
connect (document, SIGNAL (mergeDone (CSMDoc::Document*)),
|
||||
this, SLOT (insertDocument (CSMDoc::Document*)));
|
||||
connect(document, SIGNAL(mergeDone(CSMDoc::Document*)), this, SLOT(insertDocument(CSMDoc::Document*)));
|
||||
|
||||
emit loadRequest (document);
|
||||
emit loadRequest(document);
|
||||
|
||||
mLoader.hasThingsToDo().wakeAll();
|
||||
}
|
||||
|
||||
void CSMDoc::DocumentManager::removeDocument (CSMDoc::Document *document)
|
||||
void CSMDoc::DocumentManager::removeDocument(CSMDoc::Document* document)
|
||||
{
|
||||
std::vector<Document *>::iterator iter = std::find (mDocuments.begin(), mDocuments.end(), document);
|
||||
std::vector<Document*>::iterator iter = std::find(mDocuments.begin(), mDocuments.end(), document);
|
||||
|
||||
if (iter==mDocuments.end())
|
||||
throw std::runtime_error ("removing invalid document");
|
||||
if (iter == mDocuments.end())
|
||||
throw std::runtime_error("removing invalid document");
|
||||
|
||||
emit documentAboutToBeRemoved (document);
|
||||
emit documentAboutToBeRemoved(document);
|
||||
|
||||
mDocuments.erase (iter);
|
||||
mDocuments.erase(iter);
|
||||
document->deleteLater();
|
||||
|
||||
if (mDocuments.empty())
|
||||
emit lastDocumentDeleted();
|
||||
}
|
||||
|
||||
void CSMDoc::DocumentManager::setResourceDir (const std::filesystem::path& parResDir)
|
||||
void CSMDoc::DocumentManager::setResourceDir(const std::filesystem::path& parResDir)
|
||||
{
|
||||
mResDir = std::filesystem::absolute(parResDir);
|
||||
}
|
||||
|
||||
void CSMDoc::DocumentManager::setEncoding (ToUTF8::FromType encoding)
|
||||
void CSMDoc::DocumentManager::setEncoding(ToUTF8::FromType encoding)
|
||||
{
|
||||
mEncoding = encoding;
|
||||
}
|
||||
|
||||
void CSMDoc::DocumentManager::setBlacklistedScripts (const std::vector<std::string>& scriptIds)
|
||||
void CSMDoc::DocumentManager::setBlacklistedScripts(const std::vector<std::string>& scriptIds)
|
||||
{
|
||||
mBlacklistedScripts = scriptIds;
|
||||
}
|
||||
|
||||
void CSMDoc::DocumentManager::documentLoaded (Document *document)
|
||||
void CSMDoc::DocumentManager::documentLoaded(Document* document)
|
||||
{
|
||||
emit documentAdded (document);
|
||||
emit loadingStopped (document, true, "");
|
||||
emit documentAdded(document);
|
||||
emit loadingStopped(document, true, "");
|
||||
}
|
||||
|
||||
void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std::string& error)
|
||||
void CSMDoc::DocumentManager::documentNotLoaded(Document* document, const std::string& error)
|
||||
{
|
||||
emit loadingStopped (document, false, error);
|
||||
emit loadingStopped(document, false, error);
|
||||
|
||||
if (error.empty()) // do not remove the document yet, if we have an error
|
||||
removeDocument (document);
|
||||
removeDocument(document);
|
||||
}
|
||||
|
||||
void CSMDoc::DocumentManager::setFileData(bool strict, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives)
|
||||
void CSMDoc::DocumentManager::setFileData(
|
||||
bool strict, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives)
|
||||
{
|
||||
mFsStrict = strict;
|
||||
mDataPaths = dataPaths;
|
||||
|
@ -1,15 +1,15 @@
|
||||
#ifndef CSM_DOC_DOCUMENTMGR_H
|
||||
#define CSM_DOC_DOCUMENTMGR_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
#include <components/fallback/fallback.hpp>
|
||||
#include <components/files/multidircollection.hpp>
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
|
||||
#include "loader.hpp"
|
||||
|
||||
@ -29,94 +29,91 @@ namespace CSMDoc
|
||||
|
||||
class DocumentManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
std::vector<Document *> mDocuments;
|
||||
const Files::ConfigurationManager& mConfiguration;
|
||||
QThread mLoaderThread;
|
||||
Loader mLoader;
|
||||
ToUTF8::FromType mEncoding;
|
||||
std::vector<std::string> mBlacklistedScripts;
|
||||
std::vector<Document*> mDocuments;
|
||||
const Files::ConfigurationManager& mConfiguration;
|
||||
QThread mLoaderThread;
|
||||
Loader mLoader;
|
||||
ToUTF8::FromType mEncoding;
|
||||
std::vector<std::string> mBlacklistedScripts;
|
||||
|
||||
std::filesystem::path mResDir;
|
||||
std::filesystem::path mResDir;
|
||||
|
||||
bool mFsStrict;
|
||||
Files::PathContainer mDataPaths;
|
||||
std::vector<std::string> mArchives;
|
||||
bool mFsStrict;
|
||||
Files::PathContainer mDataPaths;
|
||||
std::vector<std::string> mArchives;
|
||||
|
||||
DocumentManager (const DocumentManager&);
|
||||
DocumentManager& operator= (const DocumentManager&);
|
||||
DocumentManager(const DocumentManager&);
|
||||
DocumentManager& operator=(const DocumentManager&);
|
||||
|
||||
public:
|
||||
public:
|
||||
DocumentManager(const Files::ConfigurationManager& configuration);
|
||||
|
||||
DocumentManager (const Files::ConfigurationManager& configuration);
|
||||
~DocumentManager();
|
||||
|
||||
~DocumentManager();
|
||||
void addDocument(
|
||||
const std::vector<std::filesystem::path>& files, const std::filesystem::path& savePath, bool new_);
|
||||
///< \param new_ Do not load the last content file in \a files and instead create in an
|
||||
/// appropriate way.
|
||||
|
||||
void addDocument (const std::vector< std::filesystem::path >& files,
|
||||
const std::filesystem::path& savePath, bool new_);
|
||||
///< \param new_ Do not load the last content file in \a files and instead create in an
|
||||
/// appropriate way.
|
||||
/// Create a new document. The ownership of the created document is transferred to
|
||||
/// the calling function. The DocumentManager does not manage it. Loading has not
|
||||
/// taken place at the point when the document is returned.
|
||||
///
|
||||
/// \param new_ Do not load the last content file in \a files and instead create in an
|
||||
/// appropriate way.
|
||||
Document* makeDocument(
|
||||
const std::vector<std::filesystem::path>& files, const std::filesystem::path& savePath, bool new_);
|
||||
|
||||
/// Create a new document. The ownership of the created document is transferred to
|
||||
/// the calling function. The DocumentManager does not manage it. Loading has not
|
||||
/// taken place at the point when the document is returned.
|
||||
///
|
||||
/// \param new_ Do not load the last content file in \a files and instead create in an
|
||||
/// appropriate way.
|
||||
Document *makeDocument (const std::vector< std::filesystem::path >& files,
|
||||
const std::filesystem::path& savePath, bool new_);
|
||||
void setResourceDir(const std::filesystem::path& parResDir);
|
||||
|
||||
void setResourceDir (const std::filesystem::path& parResDir);
|
||||
void setEncoding(ToUTF8::FromType encoding);
|
||||
|
||||
void setEncoding (ToUTF8::FromType encoding);
|
||||
void setBlacklistedScripts(const std::vector<std::string>& scriptIds);
|
||||
|
||||
void setBlacklistedScripts (const std::vector<std::string>& scriptIds);
|
||||
/// Sets the file data that gets passed to newly created documents.
|
||||
void setFileData(bool strict, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives);
|
||||
|
||||
/// Sets the file data that gets passed to newly created documents.
|
||||
void setFileData(bool strict, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives);
|
||||
bool isEmpty();
|
||||
|
||||
bool isEmpty();
|
||||
private slots:
|
||||
|
||||
private slots:
|
||||
void documentLoaded(Document* document);
|
||||
///< The ownership of \a document is not transferred.
|
||||
|
||||
void documentLoaded (Document *document);
|
||||
///< The ownership of \a document is not transferred.
|
||||
void documentNotLoaded(Document* document, const std::string& error);
|
||||
///< Document load has been interrupted either because of a call to abortLoading
|
||||
/// or a problem during loading). In the former case error will be an empty string.
|
||||
|
||||
void documentNotLoaded (Document *document, const std::string& error);
|
||||
///< Document load has been interrupted either because of a call to abortLoading
|
||||
/// or a problem during loading). In the former case error will be an empty string.
|
||||
public slots:
|
||||
|
||||
public slots:
|
||||
void removeDocument(CSMDoc::Document* document);
|
||||
///< Emits the lastDocumentDeleted signal, if applicable.
|
||||
|
||||
void removeDocument (CSMDoc::Document *document);
|
||||
///< Emits the lastDocumentDeleted signal, if applicable.
|
||||
/// Hand over document to *this. The ownership is transferred. The DocumentManager
|
||||
/// will initiate the load procedure, if necessary
|
||||
void insertDocument(CSMDoc::Document* document);
|
||||
|
||||
/// Hand over document to *this. The ownership is transferred. The DocumentManager
|
||||
/// will initiate the load procedure, if necessary
|
||||
void insertDocument (CSMDoc::Document *document);
|
||||
signals:
|
||||
|
||||
signals:
|
||||
void documentAdded(CSMDoc::Document* document);
|
||||
|
||||
void documentAdded (CSMDoc::Document *document);
|
||||
void documentAboutToBeRemoved(CSMDoc::Document* document);
|
||||
|
||||
void documentAboutToBeRemoved (CSMDoc::Document *document);
|
||||
void loadRequest(CSMDoc::Document* document);
|
||||
|
||||
void loadRequest (CSMDoc::Document *document);
|
||||
void lastDocumentDeleted();
|
||||
|
||||
void lastDocumentDeleted();
|
||||
void loadingStopped(CSMDoc::Document* document, bool completed, const std::string& error);
|
||||
|
||||
void loadingStopped (CSMDoc::Document *document, bool completed,
|
||||
const std::string& error);
|
||||
void nextStage(CSMDoc::Document* document, const std::string& name, int totalRecords);
|
||||
|
||||
void nextStage (CSMDoc::Document *document, const std::string& name,
|
||||
int totalRecords);
|
||||
void nextRecord(CSMDoc::Document* document, int records);
|
||||
|
||||
void nextRecord (CSMDoc::Document *document, int records);
|
||||
void cancelLoading(CSMDoc::Document* document);
|
||||
|
||||
void cancelLoading (CSMDoc::Document *document);
|
||||
|
||||
void loadMessage (CSMDoc::Document *document, const std::string& message);
|
||||
void loadMessage(CSMDoc::Document* document, const std::string& message);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -8,15 +8,19 @@
|
||||
|
||||
#include "document.hpp"
|
||||
|
||||
CSMDoc::Loader::Stage::Stage() : mFile (0), mRecordsLoaded (0), mRecordsLeft (false) {}
|
||||
|
||||
CSMDoc::Loader::Stage::Stage()
|
||||
: mFile(0)
|
||||
, mRecordsLoaded(0)
|
||||
, mRecordsLeft(false)
|
||||
{
|
||||
}
|
||||
|
||||
CSMDoc::Loader::Loader()
|
||||
: mShouldStop(false)
|
||||
{
|
||||
mTimer = new QTimer (this);
|
||||
mTimer = new QTimer(this);
|
||||
|
||||
connect (mTimer, &QTimer::timeout, this, &Loader::load);
|
||||
connect(mTimer, &QTimer::timeout, this, &Loader::load);
|
||||
mTimer->start();
|
||||
}
|
||||
|
||||
@ -35,7 +39,7 @@ void CSMDoc::Loader::load()
|
||||
if (mDocuments.empty())
|
||||
{
|
||||
mMutex.lock();
|
||||
mThingsToDo.wait (&mMutex);
|
||||
mThingsToDo.wait(&mMutex);
|
||||
mMutex.unlock();
|
||||
|
||||
if (mShouldStop)
|
||||
@ -44,12 +48,12 @@ void CSMDoc::Loader::load()
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::pair<Document *, Stage> >::iterator iter = mDocuments.begin();
|
||||
std::vector<std::pair<Document*, Stage>>::iterator iter = mDocuments.begin();
|
||||
|
||||
Document *document = iter->first;
|
||||
Document* document = iter->first;
|
||||
|
||||
int size = static_cast<int> (document->getContentFiles().size());
|
||||
int editedIndex = size-1; // index of the file to be edited/created
|
||||
int size = static_cast<int>(document->getContentFiles().size());
|
||||
int editedIndex = size - 1; // index of the file to be edited/created
|
||||
|
||||
if (document->isNew())
|
||||
--size;
|
||||
@ -60,10 +64,10 @@ void CSMDoc::Loader::load()
|
||||
{
|
||||
if (iter->second.mRecordsLeft)
|
||||
{
|
||||
Messages messages (Message::Severity_Error);
|
||||
Messages messages(Message::Severity_Error);
|
||||
const int batchingSize = 50;
|
||||
for (int i=0; i<batchingSize; ++i) // do not flood the system with update signals
|
||||
if (document->getData().continueLoading (messages))
|
||||
for (int i = 0; i < batchingSize; ++i) // do not flood the system with update signals
|
||||
if (document->getData().continueLoading(messages))
|
||||
{
|
||||
iter->second.mRecordsLeft = false;
|
||||
break;
|
||||
@ -71,39 +75,39 @@ void CSMDoc::Loader::load()
|
||||
else
|
||||
++(iter->second.mRecordsLoaded);
|
||||
|
||||
CSMWorld::UniversalId log (CSMWorld::UniversalId::Type_LoadErrorLog, 0);
|
||||
CSMWorld::UniversalId log(CSMWorld::UniversalId::Type_LoadErrorLog, 0);
|
||||
|
||||
{ // silence a g++ warning
|
||||
for (CSMDoc::Messages::Iterator messageIter (messages.begin());
|
||||
messageIter!=messages.end(); ++messageIter)
|
||||
{
|
||||
document->getReport (log)->add (*messageIter);
|
||||
emit loadMessage (document, messageIter->mMessage);
|
||||
}
|
||||
for (CSMDoc::Messages::Iterator messageIter(messages.begin()); messageIter != messages.end();
|
||||
++messageIter)
|
||||
{
|
||||
document->getReport(log)->add(*messageIter);
|
||||
emit loadMessage(document, messageIter->mMessage);
|
||||
}
|
||||
}
|
||||
|
||||
emit nextRecord (document, iter->second.mRecordsLoaded);
|
||||
emit nextRecord(document, iter->second.mRecordsLoaded);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (iter->second.mFile<size) // start loading the files
|
||||
if (iter->second.mFile < size) // start loading the files
|
||||
{
|
||||
std::filesystem::path path = document->getContentFiles()[iter->second.mFile];
|
||||
|
||||
int steps = document->getData().startLoading (path, iter->second.mFile!=editedIndex, /*project*/false);
|
||||
int steps = document->getData().startLoading(path, iter->second.mFile != editedIndex, /*project*/ false);
|
||||
iter->second.mRecordsLeft = true;
|
||||
iter->second.mRecordsLoaded = 0;
|
||||
|
||||
emit nextStage (document, Files::pathToUnicodeString(path.filename()), steps);
|
||||
emit nextStage(document, Files::pathToUnicodeString(path.filename()), steps);
|
||||
}
|
||||
else if (iter->second.mFile==size) // start loading the last (project) file
|
||||
else if (iter->second.mFile == size) // start loading the last (project) file
|
||||
{
|
||||
int steps = document->getData().startLoading (document->getProjectPath(), /*base*/false, true);
|
||||
int steps = document->getData().startLoading(document->getProjectPath(), /*base*/ false, true);
|
||||
iter->second.mRecordsLeft = true;
|
||||
iter->second.mRecordsLoaded = 0;
|
||||
|
||||
emit nextStage (document, "Project File", steps);
|
||||
emit nextStage(document, "Project File", steps);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -114,32 +118,31 @@ void CSMDoc::Loader::load()
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
mDocuments.erase (iter);
|
||||
emit documentNotLoaded (document, e.what());
|
||||
mDocuments.erase(iter);
|
||||
emit documentNotLoaded(document, e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
if (done)
|
||||
{
|
||||
mDocuments.erase (iter);
|
||||
emit documentLoaded (document);
|
||||
mDocuments.erase(iter);
|
||||
emit documentLoaded(document);
|
||||
}
|
||||
}
|
||||
|
||||
void CSMDoc::Loader::loadDocument (CSMDoc::Document *document)
|
||||
void CSMDoc::Loader::loadDocument(CSMDoc::Document* document)
|
||||
{
|
||||
mDocuments.emplace_back (document, Stage());
|
||||
mDocuments.emplace_back(document, Stage());
|
||||
}
|
||||
|
||||
void CSMDoc::Loader::abortLoading (CSMDoc::Document *document)
|
||||
void CSMDoc::Loader::abortLoading(CSMDoc::Document* document)
|
||||
{
|
||||
for (std::vector<std::pair<Document *, Stage> >::iterator iter = mDocuments.begin();
|
||||
iter!=mDocuments.end(); ++iter)
|
||||
for (std::vector<std::pair<Document*, Stage>>::iterator iter = mDocuments.begin(); iter != mDocuments.end(); ++iter)
|
||||
{
|
||||
if (iter->first==document)
|
||||
if (iter->first == document)
|
||||
{
|
||||
mDocuments.erase (iter);
|
||||
emit documentNotLoaded (document, "");
|
||||
mDocuments.erase(iter);
|
||||
emit documentNotLoaded(document, "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QWaitCondition>
|
||||
|
||||
@ -14,65 +14,63 @@ namespace CSMDoc
|
||||
|
||||
class Loader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
struct Stage
|
||||
{
|
||||
int mFile;
|
||||
int mRecordsLoaded;
|
||||
bool mRecordsLeft;
|
||||
struct Stage
|
||||
{
|
||||
int mFile;
|
||||
int mRecordsLoaded;
|
||||
bool mRecordsLeft;
|
||||
|
||||
Stage();
|
||||
};
|
||||
Stage();
|
||||
};
|
||||
|
||||
QMutex mMutex;
|
||||
QWaitCondition mThingsToDo;
|
||||
std::vector<std::pair<Document *, Stage> > mDocuments;
|
||||
QMutex mMutex;
|
||||
QWaitCondition mThingsToDo;
|
||||
std::vector<std::pair<Document*, Stage>> mDocuments;
|
||||
|
||||
QTimer* mTimer;
|
||||
bool mShouldStop;
|
||||
QTimer* mTimer;
|
||||
bool mShouldStop;
|
||||
|
||||
public:
|
||||
public:
|
||||
Loader();
|
||||
|
||||
Loader();
|
||||
QWaitCondition& hasThingsToDo();
|
||||
|
||||
QWaitCondition& hasThingsToDo();
|
||||
void stop();
|
||||
|
||||
void stop();
|
||||
private slots:
|
||||
|
||||
private slots:
|
||||
void load();
|
||||
|
||||
void load();
|
||||
public slots:
|
||||
|
||||
public slots:
|
||||
void loadDocument(CSMDoc::Document* document);
|
||||
///< The ownership of \a document is not transferred.
|
||||
|
||||
void loadDocument (CSMDoc::Document *document);
|
||||
///< The ownership of \a document is not transferred.
|
||||
void abortLoading(CSMDoc::Document* document);
|
||||
///< Abort loading \a docuemnt (ignored if \a document has already finished being
|
||||
/// loaded). Will result in a documentNotLoaded signal, once the Loader has finished
|
||||
/// cleaning up.
|
||||
|
||||
void abortLoading (CSMDoc::Document *document);
|
||||
///< Abort loading \a docuemnt (ignored if \a document has already finished being
|
||||
/// loaded). Will result in a documentNotLoaded signal, once the Loader has finished
|
||||
/// cleaning up.
|
||||
signals:
|
||||
|
||||
signals:
|
||||
void documentLoaded(Document* document);
|
||||
///< The ownership of \a document is not transferred.
|
||||
|
||||
void documentLoaded (Document *document);
|
||||
///< The ownership of \a document is not transferred.
|
||||
void documentNotLoaded(Document* document, const std::string& error);
|
||||
///< Document load has been interrupted either because of a call to abortLoading
|
||||
/// or a problem during loading). In the former case error will be an empty string.
|
||||
|
||||
void documentNotLoaded (Document *document, const std::string& error);
|
||||
///< Document load has been interrupted either because of a call to abortLoading
|
||||
/// or a problem during loading). In the former case error will be an empty string.
|
||||
void nextStage(CSMDoc::Document* document, const std::string& name, int totalRecords);
|
||||
|
||||
void nextStage (CSMDoc::Document *document, const std::string& name,
|
||||
int totalRecords);
|
||||
void nextRecord(CSMDoc::Document* document, int records);
|
||||
///< \note This signal is only given once per group of records. The group size is
|
||||
/// approximately the total number of records divided by the steps value of the
|
||||
/// previous nextStage signal.
|
||||
|
||||
void nextRecord (CSMDoc::Document *document, int records);
|
||||
///< \note This signal is only given once per group of records. The group size is
|
||||
/// approximately the total number of records divided by the steps value of the
|
||||
/// previous nextStage signal.
|
||||
|
||||
void loadMessage (CSMDoc::Document *document, const std::string& message);
|
||||
///< Non-critical load error or warning
|
||||
void loadMessage(CSMDoc::Document* document, const std::string& message);
|
||||
///< Non-critical load error or warning
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,38 +1,50 @@
|
||||
#include "messages.hpp"
|
||||
|
||||
CSMDoc::Message::Message() : mSeverity(Severity_Default){}
|
||||
CSMDoc::Message::Message()
|
||||
: mSeverity(Severity_Default)
|
||||
{
|
||||
}
|
||||
|
||||
CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& message,
|
||||
const std::string& hint, Severity severity)
|
||||
: mId (id), mMessage (message), mHint (hint), mSeverity (severity)
|
||||
{}
|
||||
CSMDoc::Message::Message(
|
||||
const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint, Severity severity)
|
||||
: mId(id)
|
||||
, mMessage(message)
|
||||
, mHint(hint)
|
||||
, mSeverity(severity)
|
||||
{
|
||||
}
|
||||
|
||||
std::string CSMDoc::Message::toString (Severity severity)
|
||||
std::string CSMDoc::Message::toString(Severity severity)
|
||||
{
|
||||
switch (severity)
|
||||
{
|
||||
case CSMDoc::Message::Severity_Info: return "Information";
|
||||
case CSMDoc::Message::Severity_Warning: return "Warning";
|
||||
case CSMDoc::Message::Severity_Error: return "Error";
|
||||
case CSMDoc::Message::Severity_SeriousError: return "Serious Error";
|
||||
case CSMDoc::Message::Severity_Default: break;
|
||||
case CSMDoc::Message::Severity_Info:
|
||||
return "Information";
|
||||
case CSMDoc::Message::Severity_Warning:
|
||||
return "Warning";
|
||||
case CSMDoc::Message::Severity_Error:
|
||||
return "Error";
|
||||
case CSMDoc::Message::Severity_SeriousError:
|
||||
return "Serious Error";
|
||||
case CSMDoc::Message::Severity_Default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
CSMDoc::Messages::Messages (Message::Severity default_)
|
||||
: mDefault (default_)
|
||||
{}
|
||||
|
||||
void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& message,
|
||||
const std::string& hint, Message::Severity severity)
|
||||
CSMDoc::Messages::Messages(Message::Severity default_)
|
||||
: mDefault(default_)
|
||||
{
|
||||
if (severity==Message::Severity_Default)
|
||||
}
|
||||
|
||||
void CSMDoc::Messages::add(
|
||||
const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint, Message::Severity severity)
|
||||
{
|
||||
if (severity == Message::Severity_Default)
|
||||
severity = mDefault;
|
||||
|
||||
mMessages.push_back (Message (id, message, hint, severity));
|
||||
mMessages.push_back(Message(id, message, hint, severity));
|
||||
}
|
||||
|
||||
CSMDoc::Messages::Iterator CSMDoc::Messages::begin() const
|
||||
|
@ -12,9 +12,9 @@ namespace CSMDoc
|
||||
{
|
||||
enum Severity
|
||||
{
|
||||
Severity_Info = 0, // no problem
|
||||
Severity_Warning = 1, // a potential problem, but we are probably fine
|
||||
Severity_Error = 2, // an error; we are not fine
|
||||
Severity_Info = 0, // no problem
|
||||
Severity_Warning = 1, // a potential problem, but we are probably fine
|
||||
Severity_Error = 2, // an error; we are not fine
|
||||
Severity_SeriousError = 3, // an error so bad we can't even be sure if we are
|
||||
// reporting it correctly
|
||||
Severity_Default = 4
|
||||
@ -27,39 +27,35 @@ namespace CSMDoc
|
||||
|
||||
Message();
|
||||
|
||||
Message (const CSMWorld::UniversalId& id, const std::string& message,
|
||||
const std::string& hint, Severity severity);
|
||||
Message(
|
||||
const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint, Severity severity);
|
||||
|
||||
static std::string toString (Severity severity);
|
||||
static std::string toString(Severity severity);
|
||||
};
|
||||
|
||||
class Messages
|
||||
{
|
||||
public:
|
||||
public:
|
||||
typedef std::vector<Message> Collection;
|
||||
|
||||
typedef std::vector<Message> Collection;
|
||||
typedef Collection::const_iterator Iterator;
|
||||
|
||||
typedef Collection::const_iterator Iterator;
|
||||
private:
|
||||
Collection mMessages;
|
||||
Message::Severity mDefault;
|
||||
|
||||
private:
|
||||
public:
|
||||
Messages(Message::Severity default_);
|
||||
|
||||
Collection mMessages;
|
||||
Message::Severity mDefault;
|
||||
void add(const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint = "",
|
||||
Message::Severity severity = Message::Severity_Default);
|
||||
|
||||
public:
|
||||
Iterator begin() const;
|
||||
|
||||
Messages (Message::Severity default_);
|
||||
|
||||
void add (const CSMWorld::UniversalId& id, const std::string& message,
|
||||
const std::string& hint = "",
|
||||
Message::Severity severity = Message::Severity_Default);
|
||||
|
||||
Iterator begin() const;
|
||||
|
||||
Iterator end() const;
|
||||
Iterator end() const;
|
||||
};
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE (CSMDoc::Message)
|
||||
Q_DECLARE_METATYPE(CSMDoc::Message)
|
||||
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user