mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-21 09:39:56 +00:00
Merge branch 'pandorasbox' into 'master'
Launcher, content selector: support ESM4 files, allow using game files as addon files See merge request OpenMW/openmw!3219
This commit is contained in:
commit
3151452e25
@ -1,7 +1,11 @@
|
||||
#include "cellnameloader.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/esm/format.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/files/openfile.hpp>
|
||||
#include <components/files/qtconversion.hpp>
|
||||
|
||||
QSet<QString> CellNameLoader::getCellNames(const QStringList& contentPaths)
|
||||
@ -16,7 +20,17 @@ QSet<QString> CellNameLoader::getCellNames(const QStringList& contentPaths)
|
||||
continue;
|
||||
try
|
||||
{
|
||||
esmReader.open(Files::pathFromQString(contentPath));
|
||||
std::filesystem::path filepath = Files::pathFromQString(contentPath);
|
||||
auto stream = Files::openBinaryInputFileStream(filepath);
|
||||
if (!stream->is_open())
|
||||
continue;
|
||||
|
||||
const ESM::Format format = ESM::readFormat(*stream);
|
||||
if (format != ESM::Format::Tes3)
|
||||
continue;
|
||||
|
||||
stream->seekg(0);
|
||||
esmReader.open(std::move(stream), filepath);
|
||||
|
||||
// Loop through all records
|
||||
while (esmReader.hasMoreRecs())
|
||||
|
@ -1,13 +1,17 @@
|
||||
#include "contentmodel.hpp"
|
||||
#include "esmfile.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
|
||||
#include <components/esm/format.hpp>
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <components/esm4/reader.hpp>
|
||||
#include <components/files/openfile.hpp>
|
||||
#include <components/files/qtconversion.hpp>
|
||||
|
||||
ContentSelectorModel::ContentModel::ContentModel(QObject* parent, QIcon& warningIcon, bool showOMWScripts)
|
||||
@ -102,7 +106,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex& index
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
// game files can always be checked
|
||||
if (file->isGameFile())
|
||||
if (file == mGameFile)
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
|
||||
|
||||
Qt::ItemFlags returnFlags;
|
||||
@ -212,7 +216,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int
|
||||
|
||||
case Qt::CheckStateRole:
|
||||
{
|
||||
if (file->isGameFile())
|
||||
if (file == mGameFile)
|
||||
return QVariant();
|
||||
|
||||
return mCheckStates[file->filePath()];
|
||||
@ -220,7 +224,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int
|
||||
|
||||
case Qt::UserRole:
|
||||
{
|
||||
if (file->isGameFile())
|
||||
if (file == mGameFile)
|
||||
return ContentType_GameFile;
|
||||
else if (flags(index))
|
||||
return ContentType_Addon;
|
||||
@ -467,29 +471,59 @@ void ContentSelectorModel::ContentModel::addFiles(const QString& path, bool newf
|
||||
|
||||
try
|
||||
{
|
||||
ESM::ESMReader fileReader;
|
||||
ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding.toStdString()));
|
||||
fileReader.setEncoder(&encoder);
|
||||
fileReader.open(Files::pathFromQString(dir.absoluteFilePath(path2)));
|
||||
|
||||
EsmFile* file = new EsmFile(path2);
|
||||
|
||||
for (std::vector<ESM::Header::MasterData>::const_iterator itemIter = fileReader.getGameFiles().begin();
|
||||
itemIter != fileReader.getGameFiles().end(); ++itemIter)
|
||||
file->addGameFile(QString::fromUtf8(itemIter->name.c_str()));
|
||||
|
||||
file->setAuthor(QString::fromUtf8(fileReader.getAuthor().c_str()));
|
||||
file->setDate(info.lastModified());
|
||||
file->setFormat(fileReader.getFormatVersion());
|
||||
file->setFilePath(info.absoluteFilePath());
|
||||
file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str()));
|
||||
std::filesystem::path filepath = Files::pathFromQString(info.absoluteFilePath());
|
||||
|
||||
// HACK
|
||||
// Load order constraint of Bloodmoon.esm needing Tribunal.esm is missing
|
||||
// from the file supplied by Bethesda, so we have to add it ourselves
|
||||
if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0)
|
||||
auto stream = Files::openBinaryInputFileStream(filepath);
|
||||
if (!stream->is_open())
|
||||
{
|
||||
file->addGameFile(QString::fromUtf8("Tribunal.esm"));
|
||||
qWarning() << "Failed to open addon file " << info.fileName() << ": "
|
||||
<< std::generic_category().message(errno).c_str();
|
||||
continue;
|
||||
}
|
||||
const ESM::Format format = ESM::readFormat(*stream);
|
||||
stream->seekg(0);
|
||||
switch (format)
|
||||
{
|
||||
case ESM::Format::Tes3:
|
||||
{
|
||||
ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding.toStdString()));
|
||||
ESM::ESMReader fileReader;
|
||||
fileReader.setEncoder(&encoder);
|
||||
fileReader.open(std::move(stream), filepath);
|
||||
file->setAuthor(QString::fromUtf8(fileReader.getAuthor().c_str()));
|
||||
file->setFormat(fileReader.getFormatVersion());
|
||||
file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str()));
|
||||
for (const auto& master : fileReader.getGameFiles())
|
||||
file->addGameFile(QString::fromUtf8(master.name.c_str()));
|
||||
|
||||
// HACK
|
||||
// Load order constraint of Bloodmoon.esm needing Tribunal.esm is missing
|
||||
// from the file supplied by Bethesda, so we have to add it ourselves
|
||||
if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0)
|
||||
file->addGameFile(QString::fromUtf8("Tribunal.esm"));
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM::Format::Tes4:
|
||||
{
|
||||
ToUTF8::StatelessUtf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding.toStdString()));
|
||||
ESM4::Reader reader(std::move(stream), filepath, nullptr, &encoder, true);
|
||||
file->setAuthor(QString::fromUtf8(reader.getAuthor().c_str()));
|
||||
file->setFormat(reader.esmVersion());
|
||||
file->setDescription(QString::fromUtf8(reader.getDesc().c_str()));
|
||||
for (const auto& master : reader.getGameFiles())
|
||||
file->addGameFile(QString::fromUtf8(master.name.c_str()));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
qWarning() << "Error reading addon file " << info.fileName() << ": unsupported ESM format "
|
||||
<< ESM::NAME(format).toString().c_str();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Put the file in the table
|
||||
@ -543,6 +577,15 @@ QStringList ContentSelectorModel::ContentModel::gameFiles() const
|
||||
return gameFiles;
|
||||
}
|
||||
|
||||
void ContentSelectorModel::ContentModel::setCurrentGameFile(const EsmFile* file)
|
||||
{
|
||||
QModelIndex oldIndex = indexFromItem(mGameFile);
|
||||
QModelIndex index = indexFromItem(file);
|
||||
mGameFile = file;
|
||||
emit dataChanged(oldIndex, oldIndex);
|
||||
emit dataChanged(index, index);
|
||||
}
|
||||
|
||||
void ContentSelectorModel::ContentModel::sortFiles()
|
||||
{
|
||||
emit layoutAboutToBeChanged();
|
||||
@ -557,10 +600,9 @@ void ContentSelectorModel::ContentModel::sortFiles()
|
||||
for (int j = 0; j < i; ++j)
|
||||
{
|
||||
const QStringList& gameFiles = mFiles.at(j)->gameFiles();
|
||||
if (gameFiles.contains(file->fileName(), Qt::CaseInsensitive)
|
||||
|| (!mFiles.at(j)->isGameFile() && gameFiles.isEmpty()
|
||||
&& file->fileName().compare("Morrowind.esm", Qt::CaseInsensitive)
|
||||
== 0)) // Hack: implicit dependency on Morrowind.esm for dependency-less files
|
||||
// All addon files are implicitly dependent on the game file
|
||||
// so that they don't accidentally become the game file
|
||||
if (gameFiles.contains(file->fileName(), Qt::CaseInsensitive) || file == mGameFile)
|
||||
{
|
||||
index = j;
|
||||
break;
|
||||
|
@ -54,6 +54,7 @@ namespace ContentSelectorModel
|
||||
const EsmFile* item(int row) const;
|
||||
EsmFile* item(int row);
|
||||
QStringList gameFiles() const;
|
||||
void setCurrentGameFile(const EsmFile* file);
|
||||
|
||||
bool isEnabled(const QModelIndex& index) const;
|
||||
bool isChecked(const QString& filepath) const;
|
||||
@ -81,6 +82,7 @@ namespace ContentSelectorModel
|
||||
|
||||
QString toolTip(const EsmFile* file) const;
|
||||
|
||||
const EsmFile* mGameFile;
|
||||
ContentFileList mFiles;
|
||||
QStringList mArchives;
|
||||
QHash<QString, Qt::CheckState> mCheckStates;
|
||||
|
@ -232,6 +232,7 @@ void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool s
|
||||
QModelIndex index2(mContentModel->indexFromItem(file));
|
||||
mContentModel->setData(index2, selected, Qt::UserRole + 1);
|
||||
}
|
||||
mContentModel->setCurrentGameFile(selected ? file : nullptr);
|
||||
}
|
||||
|
||||
void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex& index)
|
||||
|
Loading…
x
Reference in New Issue
Block a user