From 9bd6e9c977b00708248976c508ff74ed58c67e67 Mon Sep 17 00:00:00 2001 From: redstrate Date: Tue, 23 Nov 2021 15:34:23 -0500 Subject: [PATCH] Separate main launcher core and launcher window, add basic command line support --- CMakeLists.txt | 8 +- src/assetupdater.cpp | 8 +- src/assetupdater.h | 9 +- src/{xivlauncher.cpp => launchercore.cpp} | 261 ++++------------------ src/{xivlauncher.h => launchercore.h} | 41 +--- src/launcherwindow.cpp | 192 ++++++++++++++++ src/launcherwindow.h | 31 +++ src/main.cpp | 15 +- src/sapphirelauncher.cpp | 6 +- src/sapphirelauncher.h | 6 +- src/settingswindow.cpp | 69 +++--- src/settingswindow.h | 4 +- src/squareboot.cpp | 4 +- src/squareboot.h | 6 +- src/squarelauncher.cpp | 20 +- src/squarelauncher.h | 12 +- 16 files changed, 364 insertions(+), 328 deletions(-) rename src/{xivlauncher.cpp => launchercore.cpp} (59%) rename src/{xivlauncher.h => launchercore.h} (74%) create mode 100644 src/launcherwindow.cpp create mode 100644 src/launcherwindow.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 236ee48..b497bf5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,12 +12,16 @@ add_subdirectory(external) add_executable(xivlauncher src/main.cpp - src/xivlauncher.cpp + src/launchercore.cpp src/sapphirelauncher.cpp src/squareboot.cpp src/squarelauncher.cpp src/settingswindow.cpp - src/blowfish.cpp src/assetupdater.cpp src/assetupdater.h) + src/blowfish.cpp + src/assetupdater.cpp + src/assetupdater.h + src/launcherwindow.cpp + src/launcherwindow.h) target_link_libraries(xivlauncher Qt5::Core Qt5::Widgets Qt5::Network qt5keychain QuaZip) diff --git a/src/assetupdater.cpp b/src/assetupdater.cpp index 1f46e8f..20b2dec 100644 --- a/src/assetupdater.cpp +++ b/src/assetupdater.cpp @@ -6,7 +6,7 @@ #include -#include "xivlauncher.h" +#include "launchercore.h" const QString dalamudRemotePath = "https://goatcorp.github.io/dalamud-distrib/"; const QString dalamudVersion = "latest"; @@ -14,19 +14,19 @@ const QString dalamudVersion = "latest"; const QString nativeLauncherRemotePath = "https://github.com/redstrate/nativelauncher/releases/download/"; const QString nativeLauncherVersion = "v1.0.0"; -AssetUpdater::AssetUpdater(LauncherWindow &launcher) : launcher(launcher) { +AssetUpdater::AssetUpdater(LauncherCore &launcher) : launcher(launcher) { connect(launcher.mgr, &QNetworkAccessManager::finished, this, &AssetUpdater::finishDownload); launcher.mgr->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy); } -void AssetUpdater::update() { +void AssetUpdater::update(const ProfileSettings& profile) { QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); const bool hasDalamud = QFile::exists(dataDir + "/NativeLauncher.exe") && QFile::exists(dataDir + "/Dalamud"); // first we determine if we need dalamud - const bool needsDalamud = launcher.currentProfile().enableDalamud && !hasDalamud; + const bool needsDalamud = profile.enableDalamud && !hasDalamud; if(needsDalamud) { // download nativelauncher release (needed to launch the game with fixed ACLs) { diff --git a/src/assetupdater.h b/src/assetupdater.h index d762726..443dabc 100644 --- a/src/assetupdater.h +++ b/src/assetupdater.h @@ -3,15 +3,16 @@ #include #include -class LauncherWindow; +class LauncherCore; class QNetworkReply; +struct ProfileSettings; class AssetUpdater : public QObject { Q_OBJECT public: - AssetUpdater(LauncherWindow& launcher); + AssetUpdater(LauncherCore& launcher); - void update(); + void update(const ProfileSettings& profile); void finishDownload(QNetworkReply* reply); void beginInstall(); @@ -19,7 +20,7 @@ signals: void finishedUpdating(); private: - LauncherWindow& launcher; + LauncherCore& launcher; QTemporaryDir tempDir; }; \ No newline at end of file diff --git a/src/xivlauncher.cpp b/src/launchercore.cpp similarity index 59% rename from src/xivlauncher.cpp rename to src/launchercore.cpp index d5edf4c..f65405d 100755 --- a/src/xivlauncher.cpp +++ b/src/launchercore.cpp @@ -27,7 +27,7 @@ #include #endif -#include "xivlauncher.h" +#include "launchercore.h" #include "sapphirelauncher.h" #include "squarelauncher.h" #include "squareboot.h" @@ -35,7 +35,7 @@ #include "blowfish.h" #include "assetupdater.h" -void LauncherWindow::setSSL(QNetworkRequest& request) { +void LauncherCore::setSSL(QNetworkRequest& request) { QSslConfiguration config; config.setProtocol(QSsl::AnyProtocol); config.setPeerVerifyMode(QSslSocket::VerifyNone); @@ -43,7 +43,7 @@ void LauncherWindow::setSSL(QNetworkRequest& request) { request.setSslConfiguration(config); } -void LauncherWindow::buildRequest(QNetworkRequest& request) { +void LauncherCore::buildRequest(QNetworkRequest& request) { setSSL(request); request.setHeader(QNetworkRequest::UserAgentHeader, QString("SQEXAuthor/2.0.0(Windows 6.2; ja-jp; %1)").arg(QString(QSysInfo::bootUniqueId()))); @@ -106,20 +106,20 @@ QString encryptGameArg(QString arg) { return QString("//**sqex0003%1%2**//").arg(base64, QString(checksum)); } -void LauncherWindow::launchGame(const LoginAuth auth) { +void LauncherCore::launchGame(const ProfileSettings& profile, const LoginAuth auth) { QList arguments; QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); - if(currentProfile().enableDalamud) { + if(profile.enableDalamud) { arguments.push_back(dataDir + "/NativeLauncher.exe"); } // now for the actual game... - if(currentProfile().useDX9) { - arguments.push_back(currentProfile().gamePath + "\\game\\ffxiv.exe"); + if(profile.useDX9) { + arguments.push_back(profile.gamePath + "\\game\\ffxiv.exe"); } else { - arguments.push_back(currentProfile().gamePath + "\\game\\ffxiv_dx11.exe"); + arguments.push_back(profile.gamePath + "\\game\\ffxiv_dx11.exe"); } struct Argument { @@ -133,8 +133,8 @@ void LauncherWindow::launchGame(const LoginAuth auth) { gameArgs.push_back({"DEV.MaxEntitledExpansionID", QString::number(auth.maxExpansion)}); gameArgs.push_back({"DEV.TestSID", auth.SID}); gameArgs.push_back({"SYS.Region", QString::number(auth.region)}); - gameArgs.push_back({"language", QString::number(currentProfile().language)}); - gameArgs.push_back({"ver", currentProfile().gameVersion}); + gameArgs.push_back({"language", QString::number(profile.language)}); + gameArgs.push_back({"ver", profile.gameVersion}); if(!auth.lobbyhost.isEmpty()) { gameArgs.push_back({"DEV.GMServerHost", auth.frontierHost}); @@ -146,8 +146,8 @@ void LauncherWindow::launchGame(const LoginAuth auth) { auto gameProcess = new QProcess(this); - if(currentProfile().enableDalamud) { - connect(gameProcess, &QProcess::readyReadStandardOutput, [this, gameProcess] { + if(profile.enableDalamud) { + connect(gameProcess, &QProcess::readyReadStandardOutput, [this, gameProcess, profile] { QString output = gameProcess->readAllStandardOutput(); auto dalamudProcess = new QProcess(); @@ -162,11 +162,11 @@ void LauncherWindow::launchGame(const LoginAuth auth) { QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); - dalamudProcess->start(currentProfile().winePath, {dataDir + "/Dalamud/" + "Dalamud.Injector.exe", output}); + dalamudProcess->start(profile.winePath, {dataDir + "/Dalamud/" + "Dalamud.Injector.exe", output}); }); } - if(currentProfile().encryptArguments) { + if(profile.encryptArguments) { QString argJoined; for(auto arg : gameArgs) { argJoined += QString(" /%1 =%2").arg(arg.key, arg.value); @@ -174,47 +174,46 @@ void LauncherWindow::launchGame(const LoginAuth auth) { auto earg = encryptGameArg(argJoined); arguments.append(earg); - launchExecutable(gameProcess, arguments); + launchExecutable(profile, gameProcess, arguments); } else { for(auto arg : gameArgs) { arguments.push_back(QString(" %1=%2").arg(arg.key, arg.value)); } - launchExecutable(gameProcess, arguments); + launchExecutable(profile, gameProcess, arguments); } } -void LauncherWindow::launchExecutable(const QStringList args) { +void LauncherCore::launchExecutable(const ProfileSettings& profile, const QStringList args) { auto process = new QProcess(this); - launchExecutable(process, args); + launchExecutable(profile, process, args); } -void LauncherWindow::launchExecutable(QProcess* process, const QStringList args) { +void LauncherCore::launchExecutable(const ProfileSettings& profile, QProcess* process, const QStringList args) { QList arguments; QStringList env = QProcess::systemEnvironment(); #if defined(Q_OS_LINUX) - if(currentProfile().useGamescope) { + if(profile.useGamescope) { arguments.push_back("gamescope"); arguments.push_back("-f"); arguments.push_back("-b"); } - if(currentProfile().useGamemode) + if(profile.useGamemode) arguments.push_back("gamemoderun"); - if(currentProfile().useEsync) { + if(profile.useEsync) env << "WINEESYNC=1"; - } #endif #if defined(Q_OS_MAC) || defined(Q_OS_LINUX) - env << "WINEPREFIX=" + currentProfile().winePrefixPath; + env << "WINEPREFIX=" + profile.winePrefixPath; - if(currentProfile().enableDXVKhud) + if(profile.enableDXVKhud) env << "DXVK_HUD=full"; - arguments.push_back(currentProfile().winePath); + arguments.push_back(profile.winePath); #endif arguments.append(args); @@ -222,20 +221,20 @@ void LauncherWindow::launchExecutable(QProcess* process, const QStringList args) auto executable = arguments[0]; arguments.removeFirst(); - process->setWorkingDirectory(currentProfile().gamePath + "/game/"); + process->setWorkingDirectory(profile.gamePath + "/game/"); process->setEnvironment(env); process->start(executable, arguments); } -QString LauncherWindow::readVersion(QString path) { +QString LauncherCore::readVersion(QString path) { QFile file(path); file.open(QFile::OpenModeFlag::ReadOnly); return file.readAll(); } -void LauncherWindow::readInitialInformation() { +void LauncherCore::readInitialInformation() { defaultProfileIndex = settings.value("defaultProfile", 0).toInt(); auto profiles = settings.childGroups(); @@ -312,7 +311,7 @@ void LauncherWindow::readInitialInformation() { readGameVersion(); } -void LauncherWindow::readWineInfo(ProfileSettings& profile) { +void LauncherCore::readWineInfo(ProfileSettings& profile) { #if defined(Q_OS_MAC) switch(profile.wineVersion) { case 0: // system wine @@ -339,15 +338,14 @@ void LauncherWindow::readWineInfo(ProfileSettings& profile) { #endif } -void LauncherWindow::readGameVersion() { +void LauncherCore::readGameVersion() { for(auto& profile : profileSettings) { profile.bootVersion = readVersion(profile.gamePath + "/boot/ffxivboot.ver"); profile.gameVersion = readVersion(profile.gamePath + "/game/ffxivgame.ver"); } } -LauncherWindow::LauncherWindow(QWidget* parent) : - QMainWindow(parent), settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::applicationName()) { +LauncherCore::LauncherCore() : settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::applicationName()) { mgr = new QNetworkAccessManager(); sapphireLauncher = new SapphireLauncher(*this); squareLauncher = new SquareLauncher(*this); @@ -355,152 +353,17 @@ LauncherWindow::LauncherWindow(QWidget* parent) : assetUpdater = new AssetUpdater(*this); readInitialInformation(); - - QMenu* fileMenu = menuBar()->addMenu("File"); - // sorry linux users, for some reason my global menu does not like qt6 apps right now -#if defined(Q_OS_LINUX) - menuBar()->setNativeMenuBar(false); -#endif - - QAction* settingsAction = fileMenu->addAction("Settings..."); - connect(settingsAction, &QAction::triggered, [=] { - auto window = new SettingsWindow(*this); - connect(this, &LauncherWindow::settingsChanged, window, &SettingsWindow::reloadControls); - window->show(); - }); - - QMenu* toolsMenu = menuBar()->addMenu("Tools"); - - QAction* launchOfficial = toolsMenu->addAction("Launch Official Client..."); - connect(launchOfficial, &QAction::triggered, [=] { - launchExecutable({currentProfile().gamePath + "/boot/ffxivboot64.exe"}); - }); - - QAction* launchSysInfo = toolsMenu->addAction("Launch System Info..."); - connect(launchSysInfo, &QAction::triggered, [=] { - launchExecutable({currentProfile().gamePath + "/boot/ffxivsysinfo64.exe"}); - }); - - QAction* launchCfgBackup = toolsMenu->addAction("Launch Config Backup..."); - connect(launchCfgBackup, &QAction::triggered, [=] { - launchExecutable({currentProfile().gamePath + "/boot/ffxivconfig64.exe"}); - }); - -#if defined(Q_OS_MAC) || defined(Q_OS_LINUX) - QMenu* wineMenu = toolsMenu->addMenu("Wine"); - - QAction* wineCfg = wineMenu->addAction("winecfg"); - connect(wineCfg, &QAction::triggered, [=] { - launchExecutable({"winecfg.exe"}); - }); - - QAction* controlPanel = wineMenu->addAction("Control Panel"); - connect(controlPanel, &QAction::triggered, [=] { - launchExecutable({"control.exe"}); - }); -#endif - - auto layout = new QFormLayout(); - - profileSelect = new QComboBox(); - connect(profileSelect, static_cast(&QComboBox::currentIndexChanged), [=](int index) { - reloadControls(); - }); - - layout->addRow("Profile", profileSelect); - - usernameEdit = new QLineEdit(); - layout->addRow("Username", usernameEdit); - - rememberUsernameBox = new QCheckBox(); - connect(rememberUsernameBox, &QCheckBox::stateChanged, [=](int) { - currentProfile().rememberUsername = rememberUsernameBox->isChecked(); - saveSettings(); - }); - layout->addRow("Remember Username?", rememberUsernameBox); - - passwordEdit = new QLineEdit(); - passwordEdit->setEchoMode(QLineEdit::EchoMode::Password); - layout->addRow("Password", passwordEdit); - - rememberPasswordBox = new QCheckBox(); - connect(rememberPasswordBox, &QCheckBox::stateChanged, [=](int) { - currentProfile().rememberPassword = rememberPasswordBox->isChecked(); - saveSettings(); - }); - layout->addRow("Remember Password?", rememberPasswordBox); - - otpEdit = new QLineEdit(); - layout->addRow("One-Time Password", otpEdit); - - auto loginButton = new QPushButton("Login"); - layout->addRow(loginButton); - - registerButton = new QPushButton("Register"); - layout->addRow(registerButton); - - auto emptyWidget = new QWidget(); - emptyWidget->setLayout(layout); - setCentralWidget(emptyWidget); - - connect(assetUpdater, &AssetUpdater::finishedUpdating, [=] { - auto info = LoginInformation{usernameEdit->text(), passwordEdit->text(), otpEdit->text()}; - - if(currentProfile().rememberUsername) { - auto job = new QKeychain::WritePasswordJob("LauncherWindow"); - job->setTextData(usernameEdit->text()); - job->setKey(currentProfile().name + "-username"); - job->start(); - } - - if(currentProfile().rememberPassword) { - auto job = new QKeychain::WritePasswordJob("LauncherWindow"); - job->setTextData(passwordEdit->text()); - job->setKey(currentProfile().name + "-password"); - job->start(); - } - - if(currentProfile().isSapphire) { - sapphireLauncher->login(currentProfile().lobbyURL, info); - } else { - squareBoot->bootCheck(info); - } - }); - - connect(loginButton, &QPushButton::released, [=] { - // update the assets first if needed, then it calls the slot above :-) - assetUpdater->update(); - }); - - connect(registerButton, &QPushButton::released, [=] { - if(currentProfile().isSapphire) { - auto info = LoginInformation{usernameEdit->text(), passwordEdit->text(), otpEdit->text()}; - sapphireLauncher->registerAccount(currentProfile().lobbyURL, info); - } - }); - - reloadControls(); } -LauncherWindow::~LauncherWindow() = default; - -ProfileSettings LauncherWindow::currentProfile() const { - return getProfile(profileSelect->currentIndex()); -} - -ProfileSettings& LauncherWindow::currentProfile() { - return getProfile(profileSelect->currentIndex()); -} - -ProfileSettings LauncherWindow::getProfile(int index) const { +ProfileSettings LauncherCore::getProfile(int index) const { return profileSettings[index]; } -ProfileSettings& LauncherWindow::getProfile(int index) { +ProfileSettings& LauncherCore::getProfile(int index) { return profileSettings[index]; } -int LauncherWindow::getProfileIndex(QString name) { +int LauncherCore::getProfileIndex(QString name) { for(int i = 0; i < profileSettings.size(); i++) { if(profileSettings[i].name == name) return i; @@ -509,7 +372,7 @@ int LauncherWindow::getProfileIndex(QString name) { return -1; } -QList LauncherWindow::profileList() const { +QList LauncherCore::profileList() const { QList list; for(auto profile : profileSettings) { list.append(profile.name); @@ -518,7 +381,7 @@ QList LauncherWindow::profileList() const { return list; } -int LauncherWindow::addProfile() { +int LauncherCore::addProfile() { ProfileSettings newProfile; newProfile.uuid = QUuid::createUuid(); newProfile.name = "New Profile"; @@ -530,7 +393,7 @@ int LauncherWindow::addProfile() { return profileSettings.size() - 1; } -int LauncherWindow::deleteProfile(QString name) { +int LauncherCore::deleteProfile(QString name) { int index = 0; for(int i = 0; i < profileSettings.size(); i++) { if(profileSettings[i].name == name) @@ -547,7 +410,7 @@ int LauncherWindow::deleteProfile(QString name) { return index - 1; } -void LauncherWindow::saveSettings() { +void LauncherCore::saveSettings() { settings.setValue("defaultProfile", defaultProfileIndex); for(int i = 0; i < profileSettings.size(); i++) { @@ -582,52 +445,4 @@ void LauncherWindow::saveSettings() { settings.endGroup(); } -} - -void LauncherWindow::reloadControls() { - if(currentlyReloadingControls) - return; - - currentlyReloadingControls = true; - - const int oldIndex = profileSelect->currentIndex(); - - profileSelect->clear(); - - for(const auto& profile : profileList()) { - profileSelect->addItem(profile); - } - - profileSelect->setCurrentIndex(oldIndex); - - if(profileSelect->currentIndex() == -1) { - profileSelect->setCurrentIndex(defaultProfileIndex); - } - - rememberUsernameBox->setChecked(currentProfile().rememberUsername); - if(currentProfile().rememberUsername) { - auto job = new QKeychain::ReadPasswordJob("LauncherWindow"); - job->setKey(currentProfile().name + "-username"); - job->start(); - - connect(job, &QKeychain::ReadPasswordJob::finished, [=](QKeychain::Job* j) { - usernameEdit->setText(job->textData()); - }); - } - - rememberPasswordBox->setChecked(currentProfile().rememberPassword); - if(currentProfile().rememberPassword) { - auto job = new QKeychain::ReadPasswordJob("LauncherWindow"); - job->setKey(currentProfile().name + "-password"); - job->start(); - - connect(job, &QKeychain::ReadPasswordJob::finished, [=](QKeychain::Job* j) { - passwordEdit->setText(job->textData()); - }); - } - - registerButton->setEnabled(currentProfile().isSapphire); - otpEdit->setEnabled(!currentProfile().isSapphire); - - currentlyReloadingControls = false; } \ No newline at end of file diff --git a/src/xivlauncher.h b/src/launchercore.h similarity index 74% rename from src/xivlauncher.h rename to src/launchercore.h index d90ec3c..a4d195e 100755 --- a/src/xivlauncher.h +++ b/src/launchercore.h @@ -4,9 +4,6 @@ #include #include #include -#include -#include -#include #include #include @@ -45,6 +42,8 @@ struct ProfileSettings { }; struct LoginInformation { + ProfileSettings* settings = nullptr; + QString username, password, oneTimePassword; }; @@ -57,18 +56,13 @@ struct LoginAuth { QString lobbyhost, frontierHost; }; -class LauncherWindow : public QMainWindow { +class LauncherCore : public QObject { Q_OBJECT public: - explicit LauncherWindow(QWidget* parent = nullptr); - - ~LauncherWindow() override; + LauncherCore(); QNetworkAccessManager* mgr; - ProfileSettings currentProfile() const; - ProfileSettings& currentProfile(); - ProfileSettings getProfile(int index) const; ProfileSettings& getProfile(int index); @@ -77,9 +71,9 @@ public: int addProfile(); int deleteProfile(QString name); - void launchGame(const LoginAuth auth); - void launchExecutable(QStringList args); - void launchExecutable(QProcess* process, QStringList args); + void launchGame(const ProfileSettings& settings, const LoginAuth auth); + void launchExecutable(const ProfileSettings& settings, QStringList args); + void launchExecutable(const ProfileSettings& settings, QProcess* process, QStringList args); void buildRequest(QNetworkRequest& request); void setSSL(QNetworkRequest& request); QString readVersion(QString path); @@ -90,26 +84,15 @@ public: QSettings settings; -public slots: - void reloadControls(); - -signals: - void settingsChanged(); - -private: - bool currentlyReloadingControls = false; - SapphireLauncher* sapphireLauncher; SquareBoot* squareBoot; SquareLauncher* squareLauncher; AssetUpdater* assetUpdater; - QComboBox* profileSelect; - QLineEdit* usernameEdit, *passwordEdit; - QLineEdit* otpEdit; - QCheckBox* rememberUsernameBox, *rememberPasswordBox; - QPushButton* registerButton; - - QVector profileSettings; int defaultProfileIndex = 0; +signals: + void settingsChanged(); + +private: + QVector profileSettings; }; diff --git a/src/launcherwindow.cpp b/src/launcherwindow.cpp new file mode 100644 index 0000000..f734850 --- /dev/null +++ b/src/launcherwindow.cpp @@ -0,0 +1,192 @@ +#include "launcherwindow.h" + +#include +#include +#include + +#include "settingswindow.h" +#include "squareboot.h" +#include "squarelauncher.h" +#include "sapphirelauncher.h" +#include "assetupdater.h" + +LauncherWindow::LauncherWindow(LauncherCore& core, QWidget* parent) : QMainWindow(parent), core(core) { + connect(&core, &LauncherCore::settingsChanged, this, &LauncherWindow::reloadControls); + + QMenu* fileMenu = menuBar()->addMenu("File"); + + QAction* settingsAction = fileMenu->addAction("Settings..."); + connect(settingsAction, &QAction::triggered, [=] { + auto window = new SettingsWindow(*this, this->core); + connect(&this->core, &LauncherCore::settingsChanged, window, &SettingsWindow::reloadControls); + window->show(); + }); + + QMenu* toolsMenu = menuBar()->addMenu("Tools"); + + QAction* launchOfficial = toolsMenu->addAction("Launch Official Client..."); + connect(launchOfficial, &QAction::triggered, [=] { + this->core.launchExecutable(currentProfile(), {currentProfile().gamePath + "/boot/ffxivboot64.exe"}); + }); + + QAction* launchSysInfo = toolsMenu->addAction("Launch System Info..."); + connect(launchSysInfo, &QAction::triggered, [=] { + this->core.launchExecutable(currentProfile(), {currentProfile().gamePath + "/boot/ffxivsysinfo64.exe"}); + }); + + QAction* launchCfgBackup = toolsMenu->addAction("Launch Config Backup..."); + connect(launchCfgBackup, &QAction::triggered, [=] { + this->core.launchExecutable(currentProfile(), {currentProfile().gamePath + "/boot/ffxivconfig64.exe"}); + }); + +#if defined(Q_OS_MAC) || defined(Q_OS_LINUX) + QMenu* wineMenu = toolsMenu->addMenu("Wine"); + + QAction* wineCfg = wineMenu->addAction("winecfg"); + connect(wineCfg, &QAction::triggered, [=] { + this->core.launchExecutable(currentProfile(), {"winecfg.exe"}); + }); + + QAction* controlPanel = wineMenu->addAction("Control Panel"); + connect(controlPanel, &QAction::triggered, [=] { + this->core.launchExecutable(currentProfile(), {"control.exe"}); + }); +#endif + + auto layout = new QFormLayout(); + + profileSelect = new QComboBox(); + connect(profileSelect, static_cast(&QComboBox::currentIndexChanged), [=](int index) { + reloadControls(); + }); + + layout->addRow("Profile", profileSelect); + + usernameEdit = new QLineEdit(); + layout->addRow("Username", usernameEdit); + + rememberUsernameBox = new QCheckBox(); + connect(rememberUsernameBox, &QCheckBox::stateChanged, [=](int) { + currentProfile().rememberUsername = rememberUsernameBox->isChecked(); + this->core.saveSettings(); + }); + layout->addRow("Remember Username?", rememberUsernameBox); + + passwordEdit = new QLineEdit(); + passwordEdit->setEchoMode(QLineEdit::EchoMode::Password); + layout->addRow("Password", passwordEdit); + + rememberPasswordBox = new QCheckBox(); + connect(rememberPasswordBox, &QCheckBox::stateChanged, [=](int) { + currentProfile().rememberPassword = rememberPasswordBox->isChecked(); + this->core.saveSettings(); + }); + layout->addRow("Remember Password?", rememberPasswordBox); + + otpEdit = new QLineEdit(); + layout->addRow("One-Time Password", otpEdit); + + auto loginButton = new QPushButton("Login"); + layout->addRow(loginButton); + + registerButton = new QPushButton("Register"); + layout->addRow(registerButton); + + auto emptyWidget = new QWidget(); + emptyWidget->setLayout(layout); + setCentralWidget(emptyWidget); + + connect(core.assetUpdater, &AssetUpdater::finishedUpdating, [=] { + auto info = LoginInformation{¤tProfile(), usernameEdit->text(), passwordEdit->text(), otpEdit->text()}; + + if(currentProfile().rememberUsername) { + auto job = new QKeychain::WritePasswordJob("LauncherWindow"); + job->setTextData(usernameEdit->text()); + job->setKey(currentProfile().name + "-username"); + job->start(); + } + + if(currentProfile().rememberPassword) { + auto job = new QKeychain::WritePasswordJob("LauncherWindow"); + job->setTextData(passwordEdit->text()); + job->setKey(currentProfile().name + "-password"); + job->start(); + } + + if(currentProfile().isSapphire) { + this->core.sapphireLauncher->login(currentProfile().lobbyURL, info); + } else { + this->core.squareBoot->bootCheck(info); + } + }); + + connect(loginButton, &QPushButton::released, [=] { + // update the assets first if needed, then it calls the slot above :-) + this->core.assetUpdater->update(currentProfile()); + }); + + connect(registerButton, &QPushButton::released, [=] { + if(currentProfile().isSapphire) { + auto info = LoginInformation{¤tProfile(), usernameEdit->text(), passwordEdit->text(), otpEdit->text()}; + this->core.sapphireLauncher->registerAccount(currentProfile().lobbyURL, info); + } + }); + + reloadControls(); +} + +ProfileSettings LauncherWindow::currentProfile() const { + return core.getProfile(profileSelect->currentIndex()); +} + +ProfileSettings& LauncherWindow::currentProfile() { + return core.getProfile(profileSelect->currentIndex()); +} + +void LauncherWindow::reloadControls() { + if(currentlyReloadingControls) + return; + + currentlyReloadingControls = true; + + const int oldIndex = profileSelect->currentIndex(); + + profileSelect->clear(); + + for(const auto& profile : core.profileList()) { + profileSelect->addItem(profile); + } + + profileSelect->setCurrentIndex(oldIndex); + + if(profileSelect->currentIndex() == -1) { + profileSelect->setCurrentIndex(core.defaultProfileIndex); + } + + rememberUsernameBox->setChecked(currentProfile().rememberUsername); + if(currentProfile().rememberUsername) { + auto job = new QKeychain::ReadPasswordJob("LauncherWindow"); + job->setKey(currentProfile().name + "-username"); + job->start(); + + connect(job, &QKeychain::ReadPasswordJob::finished, [=](QKeychain::Job* j) { + usernameEdit->setText(job->textData()); + }); + } + + rememberPasswordBox->setChecked(currentProfile().rememberPassword); + if(currentProfile().rememberPassword) { + auto job = new QKeychain::ReadPasswordJob("LauncherWindow"); + job->setKey(currentProfile().name + "-password"); + job->start(); + + connect(job, &QKeychain::ReadPasswordJob::finished, [=](QKeychain::Job* j) { + passwordEdit->setText(job->textData()); + }); + } + + registerButton->setEnabled(currentProfile().isSapphire); + otpEdit->setEnabled(!currentProfile().isSapphire); + + currentlyReloadingControls = false; +} \ No newline at end of file diff --git a/src/launcherwindow.h b/src/launcherwindow.h new file mode 100644 index 0000000..cf5d524 --- /dev/null +++ b/src/launcherwindow.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#include + +#include "launchercore.h" + +class LauncherWindow : public QMainWindow { + Q_OBJECT +public: + explicit LauncherWindow(LauncherCore& core, QWidget* parent = nullptr); + + ProfileSettings currentProfile() const; + ProfileSettings& currentProfile(); + +public slots: + void reloadControls(); + +private: + LauncherCore& core; + + bool currentlyReloadingControls = false; + + QComboBox* profileSelect; + QLineEdit* usernameEdit, *passwordEdit; + QLineEdit* otpEdit; + QCheckBox* rememberUsernameBox, *rememberPasswordBox; + QPushButton* registerButton; +}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index c363dc3..0cb39f0 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,8 @@ -#include "xivlauncher.h" +#include "launchercore.h" +#include "launcherwindow.h" + #include +#include int main(int argc, char* argv[]) { QApplication app(argc, argv); @@ -13,7 +16,15 @@ int main(int argc, char* argv[]) { QCoreApplication::setApplicationName("xivlauncher-debug"); #endif - LauncherWindow w; + LauncherCore c; + + QCommandLineParser parser; + parser.setApplicationDescription("Cross-platform FFXIV Launcher"); + parser.addHelpOption(); + parser.addVersionOption(); + parser.process(app); + + LauncherWindow w(c); w.show(); return app.exec(); diff --git a/src/sapphirelauncher.cpp b/src/sapphirelauncher.cpp index d30dc2a..41c9a6f 100644 --- a/src/sapphirelauncher.cpp +++ b/src/sapphirelauncher.cpp @@ -5,7 +5,7 @@ #include #include -SapphireLauncher::SapphireLauncher(LauncherWindow& window) : window(window) { +SapphireLauncher::SapphireLauncher(LauncherCore& window) : window(window) { } @@ -33,7 +33,7 @@ void SapphireLauncher::login(QString lobbyUrl, const LoginInformation& info) { auth.frontierHost = document["frontierHost"].toString(); auth.region = 3; - window.launchGame(auth); + window.launchGame(*info.settings, auth); } else { auto messageBox = new QMessageBox(QMessageBox::Icon::Critical, "Failed to Login", "Invalid username/password."); messageBox->show(); @@ -64,6 +64,6 @@ void SapphireLauncher::registerAccount(QString lobbyUrl, const LoginInformation& auth.frontierHost = document["frontierHost"].toString(); auth.region = 3; - window.launchGame(auth); + window.launchGame(*info.settings, auth); }); } \ No newline at end of file diff --git a/src/sapphirelauncher.h b/src/sapphirelauncher.h index 5328be7..4fed69d 100644 --- a/src/sapphirelauncher.h +++ b/src/sapphirelauncher.h @@ -2,15 +2,15 @@ #include -#include "xivlauncher.h" +#include "launchercore.h" class SapphireLauncher : QObject { public: - SapphireLauncher(LauncherWindow& window); + SapphireLauncher(LauncherCore& window); void login(QString lobbyUrl, const LoginInformation& info); void registerAccount(QString lobbyUrl, const LoginInformation& info); private: - LauncherWindow& window; + LauncherCore& window; }; \ No newline at end of file diff --git a/src/settingswindow.cpp b/src/settingswindow.cpp index d47f0fd..8464b30 100644 --- a/src/settingswindow.cpp +++ b/src/settingswindow.cpp @@ -11,9 +11,10 @@ #include #include -#include "xivlauncher.h" +#include "launchercore.h" +#include "launcherwindow.h" -SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window(window), QWidget(parent) { +SettingsWindow::SettingsWindow(LauncherWindow& window, LauncherCore& core, QWidget* parent) : core(core), window(window), QWidget(parent) { setWindowTitle("Settings"); setWindowModality(Qt::WindowModality::ApplicationModal); @@ -30,17 +31,17 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window auto addProfileButton = new QPushButton("Add Profile"); connect(addProfileButton, &QPushButton::pressed, [=] { - profileWidget->setCurrentRow(this->window.addProfile()); + profileWidget->setCurrentRow(this->core.addProfile()); - this->window.saveSettings(); + this->core.saveSettings(); }); mainLayout->addWidget(addProfileButton, 2, 0); deleteProfileButton = new QPushButton("Delete Profile"); connect(deleteProfileButton, &QPushButton::pressed, [=] { - profileWidget->setCurrentRow(this->window.deleteProfile(getCurrentProfile().name)); + profileWidget->setCurrentRow(this->core.deleteProfile(getCurrentProfile().name)); - this->window.saveSettings(); + this->core.saveSettings(); }); mainLayout->addWidget(deleteProfileButton, 3, 0); @@ -49,7 +50,7 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window getCurrentProfile().name = nameEdit->text(); reloadControls(); - this->window.saveSettings(); + this->core.saveSettings(); }); mainLayout->addWidget(nameEdit, 0, 1); @@ -66,10 +67,10 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window connect(directXCombo, static_cast(&QComboBox::currentIndexChanged), [=](int index) { getCurrentProfile().useDX9 = directXCombo->currentIndex() == 1; - this->window.saveSettings(); + this->core.saveSettings(); }); - currentGameDirectory = new QLabel(window.currentProfile().gamePath); + currentGameDirectory = new QLabel(); currentGameDirectory->setWordWrap(true); gameBoxLayout->addRow("Game Directory", currentGameDirectory); @@ -78,9 +79,9 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window getCurrentProfile().gamePath = QFileDialog::getExistingDirectory(this, "Open Game Directory"); this->reloadControls(); - this->window.saveSettings(); + this->core.saveSettings(); - this->window.readGameVersion(); + this->core.readGameVersion(); }); gameBoxLayout->addWidget(selectDirectoryButton); @@ -100,7 +101,7 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window connect(encryptArgumentsBox, &QCheckBox::stateChanged, [=](int) { getCurrentProfile().encryptArguments = encryptArgumentsBox->isChecked(); - this->window.saveSettings(); + this->core.saveSettings(); }); loginBoxLayout->addRow("Encrypt Game Arguments", encryptArgumentsBox); @@ -108,7 +109,7 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window connect(enableDalamudBox, &QCheckBox::stateChanged, [=](int) { getCurrentProfile().enableDalamud = enableDalamudBox->isChecked(); - this->window.saveSettings(); + this->core.saveSettings(); }); loginBoxLayout->addRow("Enable Dalamud Injection", enableDalamudBox); @@ -120,8 +121,7 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window getCurrentProfile().isSapphire = index == 1; reloadControls(); - this->window.reloadControls(); - this->window.saveSettings(); + this->core.saveSettings(); }); loginBoxLayout->addRow("Server Lobby", serverType); @@ -129,7 +129,7 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window lobbyServerURL = new QLineEdit(); connect(lobbyServerURL, &QLineEdit::editingFinished, [=] { getCurrentProfile().lobbyURL = lobbyServerURL->text(); - this->window.saveSettings(); + this->core.saveSettings(); }); loginBoxLayout->addRow("Lobby URL", lobbyServerURL); @@ -137,8 +137,7 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window connect(rememberUsernameBox, &QCheckBox::stateChanged, [=](int) { getCurrentProfile().rememberUsername = rememberUsernameBox->isChecked(); - this->window.reloadControls(); - this->window.saveSettings(); + this->core.saveSettings(); }); loginBoxLayout->addRow("Remember Username?", rememberUsernameBox); @@ -146,8 +145,7 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window connect(rememberPasswordBox, &QCheckBox::stateChanged, [=](int) { getCurrentProfile().rememberPassword = rememberPasswordBox->isChecked(); - this->window.reloadControls(); - this->window.saveSettings(); + this->core.saveSettings(); }); loginBoxLayout->addRow("Remember Password?", rememberPasswordBox); @@ -163,7 +161,7 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window infoLabel->setWordWrap(true); wineBoxLayout->addWidget(infoLabel); - winePathLabel = new QLabel(window.currentProfile().winePath); + winePathLabel = new QLabel(); winePathLabel->setWordWrap(true); wineBoxLayout->addRow("Wine Executable", winePathLabel); @@ -184,19 +182,19 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window connect(wineVersionCombo, static_cast(&QComboBox::currentIndexChanged), [this](int index) { getCurrentProfile().wineVersion = index; - this->window.readWineInfo(getCurrentProfile()); - this->window.saveSettings(); + this->core.readWineInfo(getCurrentProfile()); + this->core.saveSettings(); this->reloadControls(); }); connect(selectWineButton, &QPushButton::pressed, [this] { getCurrentProfile().winePath = QFileDialog::getOpenFileName(this, "Open Wine Executable"); - this->window.saveSettings(); + this->core.saveSettings(); this->reloadControls(); }); - winePrefixDirectory = new QLabel(window.currentProfile().winePrefixPath); + winePrefixDirectory = new QLabel(); winePrefixDirectory->setWordWrap(true); wineBoxLayout->addRow("Wine Prefix", winePrefixDirectory); @@ -204,7 +202,7 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window connect(selectPrefixButton, &QPushButton::pressed, [this] { getCurrentProfile().winePrefixPath = QFileDialog::getExistingDirectory(this, "Open Wine Prefix"); - this->window.saveSettings(); + this->core.saveSettings(); this->reloadControls(); }); wineBoxLayout->addWidget(selectPrefixButton); @@ -216,12 +214,11 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window wineBoxLayout->addWidget(openPrefixButton); auto enableDXVKhud = new QCheckBox("Enable DXVK HUD"); - enableDXVKhud->setChecked(window.currentProfile().enableDXVKhud); wineBoxLayout->addWidget(enableDXVKhud); connect(enableDXVKhud, &QCheckBox::stateChanged, [this](int state) { - this->window.currentProfile().enableDXVKhud = state; - this->window.settings.setValue("enableDXVKhud", static_cast(state)); + getCurrentProfile().enableDXVKhud = state; + this->core.settings.setValue("enableDXVKhud", static_cast(state)); }); #endif @@ -237,7 +234,7 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window connect(useEsync, &QCheckBox::stateChanged, [this](int state) { getCurrentProfile().useEsync = state; - this->window.saveSettings(); + this->core.saveSettings(); }); useGamescope = new QCheckBox("Use Gamescope"); @@ -251,7 +248,7 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window connect(useGamescope, &QCheckBox::stateChanged, [this](int state) { getCurrentProfile().useGamescope = state; - this->window.saveSettings(); + this->core.saveSettings(); }); useGamemode = new QCheckBox("Use Gamemode"); @@ -265,7 +262,7 @@ SettingsWindow::SettingsWindow(LauncherWindow& window, QWidget* parent) : window connect(useGamemode, &QCheckBox::stateChanged, [this](int state) { getCurrentProfile().useGamemode = state; - this->window.saveSettings(); + this->core.saveSettings(); }); #endif @@ -282,15 +279,15 @@ void SettingsWindow::reloadControls() { profileWidget->clear(); - for(auto profile : window.profileList()) { + for(const auto& profile : core.profileList()) { profileWidget->addItem(profile); } profileWidget->setCurrentRow(oldRow); // deleting the main profile is unsupported behavior - deleteProfileButton->setEnabled(window.profileList().size() > 1); + deleteProfileButton->setEnabled(core.profileList().size() > 1); - ProfileSettings& profile = window.getProfile(profileWidget->currentRow()); + ProfileSettings& profile = core.getProfile(profileWidget->currentRow()); nameEdit->setText(profile.name); // game @@ -325,7 +322,7 @@ void SettingsWindow::reloadControls() { } ProfileSettings& SettingsWindow::getCurrentProfile() { - return this->window.getProfile(profileWidget->currentRow()); + return this->core.getProfile(profileWidget->currentRow()); } void SettingsWindow::openPath(const QString path) { diff --git a/src/settingswindow.h b/src/settingswindow.h index f433911..304eacc 100644 --- a/src/settingswindow.h +++ b/src/settingswindow.h @@ -8,12 +8,13 @@ #include #include +class LauncherCore; class LauncherWindow; struct ProfileSettings; class SettingsWindow : public QWidget { public: - SettingsWindow(LauncherWindow& window, QWidget* parent = nullptr); + SettingsWindow(LauncherWindow& window, LauncherCore& core, QWidget* parent = nullptr); public slots: void reloadControls(); @@ -48,4 +49,5 @@ private: bool currentlyReloadingControls = false; LauncherWindow& window; + LauncherCore& core; }; \ No newline at end of file diff --git a/src/squareboot.cpp b/src/squareboot.cpp index 1ed742f..57a9510 100644 --- a/src/squareboot.cpp +++ b/src/squareboot.cpp @@ -6,7 +6,7 @@ #include "squarelauncher.h" -SquareBoot::SquareBoot(LauncherWindow& window, SquareLauncher& launcher) : window(window), launcher(launcher) { +SquareBoot::SquareBoot(LauncherCore& window, SquareLauncher& launcher) : window(window), launcher(launcher) { } @@ -17,7 +17,7 @@ void SquareBoot::bootCheck(LoginInformation& info) { QUrl url; url.setScheme("http"); url.setHost("patch-bootver.ffxiv.com"); - url.setPath(QString("/http/win32/ffxivneo_release_boot/%1").arg(window.currentProfile().bootVersion)); + url.setPath(QString("/http/win32/ffxivneo_release_boot/%1").arg(info.settings->bootVersion)); url.setQuery(query); auto request = QNetworkRequest(url); diff --git a/src/squareboot.h b/src/squareboot.h index 111d0d1..3b47740 100644 --- a/src/squareboot.h +++ b/src/squareboot.h @@ -1,16 +1,16 @@ #pragma once -#include "xivlauncher.h" +#include "launchercore.h" class SquareLauncher; class SquareBoot : public QObject { public: - SquareBoot(LauncherWindow& window, SquareLauncher& launcher); + SquareBoot(LauncherCore& window, SquareLauncher& launcher); void bootCheck(LoginInformation& info); private: - LauncherWindow& window; + LauncherCore& window; SquareLauncher& launcher; }; \ No newline at end of file diff --git a/src/squarelauncher.cpp b/src/squarelauncher.cpp index cb462d2..fa6e788 100644 --- a/src/squarelauncher.cpp +++ b/src/squarelauncher.cpp @@ -6,9 +6,9 @@ #include #include -#include "xivlauncher.h" +#include "launchercore.h" -SquareLauncher::SquareLauncher(LauncherWindow& window) : window(window) { +SquareLauncher::SquareLauncher(LauncherCore& window) : window(window) { } @@ -88,7 +88,7 @@ void SquareLauncher::login(const LoginInformation& info, const QUrl referer) { auth.region = parts[5].toInt(); auth.maxExpansion = parts[13].toInt(); - readExpansionVersions(auth.maxExpansion); + readExpansionVersions(info, auth.maxExpansion); registerSession(info); } @@ -103,7 +103,7 @@ void SquareLauncher::registerSession(const LoginInformation& info) { QUrl url; url.setScheme("https"); url.setHost("patch-gamever.ffxiv.com"); - url.setPath(QString("/http/win32/ffxivneo_release_game/%1/%2").arg(window.currentProfile().gameVersion, SID)); + url.setPath(QString("/http/win32/ffxivneo_release_game/%1/%2").arg(info.settings->gameVersion, SID)); auto request = QNetworkRequest(url); window.setSSL(request); @@ -111,7 +111,7 @@ void SquareLauncher::registerSession(const LoginInformation& info) { request.setRawHeader("User-Agent", "FFXIV PATCH CLIENT"); request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded"); - QString report = window.currentProfile().bootVersion + "=" + getBootHash(); + QString report = info.settings->bootVersion + "=" + getBootHash(info); for(int i = 0; i < expansionVersions.size(); i++) report += QString("\nex%1\t%2").arg(QString::number(i + 1), expansionVersions[i]); @@ -121,7 +121,7 @@ void SquareLauncher::registerSession(const LoginInformation& info) { if(reply->rawHeaderList().contains("X-Patch-Unique-Id")) { auth.SID = reply->rawHeader("X-Patch-Unique-Id"); - window.launchGame(auth); + window.launchGame(*info.settings, auth); } else { auto messageBox = new QMessageBox(QMessageBox::Icon::Critical, "Failed to Login", "Failed the anti-tamper check. Please restore your game to the original state or update the game."); messageBox->show(); @@ -129,7 +129,7 @@ void SquareLauncher::registerSession(const LoginInformation& info) { }); } -QString SquareLauncher::getBootHash() { +QString SquareLauncher::getBootHash(const LoginInformation& info) { const QList fileList = { "ffxivboot.exe", @@ -142,7 +142,7 @@ QString SquareLauncher::getBootHash() { QString result; for (int i = 0; i < fileList.count(); i++) { - result += fileList[i] + "/" + getFileHash(window.currentProfile().gamePath + "/boot/" + fileList[i]); + result += fileList[i] + "/" + getFileHash(info.settings->gamePath + "/boot/" + fileList[i]); if (i != fileList.length() - 1) result += ","; @@ -151,9 +151,9 @@ QString SquareLauncher::getBootHash() { return result; } -void SquareLauncher::readExpansionVersions(int max) { +void SquareLauncher::readExpansionVersions(const LoginInformation& info, int max) { expansionVersions.clear(); for(int i = 0; i < max; i++) - expansionVersions.push_back(window.readVersion(QString("%1/game/sqpack/ex%2/ex%2.ver").arg(window.currentProfile().gamePath, QString::number(i + 1)))); + expansionVersions.push_back(window.readVersion(QString("%1/game/sqpack/ex%2/ex%2.ver").arg(info.settings->gamePath, QString::number(i + 1)))); } \ No newline at end of file diff --git a/src/squarelauncher.h b/src/squarelauncher.h index 1bc5531..c724348 100644 --- a/src/squarelauncher.h +++ b/src/squarelauncher.h @@ -1,25 +1,25 @@ #pragma once -#include "xivlauncher.h" +#include "launchercore.h" class SquareLauncher : public QObject { public: - SquareLauncher(LauncherWindow& window); + SquareLauncher(LauncherCore& window); void getStored(const LoginInformation& info); - void login(const LoginInformation& info, const QUrl referer); + void login(const LoginInformation& info, QUrl referer); void registerSession(const LoginInformation& info); private: - QString getBootHash(); - void readExpansionVersions(int max); + QString getBootHash(const LoginInformation& info); + void readExpansionVersions(const LoginInformation& info, int max); QString stored, SID; LoginAuth auth; - LauncherWindow& window; + LauncherCore& window; QList expansionVersions; }; \ No newline at end of file