Skip to content

Commit

Permalink
Merge pull request #808 from isanae/settings-rework
Browse files Browse the repository at this point in the history
Settings rework
  • Loading branch information
isanae committed Aug 3, 2019
2 parents 80dd922 + 712c868 commit a7df11a
Show file tree
Hide file tree
Showing 24 changed files with 1,515 additions and 1,945 deletions.
21 changes: 21 additions & 0 deletions src/CMakeLists.txt
Expand Up @@ -37,6 +37,13 @@ SET(organizer_SRCS
spawn.cpp
singleinstance.cpp
settingsdialog.cpp
settingsdialogdiagnostics.cpp
settingsdialoggeneral.cpp
settingsdialognexus.cpp
settingsdialogpaths.cpp
settingsdialogplugins.cpp
settingsdialogsteam.cpp
settingsdialogworkarounds.cpp
settings.cpp
selfupdater.cpp
selectiondialog.cpp
Expand Down Expand Up @@ -151,6 +158,13 @@ SET(organizer_HDRS
spawn.h
singleinstance.h
settingsdialog.h
settingsdialogdiagnostics.h
settingsdialoggeneral.h
settingsdialognexus.h
settingsdialogpaths.h
settingsdialogplugins.h
settingsdialogsteam.h
settingsdialogworkarounds.h
settings.h
selfupdater.h
selectiondialog.h
Expand Down Expand Up @@ -431,6 +445,13 @@ set(profiles
set(settings
settings
settingsdialog
settingsdialogdiagnostics
settingsdialoggeneral
settingsdialognexus
settingsdialogpaths
settingsdialogplugins
settingsdialogsteam
settingsdialogworkarounds
)

set(utilities
Expand Down
274 changes: 4 additions & 270 deletions src/loadmechanism.cpp
Expand Up @@ -32,286 +32,20 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QCryptographicHash>
#include <QCoreApplication>


using namespace MOBase;
using namespace MOShared;


LoadMechanism::LoadMechanism()
: m_SelectedMechanism(LOAD_MODORGANIZER)
{
}

void LoadMechanism::writeHintFile(const QDir &targetDirectory)
{
QString hintFilePath = targetDirectory.absoluteFilePath("mo_path.txt");
QFile hintFile(hintFilePath);
if (hintFile.exists()) {
hintFile.remove();
}
if (!hintFile.open(QIODevice::WriteOnly)) {
throw MyException(QObject::tr("failed to open %1: %2").arg(hintFilePath).arg(hintFile.errorString()));
}
hintFile.write(qApp->applicationDirPath().toUtf8().constData());
hintFile.close();
}


void LoadMechanism::removeHintFile(QDir targetDirectory)
{
targetDirectory.remove("mo_path.txt");
}


bool LoadMechanism::isDirectLoadingSupported()
{
//FIXME: Seriously? isn't there a 'do i need steam' thing?
IPluginGame const *game = qApp->property("managed_game").value<IPluginGame*>();
if (game->gameName().compare("oblivion", Qt::CaseInsensitive) == 0) {
// oblivion can be loaded directly if it's not the steam variant
return !game->gameDirectory().exists("steam_api.dll");
} else {
// all other games work afaik
return true;
}
}

bool LoadMechanism::isScriptExtenderSupported()
{
IPluginGame const *game = qApp->property("managed_game").value<IPluginGame*>();
ScriptExtender *extender = game->feature<ScriptExtender>();

// test if there even is an extender for the managed game and if so whether it's installed
return extender != nullptr && extender->isInstalled();
}

bool LoadMechanism::isProxyDLLSupported()
{
// using steam_api.dll as the proxy is way too game specific as many games will have different
// versions of that dll.
// plus: the proxy dll hasn't been working for at least the whole 1.12.x versions of MO and
// noone reported it so why maintain an unused feature?
return false;
/* IPluginGame const *game = qApp->property("managed_game").value<IPluginGame*>();
return game->gameDirectory().exists(QString::fromStdWString(AppConfig::proxyDLLTarget()));*/
}


bool LoadMechanism::hashIdentical(const QString &fileNameLHS, const QString &fileNameRHS)
bool LoadMechanism::isDirectLoadingSupported() const
{
QFile fileLHS(fileNameLHS);
if (!fileLHS.open(QIODevice::ReadOnly)) {
throw MyException(QObject::tr("file not found: %1").arg(qUtf8Printable(fileNameLHS)));
}
QByteArray dataLHS = fileLHS.readAll();
QByteArray hashLHS = QCryptographicHash::hash(dataLHS, QCryptographicHash::Md5);

fileLHS.close();

QFile fileRHS(fileNameRHS);
if (!fileRHS.open(QIODevice::ReadOnly)) {
throw MyException(QObject::tr("file not found: %1").arg(qUtf8Printable(fileNameRHS)));
}
QByteArray dataRHS = fileRHS.readAll();
QByteArray hashRHS = QCryptographicHash::hash(dataRHS, QCryptographicHash::Md5);

fileRHS.close();

return hashLHS == hashRHS;
return true;
}


void LoadMechanism::deactivateScriptExtender()
void LoadMechanism::activate(EMechanism)
{
try {
IPluginGame const *game = qApp->property("managed_game").value<IPluginGame*>();
ScriptExtender *extender = game->feature<ScriptExtender>();
if (extender == nullptr) {
return;
}

QDir pluginsDir(game->gameDirectory().absolutePath() + "/data/" + extender->PluginPath());

#pragma message("implement this for usvfs")

QString vfsDLLName = "";
if (extender->getArch() == IMAGE_FILE_MACHINE_I386) {
vfsDLLName = ToQString(AppConfig::vfs32DLLName());
}
else if (extender->getArch() == IMAGE_FILE_MACHINE_AMD64)
{
vfsDLLName = ToQString(AppConfig::vfs64DLLName());
}
log::debug("USVFS DLL Name: {}", vfsDLLName);
if (vfsDLLName != "") {
if (QFile(pluginsDir.absoluteFilePath(vfsDLLName)).exists()) {
// remove dll from SE plugins directory
if (!pluginsDir.remove(vfsDLLName)) {
throw MyException(QObject::tr("Failed to delete %1").arg(pluginsDir.absoluteFilePath(vfsDLLName)));
}
}
}

removeHintFile(pluginsDir);
} catch (const std::exception &e) {
QMessageBox::critical(nullptr, QObject::tr("Failed to deactivate script extender loading"), e.what());
}
// no-op
}


void LoadMechanism::deactivateProxyDLL()
{
try {
IPluginGame const *game = qApp->property("managed_game").value<IPluginGame *>();

QString targetPath = game->gameDirectory().absoluteFilePath(QString::fromStdWString(AppConfig::proxyDLLTarget()));

QFile targetDLL(targetPath);
if (targetDLL.exists()) {
QString origFile = game->gameDirectory().absoluteFilePath(QString::fromStdWString(AppConfig::proxyDLLOrig()));
// determine if a proxy-dll is installed
// this is a very crude way of making this decision but it should be good enough
if ((targetDLL.size() < 24576) && (QFile(origFile).exists())) {
// remove proxy-dll
if (!targetDLL.remove()) {
throw MyException(QObject::tr("Failed to remove %1: %2").arg(targetPath).arg(targetDLL.errorString()));
} else if (!QFile::rename(origFile, targetPath)) {
throw MyException(QObject::tr("Failed to rename %1 to %2").arg(origFile, targetPath));
}
}
}

removeHintFile(game->gameDirectory());
} catch (const std::exception &e) {
QMessageBox::critical(nullptr, QObject::tr("Failed to deactivate proxy-dll loading"), e.what());
}
}


void LoadMechanism::activateScriptExtender()
{
try {
IPluginGame const *game = qApp->property("managed_game").value<IPluginGame *>();
ScriptExtender *extender = game->feature<ScriptExtender>();
if (extender == nullptr) {
return;
}

QDir pluginsDir(game->gameDirectory().absolutePath() + "/data/" + extender->PluginPath());

if (!pluginsDir.exists()) {
pluginsDir.mkpath(".");
}

#pragma message("implement this for usvfs")
std::wstring vfsDLL = L"";
if (extender->getArch() == IMAGE_FILE_MACHINE_I386) {
vfsDLL = AppConfig::vfs32DLLName();
}
else if (extender->getArch() == IMAGE_FILE_MACHINE_AMD64)
{
vfsDLL = AppConfig::vfs64DLLName();
}
if (vfsDLL != L"") {
QString targetPath = pluginsDir.absoluteFilePath(ToQString(vfsDLL));
QString vfsDLLPath = qApp->applicationDirPath() + "/" + QString::fromStdWString(vfsDLL);

log::debug("DLL USVFS Target Path: {}", targetPath);
log::debug("DLL USVFS VFS DLL Path: {}", vfsDLLPath);

QFile dllFile(targetPath);

if (dllFile.exists()) {
// may be outdated
if (!hashIdentical(targetPath, vfsDLLPath)) {
dllFile.remove();
}
}

if (!dllFile.exists()) {
// install dll to SE plugins
if (!QFile::copy(vfsDLLPath, targetPath)) {
throw MyException(QObject::tr("Failed to copy %1 to %2").arg(vfsDLLPath, targetPath));
}
}
}
writeHintFile(pluginsDir);
} catch (const std::exception &e) {
QMessageBox::critical(nullptr, QObject::tr("Failed to set up script extender loading"), e.what());
}
}


void LoadMechanism::activateProxyDLL()
{
try {
IPluginGame const *game = qApp->property("managed_game").value<IPluginGame *>();

QString targetPath = game->gameDirectory().absoluteFilePath(QString::fromStdWString(AppConfig::proxyDLLTarget()));

QFile targetDLL(targetPath);
if (!targetDLL.exists()) {
return;
}

QString sourcePath = qApp->applicationDirPath() + "/" + ToQString(AppConfig::proxyDLLSource());

// this is a very crude way of making this decision but it should be good enough
if (targetDLL.size() < 24576) {
// determine if a proxy-dll is already installed and if so, if it's the right one
if (!hashIdentical(targetPath, sourcePath)) {
// wrong proxy dll, probably outdated. delete and install the new one
if (!QFile::remove(targetPath)) {
throw MyException(QObject::tr("Failed to delete old proxy-dll %1").arg(targetPath));
}
if (!QFile::copy(sourcePath, targetPath)) {
throw MyException(QObject::tr("Failed to copy %1 to %2").arg(sourcePath).arg(targetPath));
}
} // otherwise the proxy-dll is already the right one
} else {
// no proxy dll installed yet. move the original and insert proxy-dll

QString origFile = game->gameDirectory().absoluteFilePath(QString::fromStdWString(AppConfig::proxyDLLOrig()));

if (QFile(origFile).exists()) {
// orig-file exists. this may happen if the steam-api was updated or the user messed with the
// dlls.
if (!QFile::remove(origFile)) {
throw MyException(QObject::tr("Failed to overwrite %1").arg(origFile));
}
}
if (!QFile::rename(targetPath, origFile)) {
throw MyException(QObject::tr("Failed to rename %1 to %2").arg(targetPath).arg(origFile));
}
if (!QFile::copy(sourcePath, targetPath)) {
throw MyException(QObject::tr("Failed to copy %1 to %2").arg(sourcePath).arg(targetPath));
}
}
writeHintFile(game->gameDirectory());
} catch (const std::exception &e) {
QMessageBox::critical(nullptr, QObject::tr("Failed to set up proxy-dll loading"), e.what());
}
}


void LoadMechanism::activate(EMechanism mechanism)
{
switch (mechanism) {
case LOAD_MODORGANIZER: {
log::debug("Load Mechanism: Mod Organizer");
deactivateProxyDLL();
deactivateScriptExtender();
} break;
case LOAD_SCRIPTEXTENDER: {
log::debug("Load Mechanism: ScriptExtender");
deactivateProxyDLL();
activateScriptExtender();
} break;
case LOAD_PROXYDLL: {
log::debug("Load Mechanism: Proxy DLL");
deactivateScriptExtender();
activateProxyDLL();
} break;
}
}

0 comments on commit a7df11a

Please sign in to comment.