#include "patchinstaller.h" #include "models/filesystem.h" #include "models/downloader.h" #include "models/settings.h" #include #include QString getComponentNameFromId(int id) { switch (id) { case 100: return "texts_main"; case 101: return "texts_items"; case 102: return "texts_emotes"; case 200: return "maps"; case 201: return "loadscreens"; case 202: return "textures"; case 300: return "sounds"; case 301: return "videos"; } return "none"; } PatchInstaller::PatchInstaller(QObject *parent) : QObject(parent) { } bool PatchInstaller::initialised() { return client_general_file_->Initialized() && client_local_file_->Initialized(); } PatchInstaller::~PatchInstaller() { deinit(); } // ############## PRIVATE ############## // bool PatchInstaller::datPathIsRelevant() { QString game_folder = Settings::getValue("Lotro/game_path").toString(); QString locale_prefix = Settings::getValue("Lotro/original_locale").toString(); QString client_local_filepath = game_folder + "/client_local_" + locale_prefix + ".dat"; QString client_general_filepath = game_folder + "/client_general.dat"; QString client_local_current_path = QString::fromStdString(client_local_file_->GetFilename()); QString client_general_current_path = QString::fromStdString(client_general_file_->GetFilename()); return QFileInfo(client_local_filepath) != QFileInfo(client_local_current_path) || QFileInfo(client_general_filepath) != QFileInfo(client_general_current_path); } void PatchInstaller::deinit() { emit operationStarted("deinitializeManager"); client_local_file_->Deinit(); client_general_file_->Deinit(); emit operationFinished("deinitializeManager"); } void PatchInstaller::installPatch(QString patch_name, LOTRO_DAT::Database& database) { if (patch_name == "loadscreen") { installLoadscreens(database); return; } if (patch_name == "video") { installVideos(database); return; } if (patch_name == "micro" && !Settings::getValue("Components/micropatch").toBool()) { Settings::setValue("DatabaseNeedInstall/micropatch", false); return; } size_t patched_files_num = 0; LOTRO_DAT::SubfileData file; int i = 0; const int total_files = database.CountRows(); qDebug() << "Patching all files from database..."; while (!(file = database.GetNextFile()).Empty()) { if (i * 100 / total_files != (i - 1) * 100 / total_files) { qDebug() << "Completed " << i * 100 / total_files << "%"; } ++i; if (!file.options["fid"]) { continue; } const int category = file.options["cat"] ? file.options["cat"].as() : -1; QString component_name = getComponentNameFromId(category); if (!Settings::getValue("Components/" + component_name).toBool()) { continue; } const int dat_id = file.options["fid"].as(); if (dat_id == E_CLIENT_LOCAL) { client_local_file_->PatchFile(file); } else if (dat_id == E_CLIENT_GENERAL) { client_general_file_->PatchFile(file); } else { qWarning() << "Unknown dat id parameter for file " << file.options["fid"].as() << " (dat id value = " << dat_id << "), SKIPPING!"; } ++patched_files_num; } Settings::setValue("DatabaseNeedInstall/" + patch_name, false); return; } // TODO void PatchInstaller::installLoadscreens(LOTRO_DAT::Database& database) { if (!Settings::getValue("DatabaseNeedInstall/loadscreen").toBool() || !Settings::getValue("Components/loadscreens").toBool()) { Settings::setValue("DatabaseNeedInstall/loadscreen", false); return; } QString locale_prefix = Settings::getValue("Lotro/original_locale").toString(); const QStringList loadscreens_filenames = { locale_prefix == "English" ? "lotro_ad_pregame.jpg" : "lotro_ad_pregame_" + locale_prefix + ".jpg", "lotro_generic_teleport_screen_01.jpg", "lotro_generic_teleport_screen_02.jpg", "lotro_generic_teleport_screen_03.jpg", "lotro_generic_teleport_screen_04.jpg", "lotro_generic_teleport_screen_05.jpg", "lotro_generic_teleport_screen_06.jpg", "lotro_generic_teleport_screen_07.jpg", "lotro_generic_teleport_screen_08.jpg", "lotro_generic_teleport_screen_09.jpg", "lotro_generic_teleport_screen_10.jpg" }; LOTRO_DAT::SubfileData data; QString logo_path = Settings::getValue("Lotro/game_path").toString() + "/raw/" + (locale_prefix == "English" ? "en" : locale_prefix) + "/logo/"; for (size_t i = 0; i < qMin(size_t(loadscreens_filenames.size()), database.CountRows()); ++i) { data = database.GetNextFile(); QFile::remove(logo_path + loadscreens_filenames[i]); if (!data.binary_data.WriteToFile((logo_path + loadscreens_filenames[i]).toLocal8Bit())) { qWarning() << "InstallLoadscreens: Cannot write to file " << logo_path + loadscreens_filenames[i]; } // progress.install_finished_parts++; // emit progressChanged(progress, this); } Settings::setValue("DatabaseNeedInstall/loadscreen", false); } // TODO void PatchInstaller::installVideos(LOTRO_DAT::Database& database) { } // ############## PUBLIC SLOTS ############## // void PatchInstaller::init() { emit operationStarted("initializeManager"); qDebug() << __FUNCTION__ << "Starting initialisation of LotroDatManager"; QString game_folder = Settings::getValue("Lotro/game_path").toString(); QString locale_prefix = Settings::getValue("Lotro/original_locale").toString(); QString client_local_filepath = game_folder + "/client_local_" + locale_prefix + ".dat"; QString client_general_filepath = game_folder + "/client_general.dat"; if (!FileSystem::fileExists(client_local_filepath) || !FileSystem::fileExists(client_general_filepath)) { emit errorOccured("initializeManager", {}, "DatFilesNotFound"); emit operationFinished("initializeManager", {}, false); return; } // Updating file permissions to be sure, that they're not in read-only mode if (!QFile::setPermissions(client_local_filepath, QFileDevice::Permission(0x6666))) { qDebug() << __FUNCTION__ << "Unable to update permissions on client_local_* file!"; } if (!QFile::setPermissions(client_general_filepath, QFileDevice::Permission(0x6666))) { qDebug() << __FUNCTION__ << "Unable to update permissions on client_general* file!"; } // Initialising client_local_*.dat file and client_general.dat client_local_file_ = new LOTRO_DAT::DatFile(1); client_general_file_ = new LOTRO_DAT::DatFile(2); auto client_local_init_res = client_local_file_->Init(client_local_filepath.toStdString()); auto client_general_init_res = client_general_file_->Init(client_general_filepath.toStdString()); if (!client_local_init_res || !client_general_init_res) { client_local_file_->Deinit(); client_general_file_->Deinit(); qDebug() << __FUNCTION__ << "Finished LotroDatManager initialisation - error: DatFile initialisation error!"; emit errorOccured("initializeManager", {}, "DatInitError"); emit operationFinished("initializeManager", {}, false); return; } qDebug() << "LotroDatManager initialisation successfull! Dat files: " << QString::fromStdString(client_general_file_->GetFilename()) << QString::fromStdString(client_local_file_->GetFilename()); emit operationFinished("initializeManager", {}, true); } void PatchInstaller::startGame(bool freeze_updates) { // if freeze_updates is set to True, original game // launcher will be replaced with special program, // which controls lotro startup and prevents from updates emit operationStarted("startGame"); QString game_folder = Settings::getValue("Lotro/game_path").toString(); if (game_folder == "none") { qDebug() << __FUNCTION__ << "Starting game FAILED - game folder wasnt set!"; emit errorOccured("startGame", {}, "GameFolderNotSet"); emit operationFinished("startGame", {}, false); return; } if (!FileSystem::fileExists(QApplication::applicationDirPath() + "/Launcher.exe")) { qDebug() << __FUNCTION__ << "Starting game FAILED - no game launcher in legacy directory found!"; emit errorOccured("startGame", {}, "NoGameLauncherInLegacyDir"); emit operationFinished("startGame", {}, false); return; } if (freeze_updates) { QFile::remove(game_folder + "/lotro_ru.exe"); if (!QFile::copy(QApplication::applicationDirPath() + "/LotroLauncher.exe", game_folder + "/lotro_ru.exe")) { qDebug() << __FUNCTION__ << "Starting game FAILED - cannot copy LotroLauncher to lotro_ru.exe!!"; emit errorOccured("startGame", {}, "LauncherCopyFailed"); emit operationFinished("startGame", {}, false); return; } QFile::remove(game_folder + "/LotroLauncher.exe"); if (!QFile::copy(QApplication::applicationDirPath() + "/Launcher.exe", game_folder + "/LotroLauncher.exe")) { qDebug() << __FUNCTION__ << "Starting game FAILED - cannot copy GameLauncher to LotroLauncher!!"; emit errorOccured("startGame", {}, "NoAccessToGameLauncher"); emit operationFinished("startGame", {}, false); return; } QFile file(game_folder + "/legacy_path.txt"); file.open(QIODevice::WriteOnly); QTextStream out(&file); out << QApplication::applicationDirPath() + "/LegacyLauncher.exe"; file.close(); } else { QFile::remove(game_folder + "/LotroLauncher.exe"); if (!QFile::copy(QApplication::applicationDirPath() + "/LotroLauncher.exe", game_folder + "/LotroLauncher.exe")) { qDebug() << __FUNCTION__ << "Starting game FAILED - cannot copy LotroLauncher from working dir to LotroLauncher in lotro dir!!"; emit errorOccured("startGame", {}, "NoAccessToGameLauncher"); emit operationFinished("startGame", {}, false); return; } } QStringList args; if (freeze_updates) { args << "gamelaunch" << "-disablePatch"; } if (Settings::getValue("Lotro/skip_raw_download").toBool()) { args << "-skiprawdownload"; } if (Settings::getValue("Lotro/no_splash_screen").toBool()) { args << "-nosplashscreen"; } client_general_file_->Deinit(); client_local_file_->Deinit(); QString username = Settings::getValue("Account/username").toString(); QString password = Settings::getValue("Account/password").toString(); if (!username.isEmpty() && !password.isEmpty()) { args << "-username" << username << "-password" << password; } qDebug() << __FUNCTION__ << "Starting game with arguments: " << args; QFile f(Settings::getValue("Lotro/game_path").toString() + "/LotroLauncher.exe"); QProcess process; if (FileSystem::fileExists(f.fileName())) { if (f.fileName().contains(" ")) { f.setFileName("\"" + f.fileName() + "\""); } process.startDetached(f.fileName(), args); process.waitForFinished(-1); QApplication::quit(); } emit operationFinished("startGame"); } // TODO void PatchInstaller::startPatchInstallationChain() { }