summaryrefslogtreecommitdiff
path: root/src/organizercore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/organizercore.cpp')
-rw-r--r--src/organizercore.cpp189
1 files changed, 114 insertions, 75 deletions
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index 06a6dba4..6a8e148f 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -14,6 +14,7 @@
#include "nxmaccessmanager.h"
#include <ipluginmodpage.h>
#include <dataarchives.h>
+#include <localsavegames.h>
#include <directoryentry.h>
#include <scopeguard.h>
#include <utility.h>
@@ -235,7 +236,6 @@ QSettings::Status OrganizerCore::storeSettings(const QString &fileName)
settings.setValue("binary", item.m_BinaryInfo.absoluteFilePath());
settings.setValue("arguments", item.m_Arguments);
settings.setValue("workingDirectory", item.m_WorkingDirectory);
- settings.setValue("closeOnStart", item.m_CloseMO == ExecutableInfo::CloseMOStyle::DEFAULT_CLOSE);
settings.setValue("steamAppID", item.m_SteamAppID);
}
}
@@ -285,7 +285,9 @@ bool OrganizerCore::testForSteam()
bool success = false;
while (!success) {
processIDs.reset(new DWORD[currentSize]);
- if (!::EnumProcesses(processIDs.get(), currentSize * sizeof(DWORD), &bytesReturned)) {
+ if (!::EnumProcesses(processIDs.get(),
+ static_cast<DWORD>(currentSize) * sizeof(DWORD),
+ &bytesReturned)) {
qWarning("failed to determine if steam is running");
return true;
}
@@ -335,9 +337,6 @@ void OrganizerCore::updateExecutablesList(QSettings &settings)
int numCustomExecutables = settings.beginReadArray("customExecutables");
for (int i = 0; i < numCustomExecutables; ++i) {
settings.setArrayIndex(i);
- ExecutableInfo::CloseMOStyle closeMO =
- settings.value("closeOnStart").toBool() ? ExecutableInfo::CloseMOStyle::DEFAULT_CLOSE
- : ExecutableInfo::CloseMOStyle::DEFAULT_STAY;
Executable::Flags flags;
if (settings.value("custom", true).toBool()) flags |= Executable::CustomExecutable;
@@ -348,7 +347,6 @@ void OrganizerCore::updateExecutablesList(QSettings &settings)
settings.value("binary").toString(),
settings.value("arguments").toString(),
settings.value("workingDirectory", "").toString(),
- closeMO,
settings.value("steamAppID", "").toString(),
flags);
}
@@ -543,6 +541,11 @@ void OrganizerCore::createDefaultProfile()
}
}
+void OrganizerCore::prepareVFS()
+{
+ m_USVFS.updateMapping(fileMapping());
+}
+
void OrganizerCore::setCurrentProfile(const QString &profileName)
{
if ((m_CurrentProfile != nullptr) &&
@@ -867,7 +870,7 @@ ModList *OrganizerCore::modList()
return &m_ModList;
}
-void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &arguments, const QDir &currentDirectory, bool closeAfterStart, const QString &steamAppID)
+void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &arguments, const QDir &currentDirectory, const QString &steamAppID)
{
LockedDialog *dialog = new LockedDialog(qApp->activeWindow());
dialog->show();
@@ -875,55 +878,52 @@ void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &argument
HANDLE processHandle = spawnBinaryDirect(binary, arguments, m_CurrentProfile->name(), currentDirectory, steamAppID);
if (processHandle != INVALID_HANDLE_VALUE) {
- if (closeAfterStart && (m_UserInterface != nullptr)) {
- m_UserInterface->closeWindow();
- } else {
- if (m_UserInterface != nullptr) {
- m_UserInterface->setWindowEnabled(false);
- }
- // re-enable the locked dialog because what'd be the point otherwise?
- dialog->setEnabled(true);
+ if (m_UserInterface != nullptr) {
+ m_UserInterface->setWindowEnabled(false);
+ }
+ // re-enable the locked dialog because what'd be the point otherwise?
+ dialog->setEnabled(true);
- QCoreApplication::processEvents();
+ QCoreApplication::processEvents();
- DWORD processExitCode;
- DWORD retLen;
- JOBOBJECT_BASIC_PROCESS_ID_LIST info;
+ DWORD processExitCode;
+ DWORD retLen;
+ JOBOBJECT_BASIC_PROCESS_ID_LIST info;
- {
- DWORD currentProcess = 0UL;
- bool isJobHandle = true;
+ {
+ DWORD currentProcess = 0UL;
+ bool isJobHandle = true;
- DWORD res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE);
- while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0) && !dialog->unlockClicked()) {
- if (isJobHandle) {
- if (::QueryInformationJobObject(processHandle, JobObjectBasicProcessIdList, &info, sizeof(info), &retLen) > 0) {
- if (info.NumberOfProcessIdsInList == 0) {
- break;
- } else {
- if (info.ProcessIdList[0] != currentProcess) {
- currentProcess = info.ProcessIdList[0];
- dialog->setProcessName(ToQString(getProcessName(currentProcess)));
- }
- }
+ DWORD res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE);
+ while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0) && !dialog->unlockClicked()) {
+ if (isJobHandle) {
+ if (::QueryInformationJobObject(processHandle, JobObjectBasicProcessIdList, &info, sizeof(info), &retLen) > 0) {
+ if (info.NumberOfProcessIdsInList == 0) {
+ break;
} else {
- // the info-object I passed only provides space for 1 process id. but since this code only cares about whether there
- // is more than one that's good enough. ERROR_MORE_DATA simply signals there are at least two processes running.
- // any other error probably means the handle is a regular process handle, probably caused by running MO in a job without
- // the right to break out.
- if (::GetLastError() != ERROR_MORE_DATA) {
- isJobHandle = false;
+ if (info.ProcessIdList[0] != currentProcess) {
+ currentProcess = info.ProcessIdList[0];
+ dialog->setProcessName(ToQString(getProcessName(currentProcess)));
}
}
+ } else {
+ // the info-object I passed only provides space for 1 process id. but since this code only cares about whether there
+ // is more than one that's good enough. ERROR_MORE_DATA simply signals there are at least two processes running.
+ // any other error probably means the handle is a regular process handle, probably caused by running MO in a job without
+ // the right to break out.
+ if (::GetLastError() != ERROR_MORE_DATA) {
+ isJobHandle = false;
+ }
}
+ }
- // keep processing events so the app doesn't appear dead
- QCoreApplication::processEvents();
+ // keep processing events so the app doesn't appear dead
+ QCoreApplication::processEvents();
- res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE);
- }
- ::GetExitCodeProcess(processHandle, &processExitCode);
+ res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE);
}
+ ::GetExitCodeProcess(processHandle, &processExitCode);
+
::CloseHandle(processHandle);
if (m_UserInterface != nullptr) {
@@ -966,7 +966,8 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, const QString &
//This could possibly be extracted somewhere else but it's probably for when
//we have more than one provider of game registration.
- if (QFileInfo(managedGame()->gameDirectory().absoluteFilePath("steam_api.dll")).exists()
+ if ((QFileInfo(managedGame()->gameDirectory().absoluteFilePath("steam_api.dll")).exists()
+ || QFileInfo(managedGame()->gameDirectory().absoluteFilePath("steam_api64.dll")).exists())
&& (m_Settings.getLoadMechanism() == LoadMechanism::LOAD_MODORGANIZER)) {
if (!testForSteam()) {
QWidget *window = qApp->activeWindow();
@@ -995,7 +996,8 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, const QString &
// TODO: should also pass arguments
if (m_AboutToRun(binary.absoluteFilePath())) {
- return startBinary(binary, arguments, profileName, m_Settings.logLevel(), currentDirectory, true);
+ m_USVFS.updateMapping(fileMapping());
+ return startBinary(binary, arguments, currentDirectory, true);
} else {
qDebug("start of \"%s\" canceled by plugin", qPrintable(binary.absoluteFilePath()));
return INVALID_HANDLE_VALUE;
@@ -1190,10 +1192,6 @@ void OrganizerCore::refreshBSAList()
m_ActiveArchives = m_DefaultArchives;
}
- if (m_UserInterface != nullptr) {
- m_UserInterface->updateBSAList(m_DefaultArchives, m_ActiveArchives);
- }
-
m_ArchivesInit = true;
}
}
@@ -1252,9 +1250,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()));
@@ -1399,9 +1395,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();
@@ -1540,9 +1533,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()));
}
@@ -1576,21 +1566,53 @@ void OrganizerCore::prepareStart() {
storeSettings();
}
-/*
-std::vector<std::pair<QString, QString>> OrganizerCore::fileMapping()
+std::vector<Mapping> OrganizerCore::fileMapping()
{
- return fileMapping(managedGame()->dataDirectory().absolutePath(),
- directoryStructure(),
- directoryStructure());
-}
+ // need to wait until directory structure
+ while (m_DirectoryUpdate) {
+ ::Sleep(100);
+ QCoreApplication::processEvents();
+ }
+
+ int overwriteId = m_DirectoryStructure->getOriginByName(L"Overwrite").getID();
+
+ IPluginGame *game = qApp->property("managed_game").value<IPluginGame *>();
+ MappingType result = fileMapping(
+ QDir::toNativeSeparators(game->dataDirectory().absolutePath()),
+ "\\",
+ directoryStructure(), directoryStructure(),
+ overwriteId);
+
+ if (m_CurrentProfile->localSavesEnabled()) {
+ LocalSavegames *localSaves = game->feature<LocalSavegames>();
+
+ if (localSaves != nullptr) {
+ MappingType saveMap = localSaves->mappings(currentProfile()->absolutePath() + "/saves");
+ result.reserve(result.size() + saveMap.size());
+ result.insert(result.end(), saveMap.begin(), saveMap.end());
+ }
+ }
+ for (MOBase::IPluginFileMapper *mapper : m_PluginContainer->plugins<MOBase::IPluginFileMapper>()) {
+ IPlugin *plugin = dynamic_cast<IPlugin*>(mapper);
+ if (plugin->isActive()) {
+ MappingType pluginMap = mapper->mappings();
+ result.reserve(result.size() + pluginMap.size());
+ result.insert(result.end(), pluginMap.begin(), pluginMap.end());
+ }
+ }
-std::vector<std::pair<QString, QString>> OrganizerCore::fileMapping(
+ return result;
+}
+
+std::vector<Mapping> OrganizerCore::fileMapping(
const QString &dataPath,
+ const QString &relPath,
const DirectoryEntry *base,
- const DirectoryEntry *directoryEntry)
+ const DirectoryEntry *directoryEntry,
+ int createDestination)
{
- std::vector<std::pair<QString, QString>> result;
+ std::vector<Mapping> result;
for (FileEntry::Ptr current : directoryEntry->getFiles()) {
bool isArchive = false;
@@ -1599,20 +1621,37 @@ 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, 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();
+
+ QString originPath
+ = QString::fromStdWString(base->getOriginByID(origin).getPath());
+ QString dirName = QString::fromStdWString((*current)->getName());
+ QString source = originPath + relPath + dirName;
+ QString target = dataPath + relPath + dirName;
+
+ bool writeDestination = (base == directoryEntry)
+ && (origin == createDestination);
+
+ result.push_back({source, target, true, writeDestination});
+ std::vector<Mapping> subRes
+ = fileMapping(dataPath, relPath + dirName + "\\", base, *current,
+ createDestination);
result.insert(result.end(), subRes.begin(), subRes.end());
}
return result;
}
-*/