mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe8c3aaea5 | ||
|
|
dda9e11976 | ||
|
|
9945b5e926 | ||
|
|
dbbd0c4eec | ||
|
|
4ff751fb7e | ||
|
|
d8d81ee06f | ||
|
|
a4b69c9ed8 | ||
|
|
053ebc898f | ||
|
|
0bd38e3f67 | ||
|
|
7f4f4cafea |
@@ -83,6 +83,7 @@ SET(organizer_SRCS
|
||||
viewmarkingscrollbar.cpp
|
||||
plugincontainer.cpp
|
||||
organizercore.cpp
|
||||
usvfsconnector.cpp
|
||||
|
||||
shared/inject.cpp
|
||||
shared/windows_error.cpp
|
||||
@@ -91,6 +92,7 @@ SET(organizer_SRCS
|
||||
shared/gameinfo.cpp
|
||||
shared/oblivioninfo.cpp
|
||||
shared/fallout3info.cpp
|
||||
shared/fallout4info.cpp
|
||||
shared/falloutnvinfo.cpp
|
||||
shared/util.cpp
|
||||
shared/skyriminfo.cpp
|
||||
@@ -173,6 +175,7 @@ SET(organizer_HDRS
|
||||
plugincontainer.h
|
||||
organizercore.h
|
||||
iuserinterface.h
|
||||
usvfsconnector.h
|
||||
|
||||
shared/inject.h
|
||||
shared/windows_error.h
|
||||
@@ -181,6 +184,7 @@ SET(organizer_HDRS
|
||||
shared/gameinfo.h
|
||||
shared/oblivioninfo.h
|
||||
shared/fallout3info.h
|
||||
shared/fallout4info.h
|
||||
shared/falloutnvinfo.h
|
||||
shared/util.h
|
||||
shared/skyriminfo.h
|
||||
@@ -282,19 +286,28 @@ INCLUDE_DIRECTORIES(${project_path}/uibase/src
|
||||
${project_path}/bsatk/src
|
||||
${project_path}/esptk/src
|
||||
${project_path}/archive/src
|
||||
${project_path}/../usvfs/usvfs
|
||||
${project_path}/game_features/src)
|
||||
|
||||
INCLUDE_DIRECTORIES(shared ${ZLIB_INCLUDE_DIRS})
|
||||
LINK_DIRECTORIES(${lib_path}
|
||||
${project_path}/../zlib/lib)
|
||||
|
||||
ADD_DEFINITIONS(-D_UNICODE -DUNICODE -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
IF("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
SET(usvfs_name usvfs_x64)
|
||||
ELSE()
|
||||
SET(usvfs_name usvfs_x86)
|
||||
ENDIF()
|
||||
|
||||
ADD_EXECUTABLE(ModOrganizer WIN32 ${organizer_HDRS} ${organizer_SRCS} ${organizer_UIHDRS} ${organizer_RCS} ${organizer_RCCPPS})
|
||||
TARGET_LINK_LIBRARIES(ModOrganizer
|
||||
Qt5::Widgets Qt5::WinExtras Qt5::WebKitWidgets
|
||||
${Boost_LIBRARIES}
|
||||
zlibstatic
|
||||
uibase esptk bsatk
|
||||
${usvfs_name}
|
||||
Dbghelp advapi32 Version Shlwapi)
|
||||
|
||||
SET_TARGET_PROPERTIES(ModOrganizer PROPERTIES COMPILE_FLAGS /GL)
|
||||
|
||||
@@ -36,6 +36,7 @@ IGameInfo::Type GameInfoImpl::type() const
|
||||
switch (GameInfo::instance().getType()) {
|
||||
case GameInfo::TYPE_OBLIVION: return IGameInfo::TYPE_OBLIVION;
|
||||
case GameInfo::TYPE_FALLOUT3: return IGameInfo::TYPE_FALLOUT3;
|
||||
case GameInfo::TYPE_FALLOUT4: return IGameInfo::TYPE_FALLOUT4;
|
||||
case GameInfo::TYPE_FALLOUTNV: return IGameInfo::TYPE_FALLOUTNV;
|
||||
case GameInfo::TYPE_SKYRIM: return IGameInfo::TYPE_SKYRIM;
|
||||
default: throw MyException(QObject::tr("invalid game type %1").arg(GameInfo::instance().getType()));
|
||||
|
||||
@@ -694,7 +694,10 @@ bool InstallationManager::install(const QString &fileName, GuessedValue<QString>
|
||||
bool archiveOpen = m_CurrentArchive->open(ToWString(QDir::toNativeSeparators(fileName)).c_str(),
|
||||
new MethodCallback<InstallationManager, void, LPSTR>(this, &InstallationManager::queryPassword));
|
||||
if (!archiveOpen) {
|
||||
qDebug("integrated archiver can't open %s. errorcode %d", qPrintable(fileName), m_CurrentArchive->getLastError());
|
||||
qDebug("integrated archiver can't open %s: %s (%d)",
|
||||
qPrintable(fileName),
|
||||
qPrintable(getErrorString(m_CurrentArchive->getLastError())),
|
||||
m_CurrentArchive->getLastError());
|
||||
}
|
||||
ON_BLOCK_EXIT(std::bind(&InstallationManager::postInstallCleanup, this));
|
||||
|
||||
|
||||
@@ -26,10 +26,6 @@ public:
|
||||
|
||||
virtual void displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab) = 0;
|
||||
|
||||
virtual void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives) = 0;
|
||||
|
||||
virtual MOBase::DelayedFileWriterBase &archivesWriter() = 0;
|
||||
|
||||
virtual void lock() = 0;
|
||||
virtual void unlock() = 0;
|
||||
virtual bool unlockClicked() = 0;
|
||||
|
||||
@@ -132,6 +132,9 @@ void LoadMechanism::deactivateScriptExtender()
|
||||
|
||||
QDir pluginsDir(game->gameDirectory().absolutePath() + "/data/" + extender->name() + "/plugins");
|
||||
|
||||
#pragma "implement this for usvfs"
|
||||
|
||||
/*
|
||||
QString hookDLLName = ToQString(AppConfig::hookDLLName());
|
||||
if (QFile(pluginsDir.absoluteFilePath(hookDLLName)).exists()) {
|
||||
// remove dll from SE plugins directory
|
||||
@@ -141,6 +144,7 @@ void LoadMechanism::deactivateScriptExtender()
|
||||
}
|
||||
|
||||
removeHintFile(pluginsDir);
|
||||
*/
|
||||
} catch (const std::exception &e) {
|
||||
QMessageBox::critical(nullptr, QObject::tr("Failed to deactivate script extender loading"), e.what());
|
||||
}
|
||||
@@ -191,6 +195,8 @@ void LoadMechanism::activateScriptExtender()
|
||||
pluginsDir.mkpath(".");
|
||||
}
|
||||
|
||||
#pragma message("implement this for usvfs")
|
||||
/*
|
||||
QString targetPath = pluginsDir.absoluteFilePath(ToQString(AppConfig::hookDLLName()));
|
||||
QString hookDLLPath = qApp->applicationDirPath() + "/" + QString::fromStdWString(AppConfig::hookDLLName());
|
||||
|
||||
@@ -210,6 +216,7 @@ void LoadMechanism::activateScriptExtender()
|
||||
}
|
||||
}
|
||||
writeHintFile(pluginsDir);
|
||||
*/
|
||||
} catch (const std::exception &e) {
|
||||
QMessageBox::critical(nullptr, QObject::tr("Failed to set up script extender loading"), e.what());
|
||||
}
|
||||
|
||||
+1
-19
@@ -124,8 +124,6 @@ char LogBuffer::msgTypeID(QtMsgType type)
|
||||
}
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
|
||||
void LogBuffer::log(QtMsgType type, const QMessageLogContext &context, const QString &message)
|
||||
{
|
||||
// QMutexLocker doesn't support timeout...
|
||||
@@ -141,6 +139,7 @@ void LogBuffer::log(QtMsgType type, const QMessageLogContext &context, const QSt
|
||||
s_Instance->logMessage(type, message);
|
||||
}
|
||||
// fprintf(stdout, "(%s:%u) %s\n", context.file, context.line, qPrintable(message));
|
||||
|
||||
if (type == QtDebugMsg) {
|
||||
fprintf(stdout, "%s [%c] %s\n", qPrintable(QTime::currentTime().toString()), msgTypeID(type), qPrintable(message));
|
||||
} else {
|
||||
@@ -154,21 +153,6 @@ void LogBuffer::log(QtMsgType type, const QMessageLogContext &context, const QSt
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void LogBuffer::log(QtMsgType type, const char *message)
|
||||
{
|
||||
QMutexLocker guard(&s_Mutex);
|
||||
if (!s_Instance.isNull()) {
|
||||
s_Instance->logMessage(type, message);
|
||||
}
|
||||
fprintf(stdout, "%s [%c] %s\n", qPrintable(QTime::currentTime().toString()), msgTypeID(type), message);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
QModelIndex LogBuffer::index(int row, int column, const QModelIndex&) const
|
||||
{
|
||||
return createIndex(row, column, row);
|
||||
@@ -269,8 +253,6 @@ void log(const char *format, ...)
|
||||
va_end(argList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString LogBuffer::Message::toString() const
|
||||
{
|
||||
return QString("%1 [%2] %3").arg(time.toString()).arg(msgTypeID(type)).arg(message);
|
||||
|
||||
@@ -35,11 +35,7 @@ class LogBuffer : public QAbstractItemModel
|
||||
public:
|
||||
|
||||
static void init(int messageCount, QtMsgType minMsgType, const QString &outputFileName);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
static void log(QtMsgType type, const QMessageLogContext &context, const QString &message);
|
||||
#else
|
||||
static void log(QtMsgType type, const char *message);
|
||||
#endif
|
||||
|
||||
static void writeNow();
|
||||
static void cleanQuit();
|
||||
|
||||
+1
-15
@@ -123,7 +123,7 @@ bool bootstrap()
|
||||
|
||||
// cycle logfile
|
||||
removeOldFiles(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()),
|
||||
"ModOrganizer*.log", 5, QDir::Name);
|
||||
"usvfs*.log", 5, QDir::Name);
|
||||
|
||||
createAndMakeWritable(AppConfig::profilesPath());
|
||||
createAndMakeWritable(AppConfig::modsPath());
|
||||
@@ -131,19 +131,6 @@ bool bootstrap()
|
||||
createAndMakeWritable(AppConfig::overwritePath());
|
||||
createAndMakeWritable(AppConfig::logPath());
|
||||
|
||||
// verify the hook-dll exists
|
||||
QString dllName = qApp->applicationDirPath() + "/" + ToQString(AppConfig::hookDLLName());
|
||||
|
||||
if (::GetModuleHandleW(ToWString(dllName).c_str()) != nullptr) {
|
||||
throw std::runtime_error("hook.dll already loaded! You can't start Mod Organizer from within itself (not even indirectly)");
|
||||
}
|
||||
|
||||
HMODULE dllMod = ::LoadLibraryW(ToWString(dllName).c_str());
|
||||
if (dllMod == nullptr) {
|
||||
throw windows_error("hook.dll is missing or invalid");
|
||||
}
|
||||
::FreeLibrary(dllMod);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -516,7 +503,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
game->setGameVariant(settings.value("game_edition").toString());
|
||||
|
||||
|
||||
#pragma message("edition isn't used?")
|
||||
qDebug("managing game at %s", qPrintable(QDir::toNativeSeparators(gamePath)));
|
||||
|
||||
|
||||
+5
-237
@@ -162,7 +162,6 @@ MainWindow::MainWindow(const QString &exeName
|
||||
, m_OrganizerCore(organizerCore)
|
||||
, m_PluginContainer(pluginContainer)
|
||||
, m_DidUpdateMasterList(false)
|
||||
, m_ArchiveListWriter(std::bind(&MainWindow::saveArchiveList, this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
updateWindowTitle(QString(), false);
|
||||
@@ -187,6 +186,7 @@ MainWindow::MainWindow(const QString &exeName
|
||||
m_RefreshProgress->setVisible(false);
|
||||
statusBar()->addWidget(m_RefreshProgress, 1000);
|
||||
statusBar()->clearMessage();
|
||||
statusBar()->hide();
|
||||
|
||||
ui->actionEndorseMO->setVisible(false);
|
||||
|
||||
@@ -234,8 +234,6 @@ MainWindow::MainWindow(const QString &exeName
|
||||
}
|
||||
ui->espList->installEventFilter(m_OrganizerCore.pluginList());
|
||||
|
||||
ui->bsaList->setLocalMoveOnly(true);
|
||||
|
||||
ui->splitter->setStretchFactor(0, 3);
|
||||
ui->splitter->setStretchFactor(1, 2);
|
||||
|
||||
@@ -265,8 +263,6 @@ MainWindow::MainWindow(const QString &exeName
|
||||
connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), m_PluginListSortProxy, SLOT(updateFilter(QString)));
|
||||
connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), this, SLOT(espFilterChanged(QString)));
|
||||
|
||||
connect(ui->bsaList, SIGNAL(itemsMoved()), this, SLOT(bsaList_itemMoved()));
|
||||
|
||||
connect(ui->dataTree, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(expandDataTreeItem(QTreeWidgetItem*)));
|
||||
|
||||
connect(m_OrganizerCore.directoryRefresher(), SIGNAL(refreshed()), this, SLOT(directory_refreshed()));
|
||||
@@ -305,9 +301,6 @@ MainWindow::MainWindow(const QString &exeName
|
||||
|
||||
connect(this, SIGNAL(styleChanged(QString)), this, SLOT(updateStyle(QString)));
|
||||
|
||||
m_CheckBSATimer.setSingleShot(true);
|
||||
connect(&m_CheckBSATimer, SIGNAL(timeout()), this, SLOT(checkBSAList()));
|
||||
|
||||
m_UpdateProblemsTimer.setSingleShot(true);
|
||||
connect(&m_UpdateProblemsTimer, SIGNAL(timeout()), this, SLOT(updateProblemsButton()));
|
||||
|
||||
@@ -1320,164 +1313,6 @@ static QStringList toStringList(InputIterator current, InputIterator end)
|
||||
return result;
|
||||
}
|
||||
|
||||
void MainWindow::updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives)
|
||||
{
|
||||
m_DefaultArchives = defaultArchives;
|
||||
ui->bsaList->clear();
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
ui->bsaList->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
#else
|
||||
ui->bsaList->header()->setResizeMode(QHeaderView::ResizeToContents);
|
||||
#endif
|
||||
|
||||
std::vector<std::pair<UINT32, QTreeWidgetItem*>> items;
|
||||
|
||||
IPluginGame *gamePlugin = qApp->property("managed_game").value<IPluginGame*>();
|
||||
BSAInvalidation *invalidation = gamePlugin->feature<BSAInvalidation>();
|
||||
std::vector<FileEntry::Ptr> files = m_OrganizerCore.directoryStructure()->getFiles();
|
||||
|
||||
QStringList plugins = m_OrganizerCore.findFiles("", [] (const QString &fileName) -> bool {
|
||||
return fileName.endsWith(".esp", Qt::CaseInsensitive)
|
||||
|| fileName.endsWith(".esm", Qt::CaseInsensitive);
|
||||
});
|
||||
|
||||
auto hasAssociatedPlugin = [&](const QString &bsaName) -> bool {
|
||||
for (const QString &pluginName : plugins) {
|
||||
QFileInfo pluginInfo(pluginName);
|
||||
if (bsaName.startsWith(QFileInfo(pluginName).baseName(), Qt::CaseInsensitive)
|
||||
&& (m_OrganizerCore.pluginList()->state(pluginInfo.fileName()) == IPluginList::STATE_ACTIVE)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (FileEntry::Ptr current : files) {
|
||||
QFileInfo fileInfo(ToQString(current->getName().c_str()));
|
||||
|
||||
if (fileInfo.suffix().toLower() == "bsa") {
|
||||
int index = activeArchives.indexOf(fileInfo.fileName());
|
||||
if (index == -1) {
|
||||
index = 0xFFFF;
|
||||
} else {
|
||||
index += 2;
|
||||
}
|
||||
|
||||
if ((invalidation != nullptr) && invalidation->isInvalidationBSA(fileInfo.fileName())) {
|
||||
index = 1;
|
||||
}
|
||||
|
||||
int originId = current->getOrigin();
|
||||
FilesOrigin &origin = m_OrganizerCore.directoryStructure()->getOriginByID(originId);
|
||||
|
||||
QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList()
|
||||
<< fileInfo.fileName()
|
||||
<< ToQString(origin.getName()));
|
||||
newItem->setData(0, Qt::UserRole, index);
|
||||
newItem->setData(1, Qt::UserRole, originId);
|
||||
newItem->setFlags(newItem->flags() & ~Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable);
|
||||
newItem->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked);
|
||||
newItem->setData(0, Qt::UserRole, false);
|
||||
if (m_OrganizerCore.settings().forceEnableCoreFiles()
|
||||
&& defaultArchives.contains(fileInfo.fileName())) {
|
||||
newItem->setCheckState(0, Qt::Checked);
|
||||
newItem->setDisabled(true);
|
||||
newItem->setData(0, Qt::UserRole, true);
|
||||
} else if (fileInfo.fileName().compare("update.bsa", Qt::CaseInsensitive) == 0) {
|
||||
newItem->setCheckState(0, Qt::Checked);
|
||||
newItem->setDisabled(true);
|
||||
} else if (hasAssociatedPlugin(fileInfo.fileName())) {
|
||||
newItem->setCheckState(0, Qt::Checked);
|
||||
newItem->setDisabled(true);
|
||||
} else {
|
||||
if (ui->manageArchivesBox->isChecked()) {
|
||||
newItem->setCheckState(0, (index != 0xFFFF) ? Qt::Checked : Qt::Unchecked);
|
||||
} else {
|
||||
newItem->setCheckState(0, Qt::Unchecked);
|
||||
newItem->setDisabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) index = 0;
|
||||
|
||||
UINT32 sortValue = ((origin.getPriority() & 0xFFFF) << 16) | (index & 0xFFFF);
|
||||
items.push_back(std::make_pair(sortValue, newItem));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(items.begin(), items.end(), BySortValue);
|
||||
|
||||
for (auto iter = items.begin(); iter != items.end(); ++iter) {
|
||||
int originID = iter->second->data(1, Qt::UserRole).toInt();
|
||||
|
||||
FilesOrigin origin = m_OrganizerCore.directoryStructure()->getOriginByID(originID);
|
||||
QString modName("data");
|
||||
unsigned int modIndex = ModInfo::getIndex(ToQString(origin.getName()));
|
||||
if (modIndex != UINT_MAX) {
|
||||
ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
|
||||
modName = modInfo->name();
|
||||
}
|
||||
QList<QTreeWidgetItem*> items = ui->bsaList->findItems(modName, Qt::MatchFixedString);
|
||||
QTreeWidgetItem *subItem = nullptr;
|
||||
if (items.length() > 0) {
|
||||
subItem = items.at(0);
|
||||
} else {
|
||||
subItem = new QTreeWidgetItem(QStringList(modName));
|
||||
subItem->setFlags(subItem->flags() & ~Qt::ItemIsDragEnabled);
|
||||
ui->bsaList->addTopLevelItem(subItem);
|
||||
}
|
||||
subItem->addChild(iter->second);
|
||||
subItem->setExpanded(true);
|
||||
}
|
||||
|
||||
checkBSAList();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::checkBSAList()
|
||||
{
|
||||
DataArchives *archives = m_OrganizerCore.managedGame()->feature<DataArchives>();
|
||||
|
||||
if (archives != nullptr) {
|
||||
ui->bsaList->blockSignals(true);
|
||||
ON_BLOCK_EXIT([&] () { ui->bsaList->blockSignals(false); });
|
||||
|
||||
QStringList defaultArchives = archives->archives(m_OrganizerCore.currentProfile());
|
||||
|
||||
bool warning = false;
|
||||
|
||||
for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
|
||||
bool modWarning = false;
|
||||
QTreeWidgetItem *tlItem = ui->bsaList->topLevelItem(i);
|
||||
for (int j = 0; j < tlItem->childCount(); ++j) {
|
||||
QTreeWidgetItem *item = tlItem->child(j);
|
||||
QString filename = item->text(0);
|
||||
item->setIcon(0, QIcon());
|
||||
item->setToolTip(0, QString());
|
||||
|
||||
if (item->checkState(0) == Qt::Unchecked) {
|
||||
if (defaultArchives.contains(filename)) {
|
||||
item->setIcon(0, QIcon(":/MO/gui/warning"));
|
||||
item->setToolTip(0, tr("This bsa is enabled in the ini file so it may be required!"));
|
||||
modWarning = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (modWarning) {
|
||||
ui->bsaList->expandItem(ui->bsaList->topLevelItem(i));
|
||||
warning = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (warning) {
|
||||
ui->tabWidget->setTabIcon(1, QIcon(":/MO/gui/warning"));
|
||||
} else {
|
||||
ui->tabWidget->setTabIcon(1, QIcon());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::saveModMetas()
|
||||
{
|
||||
for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) {
|
||||
@@ -1486,7 +1321,6 @@ void MainWindow::saveModMetas()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::fixCategories()
|
||||
{
|
||||
for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) {
|
||||
@@ -1557,10 +1391,6 @@ void MainWindow::readSettings()
|
||||
if (settings.value("Settings/use_proxy", false).toBool()) {
|
||||
activateProxy(true);
|
||||
}
|
||||
|
||||
ui->manageArchivesBox->blockSignals(true);
|
||||
ui->manageArchivesBox->setChecked(settings.value("manage_bsas", true).toBool());
|
||||
ui->manageArchivesBox->blockSignals(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -1578,7 +1408,6 @@ void MainWindow::storeSettings(QSettings &settings)
|
||||
settings.setValue("browser_geometry", m_IntegratedBrowser.saveGeometry());
|
||||
|
||||
settings.setValue("filters_visible", ui->displayCategoriesBtn->isChecked());
|
||||
settings.setValue("manage_bsas", ui->manageArchivesBox->isChecked());
|
||||
|
||||
settings.setValue("selected_executable", ui->executablesListBox->currentIndex());
|
||||
}
|
||||
@@ -1871,8 +1700,10 @@ void MainWindow::setESPListSorting(int index)
|
||||
void MainWindow::refresher_progress(int percent)
|
||||
{
|
||||
if (percent == 100) {
|
||||
// m_RefreshProgress->setVisible(false);
|
||||
m_RefreshProgress->setVisible(false);
|
||||
statusBar()->hide();
|
||||
} else if (!m_RefreshProgress->isVisible()) {
|
||||
statusBar()->show();
|
||||
m_RefreshProgress->setVisible(true);
|
||||
m_RefreshProgress->setRange(0, 100);
|
||||
m_RefreshProgress->setValue(percent);
|
||||
@@ -1900,7 +1731,6 @@ void MainWindow::modorder_changed()
|
||||
}
|
||||
m_OrganizerCore.refreshBSAList();
|
||||
m_OrganizerCore.currentProfile()->modlistWriter().write();
|
||||
m_ArchiveListWriter.write();
|
||||
m_OrganizerCore.directoryStructure()->getFileRegister()->sortOrigins();
|
||||
|
||||
{ // refresh selection
|
||||
@@ -2809,30 +2639,6 @@ void MainWindow::savePrimaryCategory()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::saveArchiveList()
|
||||
{
|
||||
if (m_OrganizerCore.isArchivesInit()) {
|
||||
SafeWriteFile archiveFile(m_OrganizerCore.currentProfile()->getArchivesFileName());
|
||||
for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
|
||||
QTreeWidgetItem *tlItem = ui->bsaList->topLevelItem(i);
|
||||
for (int j = 0; j < tlItem->childCount(); ++j) {
|
||||
QTreeWidgetItem *item = tlItem->child(j);
|
||||
if (item->checkState(0) == Qt::Checked) {
|
||||
// in managed mode, "register" all enabled archives, otherwise register only the files registered in the ini
|
||||
if (ui->manageArchivesBox->isChecked()
|
||||
|| item->data(0, Qt::UserRole).toBool()) {
|
||||
archiveFile->write(item->text(0).toUtf8().append("\r\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (archiveFile.commitIfDifferent(m_ArchiveListHash)) {
|
||||
qDebug("%s saved", qPrintable(QDir::toNativeSeparators(m_OrganizerCore.currentProfile()->getArchivesFileName())));
|
||||
}
|
||||
} else {
|
||||
qWarning("archive list not initialised");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::checkModsForUpdates()
|
||||
{
|
||||
@@ -3855,8 +3661,7 @@ void MainWindow::updateDownloadListDelegate()
|
||||
|
||||
void MainWindow::modDetailsUpdated(bool)
|
||||
{
|
||||
--m_ModsToUpdate;
|
||||
if (m_ModsToUpdate == 0) {
|
||||
if (--m_ModsToUpdate == 0) {
|
||||
statusBar()->hide();
|
||||
m_ModListSortProxy->setCategoryFilter(boost::assign::list_of(CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE));
|
||||
for (int i = 0; i < ui->categoriesList->topLevelItemCount(); ++i) {
|
||||
@@ -4062,32 +3867,6 @@ void MainWindow::displayColumnSelection(const QPoint &pos)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_bsaList_customContextMenuRequested(const QPoint &pos)
|
||||
{
|
||||
m_ContextItem = ui->bsaList->itemAt(pos);
|
||||
|
||||
// m_ContextRow = ui->bsaList->indexOfTopLevelItem(ui->bsaList->itemAt(pos));
|
||||
|
||||
QMenu menu;
|
||||
menu.addAction(tr("Extract..."), this, SLOT(extractBSATriggered()));
|
||||
|
||||
menu.exec(ui->bsaList->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void MainWindow::bsaList_itemMoved()
|
||||
{
|
||||
m_ArchiveListWriter.write();
|
||||
m_CheckBSATimer.start(500);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int)
|
||||
{
|
||||
m_ArchiveListWriter.write();
|
||||
m_CheckBSATimer.start(500);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionProblems_triggered()
|
||||
{
|
||||
ProblemsDialog problems(m_PluginContainer.plugins<IPluginDiagnose>(), this);
|
||||
@@ -4663,17 +4442,6 @@ void MainWindow::on_categoriesOrBtn_toggled(bool checked)
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_managedArchiveLabel_linkHovered(const QString&)
|
||||
{
|
||||
QToolTip::showText(QCursor::pos(),
|
||||
ui->managedArchiveLabel->toolTip());
|
||||
}
|
||||
|
||||
void MainWindow::on_manageArchivesBox_toggled(bool)
|
||||
{
|
||||
m_OrganizerCore.refreshBSAList();
|
||||
}
|
||||
|
||||
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
//Accept copy or move drags to the download window. Link drags are not
|
||||
|
||||
+2
-18
@@ -73,8 +73,8 @@ class MainWindow : public QMainWindow, public IUserInterface
|
||||
|
||||
friend class OrganizerProxy;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
explicit MainWindow(const QString &exeName, QSettings &initSettings,
|
||||
OrganizerCore &organizerCore, PluginContainer &pluginContainer,
|
||||
QWidget *parent = 0);
|
||||
@@ -88,15 +88,12 @@ public:
|
||||
virtual bool unlockClicked() override;
|
||||
|
||||
bool addProfile();
|
||||
void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives);
|
||||
void refreshDataTree();
|
||||
void refreshSaveList();
|
||||
|
||||
void setModListSorting(int index);
|
||||
void setESPListSorting(int index);
|
||||
|
||||
void saveArchiveList();
|
||||
|
||||
void registerPluginTool(MOBase::IPluginTool *tool);
|
||||
void registerModPage(MOBase::IPluginModPage *modPage);
|
||||
|
||||
@@ -119,9 +116,8 @@ public:
|
||||
virtual bool closeWindow();
|
||||
virtual void setWindowEnabled(bool enabled);
|
||||
|
||||
virtual MOBase::DelayedFileWriterBase &archivesWriter() override { return m_ArchiveListWriter; }
|
||||
|
||||
void updateWindowTitle(const QString &accountName, bool premium);
|
||||
|
||||
public slots:
|
||||
|
||||
void displayColumnSelection(const QPoint &pos);
|
||||
@@ -135,7 +131,6 @@ public slots:
|
||||
|
||||
signals:
|
||||
|
||||
|
||||
/**
|
||||
* @brief emitted after the information dialog has been closed
|
||||
*/
|
||||
@@ -319,14 +314,10 @@ private:
|
||||
|
||||
std::vector<QTreeWidgetItem*> m_RemoveWidget;
|
||||
|
||||
QByteArray m_ArchiveListHash;
|
||||
|
||||
bool m_DidUpdateMasterList;
|
||||
|
||||
LockedDialog *m_LockDialog { nullptr };
|
||||
|
||||
MOBase::DelayedFileWriter m_ArchiveListWriter;
|
||||
|
||||
enum class ShortcutType {
|
||||
Toolbar,
|
||||
Desktop,
|
||||
@@ -447,8 +438,6 @@ private slots:
|
||||
|
||||
void startExeAction();
|
||||
|
||||
void checkBSAList();
|
||||
|
||||
void updateProblemsButton();
|
||||
|
||||
void saveModMetas();
|
||||
@@ -502,8 +491,6 @@ private slots: // ui slots
|
||||
void on_actionUpdate_triggered();
|
||||
void on_actionEndorseMO_triggered();
|
||||
|
||||
void on_bsaList_customContextMenuRequested(const QPoint &pos);
|
||||
void bsaList_itemMoved();
|
||||
void on_btnRefreshData_clicked();
|
||||
void on_categoriesList_customContextMenuRequested(const QPoint &pos);
|
||||
void on_conflictsCheckBox_toggled(bool checked);
|
||||
@@ -522,7 +509,6 @@ private slots: // ui slots
|
||||
void on_categoriesList_itemSelectionChanged();
|
||||
void on_linkButton_pressed();
|
||||
void on_showHiddenBox_toggled(bool checked);
|
||||
void on_bsaList_itemChanged(QTreeWidgetItem *item, int column);
|
||||
void on_bossButton_clicked();
|
||||
|
||||
void on_saveButton_clicked();
|
||||
@@ -532,8 +518,6 @@ private slots: // ui slots
|
||||
void on_actionCopy_Log_to_Clipboard_triggered();
|
||||
void on_categoriesAndBtn_toggled(bool checked);
|
||||
void on_categoriesOrBtn_toggled(bool checked);
|
||||
void on_managedArchiveLabel_linkHovered(const QString &link);
|
||||
void on_manageArchivesBox_toggled(bool checked);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -884,112 +884,6 @@ p, li { white-space: pre-wrap; }
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="bsaTab">
|
||||
<attribute name="title">
|
||||
<string>Archives</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9" stretch="0,1">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="manageArchivesBox">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="managedArchiveLabel">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>BSAs are bundles of game assets (textures, scripts, ...). By default, the engine loads these bundles in a separate step from loose files. MO can manage those archives to align their load order with that of loose files:</p><p>If archives are <span style=" font-weight:600;">managed</span>, their load order is specified by the priority of the corresponding mod (left pane), the same as the loose files. You can manually enable any BSA that has no corresponding plugin active.<br/></p><p>If archives are <span style=" font-weight:600;">not managed</span> their load order is specified by the priority of the corresponding plugin (right pane, plugins tab). You can then not manually enable BSAs where the plugin isn't active.</p><p>In either case you can not disable archives if there is a matching plugin, the game will load them no matter what.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Have MO manage archives (<a href="#"><span style=" text-decoration: underline; color:#0000ff;">read more</span></a>)</p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MOBase::SortableTreeWidget" name="bsaList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded.
|
||||
By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored!
|
||||
|
||||
BSAs checked here are loaded in such a way that your installation order is obeyed properly.</string>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="showDropIndicator" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="dragDropOverwriteMode">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DragDrop</enum>
|
||||
</property>
|
||||
<property name="defaultDropAction">
|
||||
<enum>Qt::MoveAction</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="indentation">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="itemsExpandable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="headerDefaultSectionSize">
|
||||
<number>200</number>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>File</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="dataTab">
|
||||
<attribute name="title">
|
||||
<string>Data</string>
|
||||
@@ -1487,11 +1381,6 @@ Right now this has very limited functionality</string>
|
||||
<extends>QTreeView</extends>
|
||||
<header>modlistview.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MOBase::SortableTreeWidget</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header>sortabletreewidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="resources.qrc"/>
|
||||
|
||||
@@ -83,7 +83,7 @@ void NexusBridge::nxmFilesAvailable(int modID, QVariant userData, QVariant resul
|
||||
|
||||
QVariantList resultList = resultData.toList();
|
||||
|
||||
foreach(QVariant file, resultList) {
|
||||
for (const QVariant &file : resultList) {
|
||||
ModRepositoryFileInfo temp;
|
||||
QVariantMap fileInfo = file.toMap();
|
||||
temp.uri = fileInfo["uri"].toString();
|
||||
@@ -536,8 +536,10 @@ void NexusInterface::requestError(QNetworkReply::NetworkError)
|
||||
return;
|
||||
}
|
||||
|
||||
qCritical("request (%s) error: %s",
|
||||
qPrintable(reply->url().toString()), qPrintable(reply->errorString()));
|
||||
qCritical("request (%s) error: %s (%d)",
|
||||
qPrintable(reply->url().toString()),
|
||||
qPrintable(reply->errorString()),
|
||||
reply->error());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,11 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
|
||||
m_LoginTimeout.setInterval(30000);
|
||||
setCookieJar(new PersistentCookieJar(
|
||||
QDir::fromNativeSeparators(Settings::instance().getCacheDirectory() + "/nexus_cookies.dat")));
|
||||
|
||||
if (networkAccessible() == QNetworkAccessManager::UnknownAccessibility) {
|
||||
// why is this necessary all of a sudden?
|
||||
setNetworkAccessible(QNetworkAccessManager::Accessible);
|
||||
}
|
||||
}
|
||||
|
||||
NXMAccessManager::~NXMAccessManager()
|
||||
|
||||
+41
-27
@@ -990,6 +990,7 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, const QString &
|
||||
|
||||
// TODO: should also pass arguments
|
||||
if (m_AboutToRun(binary.absoluteFilePath())) {
|
||||
m_USVFS.updateMapping(fileMapping());
|
||||
return startBinary(binary, arguments, profileName, m_Settings.logLevel(), currentDirectory, true);
|
||||
} else {
|
||||
qDebug("start of \"%s\" canceled by plugin", qPrintable(binary.absoluteFilePath()));
|
||||
@@ -1185,10 +1186,6 @@ void OrganizerCore::refreshBSAList()
|
||||
m_ActiveArchives = m_DefaultArchives;
|
||||
}
|
||||
|
||||
if (m_UserInterface != nullptr) {
|
||||
m_UserInterface->updateBSAList(m_DefaultArchives, m_ActiveArchives);
|
||||
}
|
||||
|
||||
m_ArchivesInit = true;
|
||||
}
|
||||
}
|
||||
@@ -1247,9 +1244,7 @@ void OrganizerCore::updateModInDirectoryStructure(unsigned int index, ModInfo::P
|
||||
updateModActiveState(index, true);
|
||||
// now we need to refresh the bsa list and save it so there is no confusion about what archives are avaiable and active
|
||||
refreshBSAList();
|
||||
if (m_UserInterface != nullptr) {
|
||||
m_UserInterface->archivesWriter().write();
|
||||
}
|
||||
|
||||
std::vector<QString> archives = enabledArchives();
|
||||
m_DirectoryRefresher.setMods(m_CurrentProfile->getActiveMods(),
|
||||
std::set<QString>(archives.begin(), archives.end()));
|
||||
@@ -1394,9 +1389,6 @@ void OrganizerCore::modStatusChanged(unsigned int index)
|
||||
FilesOrigin &origin = m_DirectoryStructure->getOriginByName(ToWString(modInfo->name()));
|
||||
origin.enable(false);
|
||||
}
|
||||
if (m_UserInterface != nullptr) {
|
||||
m_UserInterface->archivesWriter().write();
|
||||
}
|
||||
}
|
||||
modInfo->clearCaches();
|
||||
|
||||
@@ -1535,9 +1527,6 @@ bool OrganizerCore::saveCurrentLists()
|
||||
|
||||
try {
|
||||
savePluginList();
|
||||
if (m_UserInterface != nullptr) {
|
||||
m_UserInterface->archivesWriter().write();
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
reportError(tr("failed to save load order: %1").arg(e.what()));
|
||||
}
|
||||
@@ -1571,21 +1560,30 @@ void OrganizerCore::prepareStart() {
|
||||
storeSettings();
|
||||
}
|
||||
|
||||
std::vector<std::pair<QString, QString>> OrganizerCore::fileMapping()
|
||||
std::vector<Mapping> OrganizerCore::fileMapping()
|
||||
{
|
||||
IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>();
|
||||
return fileMapping(game->dataDirectory().absolutePath(),
|
||||
directoryStructure(),
|
||||
directoryStructure());
|
||||
IPluginGame *game = qApp->property("managed_game").value<IPluginGame *>();
|
||||
MappingType result = fileMapping(
|
||||
QDir::toNativeSeparators(game->dataDirectory().absolutePath()),
|
||||
"\\",
|
||||
directoryStructure(), directoryStructure());
|
||||
|
||||
for (MOBase::IPluginFileMapper *mapper : m_PluginContainer->plugins<MOBase::IPluginFileMapper>()) {
|
||||
MappingType pluginMap = mapper->mappings();
|
||||
result.reserve(result.size() + pluginMap.size());
|
||||
result.insert(result.end(), pluginMap.begin(), pluginMap.end());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::pair<QString, QString>> OrganizerCore::fileMapping(
|
||||
std::vector<Mapping> OrganizerCore::fileMapping(
|
||||
const QString &dataPath,
|
||||
const QString &relPath,
|
||||
const DirectoryEntry *base,
|
||||
const DirectoryEntry *directoryEntry)
|
||||
{
|
||||
std::vector<std::pair<QString, QString>> result;
|
||||
std::vector<Mapping> result;
|
||||
|
||||
for (FileEntry::Ptr current : directoryEntry->getFiles()) {
|
||||
bool isArchive = false;
|
||||
@@ -1594,20 +1592,36 @@ std::vector<std::pair<QString, QString>> OrganizerCore::fileMapping(
|
||||
continue;
|
||||
}
|
||||
|
||||
QString fileName = ToQString(current->getRelativePath());
|
||||
QString source = ToQString(base->getOriginByID(origin).getPath()) + fileName;
|
||||
QString target = QDir::toNativeSeparators(dataPath) + fileName;
|
||||
result.push_back(std::make_pair(source, target));
|
||||
QString originPath
|
||||
= QString::fromStdWString(base->getOriginByID(origin).getPath());
|
||||
QString fileName = QString::fromStdWString(current->getName());
|
||||
QString source = originPath + relPath + fileName;
|
||||
QString target = dataPath + relPath + fileName;
|
||||
if (source != target) {
|
||||
result.push_back({source, target, false});
|
||||
}
|
||||
}
|
||||
|
||||
// recurse into subdirectories
|
||||
std::vector<DirectoryEntry*>::const_iterator current, end;
|
||||
directoryEntry->getSubDirectories(current, end);
|
||||
for (; current != end; ++current) {
|
||||
std::vector<std::pair<QString, QString>> subRes = fileMapping(dataPath, base, *current);
|
||||
int origin = (*current)->anyOrigin();
|
||||
if (origin == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString originPath
|
||||
= QString::fromStdWString(base->getOriginByID(origin).getPath());
|
||||
QString dirName = QString::fromStdWString((*current)->getName());
|
||||
QString source = originPath + relPath + dirName;
|
||||
QString target = dataPath + relPath + dirName;
|
||||
|
||||
result.push_back({source, target, true});
|
||||
std::vector<Mapping> subRes
|
||||
= fileMapping(dataPath, relPath + dirName + "\\", base, *current);
|
||||
result.insert(result.end(), subRes.begin(), subRes.end());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+10
-4
@@ -14,6 +14,7 @@
|
||||
#include "modlistsortproxy.h"
|
||||
#include "pluginlistsortproxy.h"
|
||||
#include "executableslist.h"
|
||||
#include "usvfsconnector.h"
|
||||
#include <directoryentry.h>
|
||||
#include <imoinfo.h>
|
||||
#include <iplugindiagnose.h>
|
||||
@@ -157,7 +158,10 @@ public:
|
||||
bool onFinishedRun(const std::function<void (const QString &, unsigned int)> &func);
|
||||
void refreshModList(bool saveChanges = true);
|
||||
|
||||
std::vector<std::pair<QString, QString> > fileMapping();
|
||||
/**
|
||||
* @brief return a descriptor of the mappings real file->virtual file
|
||||
*/
|
||||
std::vector<Mapping> fileMapping();
|
||||
|
||||
public: // IPluginDiagnose interface
|
||||
|
||||
@@ -210,9 +214,10 @@ private:
|
||||
|
||||
bool testForSteam();
|
||||
|
||||
std::vector<std::pair<QString, QString>> fileMapping(const QString &dataPath,
|
||||
const MOShared::DirectoryEntry *base,
|
||||
const MOShared::DirectoryEntry *directoryEntry);
|
||||
std::vector<Mapping>
|
||||
fileMapping(const QString &dataPath, const QString &relPath,
|
||||
const MOShared::DirectoryEntry *base,
|
||||
const MOShared::DirectoryEntry *directoryEntry);
|
||||
|
||||
private slots:
|
||||
|
||||
@@ -270,6 +275,7 @@ private:
|
||||
bool m_ArchivesInit;
|
||||
|
||||
MOBase::DelayedFileWriter m_PluginListsWriter;
|
||||
UsvfsConnector m_USVFS;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName)
|
||||
m_Organizer->settings().registerPlugin(pluginObj);
|
||||
}
|
||||
|
||||
{ // diagnosis plugins
|
||||
{ // diagnosis plugin
|
||||
IPluginDiagnose *diagnose = qobject_cast<IPluginDiagnose*>(plugin);
|
||||
if (diagnose != nullptr) {
|
||||
bf::at_key<IPluginDiagnose>(m_Plugins).push_back(diagnose);
|
||||
@@ -96,6 +96,12 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName)
|
||||
);
|
||||
}
|
||||
}
|
||||
{ // file mapper plugin
|
||||
IPluginFileMapper *mapper = qobject_cast<IPluginFileMapper*>(plugin);
|
||||
if (mapper != nullptr) {
|
||||
bf::at_key<IPluginFileMapper>(m_Plugins).push_back(mapper);
|
||||
}
|
||||
}
|
||||
{ // mod page plugin
|
||||
IPluginModPage *modPage = qobject_cast<IPluginModPage*>(plugin);
|
||||
if (verifyPlugin(modPage)) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <iplugintool.h>
|
||||
#include <ipluginproxy.h>
|
||||
#include <iplugininstaller.h>
|
||||
#include <ipluginfilemapper.h>
|
||||
#include <QtPlugin>
|
||||
#include <QPluginLoader>
|
||||
#include <QFile>
|
||||
@@ -36,7 +37,8 @@ private:
|
||||
boost::fusion::pair<MOBase::IPluginModPage, std::vector<MOBase::IPluginModPage*>>,
|
||||
boost::fusion::pair<MOBase::IPluginPreview, std::vector<MOBase::IPluginPreview*>>,
|
||||
boost::fusion::pair<MOBase::IPluginTool, std::vector<MOBase::IPluginTool*>>,
|
||||
boost::fusion::pair<MOBase::IPluginProxy, std::vector<MOBase::IPluginProxy*>>
|
||||
boost::fusion::pair<MOBase::IPluginProxy, std::vector<MOBase::IPluginProxy*>>,
|
||||
boost::fusion::pair<MOBase::IPluginFileMapper, std::vector<MOBase::IPluginFileMapper*>>
|
||||
> PluginMap;
|
||||
|
||||
static const unsigned int PROBLEM_PLUGINSNOTLOADED = 1;
|
||||
|
||||
+3
-1
@@ -585,7 +585,9 @@ bool Profile::invalidationActive(bool *supported) const
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
*supported = false;
|
||||
if (supported != nullptr) {
|
||||
*supported = false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -117,9 +117,6 @@ SaveGameGamebryo::~SaveGameGamebryo()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void SaveGameGamebryo::readSkyrimFile(QFile &saveFile)
|
||||
{
|
||||
char fileID[14];
|
||||
@@ -172,6 +169,58 @@ void SaveGameGamebryo::readSkyrimFile(QFile &saveFile)
|
||||
}
|
||||
}
|
||||
|
||||
void SaveGameGamebryo::readFO4File(QFile &saveFile)
|
||||
{
|
||||
char fileID[13];
|
||||
|
||||
saveFile.read(fileID, 12);
|
||||
fileID[12] = '\0';
|
||||
if (strncmp(fileID, "FO4_SAVEGAME", 12) != 0) {
|
||||
throw std::runtime_error(QObject::tr("wrong file format").toUtf8().constData());
|
||||
}
|
||||
|
||||
FileSkip<unsigned long>(saveFile); // header size
|
||||
FileSkip<unsigned long>(saveFile); // header version, -> 11
|
||||
FileRead(saveFile, m_SaveNumber);
|
||||
|
||||
m_PCName = ReadFOSString(saveFile, false);
|
||||
|
||||
unsigned long temp;
|
||||
FileRead(saveFile, temp); // player level
|
||||
m_PCLevel = static_cast<unsigned short>(temp);
|
||||
|
||||
m_PCLocation = ReadFOSString(saveFile, false);
|
||||
ReadFOSString(saveFile, false); // playtime as ascii hhh.mm.ss
|
||||
ReadFOSString(saveFile, false); // race name (HumanRace)
|
||||
|
||||
|
||||
FileSkip<unsigned short>(saveFile); // ???
|
||||
FileSkip<float>(saveFile, 2); // ???
|
||||
FileSkip<unsigned char>(saveFile, 8); // filetime
|
||||
|
||||
// FileSkip<unsigned char>(saveFile, 18); // ??? 18 bytes of data. not completely random, maybe a time stamp? maybe
|
||||
|
||||
unsigned long width, height;
|
||||
FileRead(saveFile, width); // 640
|
||||
FileRead(saveFile, height); // 384
|
||||
|
||||
QScopedArrayPointer<unsigned char> buffer(new unsigned char[width * height * 4]);
|
||||
saveFile.read(reinterpret_cast<char*>(buffer.data()), width * height * 4);
|
||||
// 640x384 is a bit large
|
||||
m_Screenshot = QImage(buffer.data(), width, height, QImage::Format_RGBA8888).scaledToWidth(320);
|
||||
|
||||
FileSkip<unsigned char>(saveFile); // form version (?)
|
||||
ReadFOSString(saveFile, false); // game version
|
||||
FileSkip<unsigned long>(saveFile); // plugin info size (?)
|
||||
|
||||
unsigned char pluginCount;
|
||||
FileRead(saveFile, pluginCount);
|
||||
|
||||
for (int i = 0; i < pluginCount; ++i) {
|
||||
m_Plugins.push_back(ReadFOSString(saveFile, false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SaveGameGamebryo::readESSFile(QFile &saveFile)
|
||||
{
|
||||
@@ -332,6 +381,10 @@ void SaveGameGamebryo::readFile(const QString &fileName)
|
||||
setCreationTime(fileName);
|
||||
readSkyrimFile(saveFile);
|
||||
} break;
|
||||
case GameInfo::TYPE_FALLOUT4: {
|
||||
setCreationTime(fileName);
|
||||
readFO4File(saveFile);
|
||||
} break;
|
||||
}
|
||||
|
||||
saveFile.close();
|
||||
|
||||
@@ -85,6 +85,7 @@ private:
|
||||
|
||||
void readESSFile(QFile &saveFile);
|
||||
void readFOSFile(QFile &saveFile, bool newVegas);
|
||||
void readFO4File(QFile &saveFile);
|
||||
void readSkyrimFile(QFile &saveFile);
|
||||
|
||||
void setCreationTime(const QString &fileName);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user