diff options
Diffstat (limited to 'logic')
-rw-r--r-- | logic/LegacyInstance.cpp | 5 | ||||
-rw-r--r-- | logic/LegacyInstance.h | 1 | ||||
-rw-r--r-- | logic/LegacyUpdate.cpp | 169 | ||||
-rw-r--r-- | logic/LegacyUpdate.h | 13 | ||||
-rw-r--r-- | logic/OneSixLibrary.cpp | 27 | ||||
-rw-r--r-- | logic/OneSixLibrary.h | 1 | ||||
-rw-r--r-- | logic/OneSixUpdate.cpp | 18 | ||||
-rw-r--r-- | logic/auth/MojangAccount.cpp | 2 | ||||
-rw-r--r-- | logic/auth/YggdrasilTask.cpp | 110 | ||||
-rw-r--r-- | logic/auth/YggdrasilTask.h | 25 | ||||
-rw-r--r-- | logic/auth/flows/AuthenticateTask.cpp | 36 | ||||
-rw-r--r-- | logic/auth/flows/AuthenticateTask.h | 8 | ||||
-rw-r--r-- | logic/auth/flows/RefreshTask.cpp | 32 | ||||
-rw-r--r-- | logic/auth/flows/RefreshTask.h | 8 | ||||
-rw-r--r-- | logic/auth/flows/ValidateTask.cpp | 15 | ||||
-rw-r--r-- | logic/auth/flows/ValidateTask.h | 8 | ||||
-rw-r--r-- | logic/net/URLConstants.cpp | 2 | ||||
-rw-r--r-- | logic/net/URLConstants.h | 2 |
18 files changed, 362 insertions, 120 deletions
diff --git a/logic/LegacyInstance.cpp b/logic/LegacyInstance.cpp index 4f2dfd9b..d06b8827 100644 --- a/logic/LegacyInstance.cpp +++ b/logic/LegacyInstance.cpp @@ -159,6 +159,11 @@ QString LegacyInstance::binDir() const return PathCombine(minecraftRoot(), "bin"); } +QString LegacyInstance::libDir() const +{ + return PathCombine(minecraftRoot(), "lib"); +} + QString LegacyInstance::savesDir() const { return PathCombine(minecraftRoot(), "saves"); diff --git a/logic/LegacyInstance.h b/logic/LegacyInstance.h index 636addeb..badaf7e3 100644 --- a/logic/LegacyInstance.h +++ b/logic/LegacyInstance.h @@ -41,6 +41,7 @@ public: std::shared_ptr<ModList> texturePackList(); ////// Directories ////// + QString libDir() const; QString savesDir() const; QString texturePacksDir() const; QString jarModsDir() const; diff --git a/logic/LegacyUpdate.cpp b/logic/LegacyUpdate.cpp index 5d82a76b..15c99234 100644 --- a/logic/LegacyUpdate.cpp +++ b/logic/LegacyUpdate.cpp @@ -26,9 +26,56 @@ #include <JlCompress.h> #include "logger/QsLog.h" #include "logic/net/URLConstants.h" +#include <QStringList> LegacyUpdate::LegacyUpdate(BaseInstance *inst, QObject *parent) : Task(parent), m_inst(inst) { + // 1.3 - 1.3.2 + auto libs13 = QList<FMLlib>{ + {"argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b", false}, + {"guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f", false}, + {"asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82", false}}; + + fmlLibsMapping["1.3.2"] = libs13; + + auto libs14 = QList<FMLlib>{ + {"argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b", false}, + {"guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f", false}, + {"asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82", false}, + {"bcprov-jdk15on-147.jar", "b6f5d9926b0afbde9f4dbe3db88c5247be7794bb", false}}; + + fmlLibsMapping["1.4"] = libs14; + fmlLibsMapping["1.4.1"] = libs14; + fmlLibsMapping["1.4.2"] = libs14; + fmlLibsMapping["1.4.3"] = libs14; + fmlLibsMapping["1.4.4"] = libs14; + fmlLibsMapping["1.4.5"] = libs14; + fmlLibsMapping["1.4.6"] = libs14; + fmlLibsMapping["1.4.7"] = libs14; + + fmlLibsMapping["1.5"] = QList<FMLlib>{ + {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51", false}, + {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a", false}, + {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58", false}, + {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65", true}, + {"deobfuscation_data_1.5.zip", "5f7c142d53776f16304c0bbe10542014abad6af8", false}, + {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85", true}}; + + fmlLibsMapping["1.5.1"] = QList<FMLlib>{ + {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51", false}, + {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a", false}, + {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58", false}, + {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65", true}, + {"deobfuscation_data_1.5.1.zip", "22e221a0d89516c1f721d6cab056a7e37471d0a6", false}, + {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85", true}}; + + fmlLibsMapping["1.5.2"] = QList<FMLlib>{ + {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51", false}, + {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a", false}, + {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58", false}, + {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65", true}, + {"deobfuscation_data_1.5.2.zip", "446e55cd986582c70fcf12cb27bc00114c5adfd9", false}, + {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85", true}}; } void LegacyUpdate::executeTask() @@ -50,10 +97,130 @@ void LegacyUpdate::executeTask() else { */ - lwjglStart(); + fmllibsStart(); //} } +void LegacyUpdate::fmllibsStart() +{ + // Get the mod list + LegacyInstance *inst = (LegacyInstance *)m_inst; + auto modList = inst->jarModList(); + + bool forge_present = false; + + QString version = inst->intendedVersionId(); + if (!fmlLibsMapping.contains(version)) + { + lwjglStart(); + return; + } + + auto &libList = fmlLibsMapping[version]; + + // determine if we need some libs for FML or forge + setStatus(tr("Checking for FML libraries...")); + for (unsigned i = 0; i < modList->size(); i++) + { + auto &mod = modList->operator[](i); + + // do not use disabled mods. + if (!mod.enabled()) + continue; + + if (mod.type() != Mod::MOD_ZIPFILE) + continue; + + if (mod.mmc_id().contains("forge", Qt::CaseInsensitive)) + { + forge_present = true; + break; + } + if (mod.mmc_id().contains("fml", Qt::CaseInsensitive)) + { + forge_present = true; + break; + } + } + // we don't... + if (!forge_present) + { + lwjglStart(); + return; + } + + // now check the lib folder inside the instance for files. + for (auto &lib : libList) + { + QFileInfo libInfo(PathCombine(inst->libDir(), lib.name)); + if (libInfo.exists()) + continue; + fmlLibsToProcess.append(lib); + } + + // if everything is in place, there's nothing to do here... + if (fmlLibsToProcess.isEmpty()) + { + lwjglStart(); + return; + } + + // download missing libs to our place + setStatus(tr("Dowloading FML libraries...")); + auto dljob = new NetJob("FML libraries"); + auto metacache = MMC->metacache(); + for (auto &lib : fmlLibsToProcess) + { + auto entry = metacache->resolveEntry("fmllibs", lib.name); + QString urlString = lib.ours ? URLConstants::FMLLIBS_OUR_BASE_URL + lib.name + : URLConstants::FMLLIBS_FORGE_BASE_URL + lib.name; + dljob->addNetAction(CacheDownload::make(QUrl(urlString), entry)); + } + + connect(dljob, SIGNAL(succeeded()), SLOT(fmllibsFinished())); + connect(dljob, SIGNAL(failed()), SLOT(fmllibsFailed())); + connect(dljob, SIGNAL(progress(qint64, qint64)), SIGNAL(progress(qint64, qint64))); + legacyDownloadJob.reset(dljob); + legacyDownloadJob->start(); +} + +void LegacyUpdate::fmllibsFinished() +{ + legacyDownloadJob.reset(); + if(!fmlLibsToProcess.isEmpty()) + { + setStatus(tr("Copying FML libraries into the instance...")); + LegacyInstance *inst = (LegacyInstance *)m_inst; + auto metacache = MMC->metacache(); + int index = 0; + for (auto &lib : fmlLibsToProcess) + { + progress(index, fmlLibsToProcess.size()); + auto entry = metacache->resolveEntry("fmllibs", lib.name); + auto path = PathCombine(inst->libDir(), lib.name); + if(!ensureFilePathExists(path)) + { + emitFailed(tr("Failed creating FML library folder inside the instance.")); + return; + } + if (!QFile::copy(entry->getFullPath(), PathCombine(inst->libDir(), lib.name))) + { + emitFailed(tr("Failed copying Forge/FML library: %1.").arg(lib.name)); + return; + } + index++; + } + progress(index, fmlLibsToProcess.size()); + } + lwjglStart(); +} + +void LegacyUpdate::fmllibsFailed() +{ + emitFailed("Game update failed: it was impossible to fetch the required FML libraries."); + return; +} + void LegacyUpdate::lwjglStart() { LegacyInstance *inst = (LegacyInstance *)m_inst; diff --git a/logic/LegacyUpdate.h b/logic/LegacyUpdate.h index 613eb1f9..5b073cb7 100644 --- a/logic/LegacyUpdate.h +++ b/logic/LegacyUpdate.h @@ -27,6 +27,13 @@ class BaseInstance; class QuaZip; class Mod; +struct FMLlib +{ + QString name; + QString checksum; + bool ours; +}; + class LegacyUpdate : public Task { Q_OBJECT @@ -44,6 +51,10 @@ slots: void jarFinished(); void jarFailed(); + void fmllibsStart(); + void fmllibsFinished(); + void fmllibsFailed(); + void extractLwjgl(); void ModTheJar(); @@ -72,4 +83,6 @@ private: private: NetJobPtr legacyDownloadJob; BaseInstance *m_inst = nullptr; + QList<FMLlib> fmlLibsToProcess; + QMap<QString, QList<FMLlib>> fmlLibsMapping; }; diff --git a/logic/OneSixLibrary.cpp b/logic/OneSixLibrary.cpp index c78679d1..7032809d 100644 --- a/logic/OneSixLibrary.cpp +++ b/logic/OneSixLibrary.cpp @@ -140,33 +140,32 @@ QString OneSixLibrary::hint() const return m_hint; } -bool OneSixLibrary::filesExist() +QStringList OneSixLibrary::files() { + QStringList retval; QString storage = storagePath(); if (storage.contains("${arch}")) { QString cooked_storage = storage; cooked_storage.replace("${arch}", "32"); - QFileInfo info32(PathCombine("libraries", cooked_storage)); - if (!info32.exists()) - { - return false; - } + retval.append(PathCombine("libraries", cooked_storage)); cooked_storage = storage; cooked_storage.replace("${arch}", "64"); - QFileInfo info64(PathCombine("libraries", cooked_storage)); - if (!info64.exists()) - { - return false; - } + retval.append(PathCombine("libraries", cooked_storage)); } else + retval.append(PathCombine("libraries", storage)); + return retval; +} + +bool OneSixLibrary::filesExist() +{ + auto libFiles = files(); + for(auto file: libFiles) { - QFileInfo info(PathCombine("libraries", storage)); + QFileInfo info(file); if (!info.exists()) - { return false; - } } return true; } diff --git a/logic/OneSixLibrary.h b/logic/OneSixLibrary.h index 3bd21c51..a74b7cac 100644 --- a/logic/OneSixLibrary.h +++ b/logic/OneSixLibrary.h @@ -143,4 +143,5 @@ public: bool extractTo(QString target_dir); bool filesExist(); + QStringList files(); }; diff --git a/logic/OneSixUpdate.cpp b/logic/OneSixUpdate.cpp index cddd0def..27bc415f 100644 --- a/logic/OneSixUpdate.cpp +++ b/logic/OneSixUpdate.cpp @@ -268,10 +268,16 @@ void OneSixUpdate::jarlibStart() auto metacache = MMC->metacache(); QList<ForgeXzDownloadPtr> ForgeLibs; + QList<std::shared_ptr<OneSixLibrary>> brokenLocalLibs; + for (auto lib : libs) { if (lib->hint() == "local") + { + if(!lib->filesExist()) + brokenLocalLibs.append(lib); continue; + } QString raw_storage = lib->storagePath(); QString raw_dl = lib->downloadUrl(); @@ -305,6 +311,18 @@ void OneSixUpdate::jarlibStart() f(raw_storage, raw_dl); } } + if(!brokenLocalLibs.empty()) + { + jarlibDownloadJob.reset(); + QStringList failed; + for(auto brokenLib : brokenLocalLibs) + { + failed.append(brokenLib->files()); + } + QString failed_all = failed.join("\n"); + emitFailed(tr("Some libraries marked as 'local' are missing their jar files:\n%1\n\nYou'll have to correct this problem manually. If this is an externally tracked instance, make sure to run it at least once outside of MultiMC.").arg(failed_all)); + return; + } // TODO: think about how to propagate this from the original json file... or IF AT ALL QString forgeMirrorList = "http://files.minecraftforge.net/mirror-brand.list"; if (!ForgeLibs.empty()) diff --git a/logic/auth/MojangAccount.cpp b/logic/auth/MojangAccount.cpp index 6c937ef1..31a238ba 100644 --- a/logic/auth/MojangAccount.cpp +++ b/logic/auth/MojangAccount.cpp @@ -220,7 +220,7 @@ void MojangAccount::authFailed(QString reason) auto session = m_currentTask->getAssignedSession(); // This is emitted when the yggdrasil tasks time out or are cancelled. // -> we treat the error as no-op - if (reason == "Yggdrasil task cancelled.") + if (m_currentTask->state() == YggdrasilTask::STATE_FAILED_SOFT) { if (session) { diff --git a/logic/auth/YggdrasilTask.cpp b/logic/auth/YggdrasilTask.cpp index 7679b11f..ab6ac5e4 100644 --- a/logic/auth/YggdrasilTask.cpp +++ b/logic/auth/YggdrasilTask.cpp @@ -29,11 +29,12 @@ YggdrasilTask::YggdrasilTask(MojangAccount *account, QObject *parent) : Task(parent), m_account(account) { + changeState(STATE_CREATED); } void YggdrasilTask::executeTask() { - setStatus(getStateMessage(STATE_SENDING_REQUEST)); + changeState(STATE_SENDING_REQUEST); // Get the content of the request we're going to send to the server. QJsonDocument doc(getRequestContent()); @@ -73,12 +74,16 @@ void YggdrasilTask::heartbeat() void YggdrasilTask::abort() { progress(timeout_max, timeout_max); + // TODO: actually use this in a meaningful way + m_aborted = YggdrasilTask::BY_USER; m_netReply->abort(); } void YggdrasilTask::abortByTimeout() { progress(timeout_max, timeout_max); + // TODO: actually use this in a meaningful way + m_aborted = YggdrasilTask::BY_TIMEOUT; m_netReply->abort(); } @@ -96,11 +101,21 @@ void YggdrasilTask::sslErrors(QList<QSslError> errors) void YggdrasilTask::processReply() { - setStatus(getStateMessage(STATE_PROCESSING_RESPONSE)); + changeState(STATE_PROCESSING_RESPONSE); - if (m_netReply->error() == QNetworkReply::SslHandshakeFailedError) + switch (m_netReply->error()) { - emitFailed( + case QNetworkReply::NoError: + break; + case QNetworkReply::TimeoutError: + changeState(STATE_FAILED_SOFT, tr("Authentication operation timed out.")); + return; + case QNetworkReply::OperationCanceledError: + changeState(STATE_FAILED_SOFT, tr("Authentication operation cancelled.")); + return; + case QNetworkReply::SslHandshakeFailedError: + changeState( + STATE_FAILED_SOFT, tr("<b>SSL Handshake failed.</b><br/>There might be a few causes for it:<br/>" "<ul>" "<li>You use Windows XP and need to <a " @@ -111,16 +126,13 @@ void YggdrasilTask::processReply() "<li>Possibly something else. Check the MultiMC log file for details</li>" "</ul>")); return; - } - - // any network errors lead to offline mode right now - if (m_netReply->error() >= QNetworkReply::ConnectionRefusedError && - m_netReply->error() <= QNetworkReply::UnknownNetworkError) - { - // WARNING/FIXME: the value here is used in MojangAccount to detect the cancel/timeout - emitFailed("Yggdrasil task cancelled."); - QLOG_ERROR() << "Yggdrasil task cancelled because of: " << m_netReply->error() << " : " - << m_netReply->errorString(); + // used for invalid credentials and similar errors. Fall through. + case QNetworkReply::ContentOperationNotPermittedError: + break; + default: + changeState(STATE_FAILED_SOFT, + tr("Authentication operation failed due to a network error: %1 (%2)") + .arg(m_netReply->errorString()).arg(m_netReply->error())); return; } @@ -140,22 +152,16 @@ void YggdrasilTask::processReply() // pass an empty json object to the processResponse function. if (jsonError.error == QJsonParseError::NoError || replyData.size() == 0) { - if (processResponse(replyData.size() > 0 ? doc.object() : QJsonObject())) - { - emitSucceeded(); - return; - } - - // errors happened anyway? - emitFailed(m_error ? m_error->m_errorMessageVerbose - : tr("An unknown error occurred when processing the response " - "from the authentication server.")); + processResponse(replyData.size() > 0 ? doc.object() : QJsonObject()); + return; } else { - emitFailed(tr("Failed to parse Yggdrasil JSON response: %1 at offset %2.") - .arg(jsonError.errorString()) - .arg(jsonError.offset)); + changeState(STATE_FAILED_SOFT, tr("Failed to parse authentication server response " + "JSON response: %1 at offset %2.") + .arg(jsonError.errorString()) + .arg(jsonError.offset)); + QLOG_ERROR() << replyData; } return; } @@ -171,20 +177,21 @@ void YggdrasilTask::processReply() // stuff there. QLOG_DEBUG() << "The request failed, but the server gave us an error message. " "Processing error."; - emitFailed(processError(doc.object())); + processError(doc.object()); } else { // The server didn't say anything regarding the error. Give the user an unknown // error. - QLOG_DEBUG() << "The request failed and the server gave no error message. " - "Unknown error."; - emitFailed(tr("An unknown error occurred when trying to communicate with the " - "authentication server: %1").arg(m_netReply->errorString())); + QLOG_DEBUG() + << "The request failed and the server gave no error message. Unknown error."; + changeState(STATE_FAILED_SOFT, + tr("An unknown error occurred when trying to communicate with the " + "authentication server: %1").arg(m_netReply->errorString())); } } -QString YggdrasilTask::processError(QJsonObject responseData) +void YggdrasilTask::processError(QJsonObject responseData) { QJsonValue errorVal = responseData.value("error"); QJsonValue errorMessageValue = responseData.value("errorMessage"); @@ -194,24 +201,51 @@ QString YggdrasilTask::processError(QJsonObject responseData) { m_error = std::shared_ptr<Error>(new Error{ errorVal.toString(""), errorMessageValue.toString(""), causeVal.toString("")}); - return m_error->m_errorMessageVerbose; + changeState(STATE_FAILED_HARD, m_error->m_errorMessageVerbose); } else { // Error is not in standard format. Don't set m_error and return unknown error. - return tr("An unknown Yggdrasil error occurred."); + changeState(STATE_FAILED_HARD, tr("An unknown Yggdrasil error occurred.")); } } -QString YggdrasilTask::getStateMessage(const YggdrasilTask::State state) const +QString YggdrasilTask::getStateMessage() const { - switch (state) + switch (m_state) { + case STATE_CREATED: + return "Waiting..."; case STATE_SENDING_REQUEST: return tr("Sending request to auth servers..."); case STATE_PROCESSING_RESPONSE: return tr("Processing response from servers..."); + case STATE_SUCCEEDED: + return tr("Authentication task succeeded."); + case STATE_FAILED_SOFT: + return tr("Failed to contact the authentication server."); + case STATE_FAILED_HARD: + return tr("Failed to authenticate."); default: - return tr("Processing. Please wait..."); + return tr("..."); + } +} + +void YggdrasilTask::changeState(YggdrasilTask::State newState, QString reason) +{ + m_state = newState; + setStatus(getStateMessage()); + if (newState == STATE_SUCCEEDED) + { + emitSucceeded(); + } + else if (newState == STATE_FAILED_HARD || newState == STATE_FAILED_SOFT) + { + emitFailed(reason); } } + +YggdrasilTask::State YggdrasilTask::state() +{ + return m_state; +} diff --git a/logic/auth/YggdrasilTask.h b/logic/auth/YggdrasilTask.h index b24f909f..ed70b957 100644 --- a/logic/auth/YggdrasilTask.h +++ b/logic/auth/YggdrasilTask.h @@ -60,17 +60,28 @@ public: QString m_cause; }; -protected: + enum AbortedBy + { + BY_NOTHING, + BY_USER, + BY_TIMEOUT + } m_aborted = BY_NOTHING; + /** * Enum for describing the state of the current task. * Used by the getStateMessage function to determine what the status message should be. */ enum State { + STATE_CREATED, STATE_SENDING_REQUEST, STATE_PROCESSING_RESPONSE, - STATE_OTHER, - }; + STATE_FAILED_SOFT, //!< soft failure. this generally means the user auth details haven't been invalidated + STATE_FAILED_HARD, //!< hard failure. auth is invalid + STATE_SUCCEEDED + } m_state = STATE_CREATED; + +protected: virtual void executeTask(); @@ -94,21 +105,21 @@ protected: * Note: If the response from the server was blank, and the HTTP code was 200, this function is called with * an empty QJsonObject. */ - virtual bool processResponse(QJsonObject responseData) = 0; + virtual void processResponse(QJsonObject responseData) = 0; /** * Processes an error response received from the server. * The default implementation will read data from Yggdrasil's standard error response format and set it as this task's Error. * \returns a QString error message that will be passed to emitFailed. */ - virtual QString processError(QJsonObject responseData); + virtual void processError(QJsonObject responseData); /** * Returns the state message for the given state. * Used to set the status message for the task. * Should be overridden by subclasses that want to change messages for a given state. */ - virtual QString getStateMessage(const State state) const; + virtual QString getStateMessage() const; protected slots: @@ -117,10 +128,12 @@ slots: void heartbeat(); void sslErrors(QList<QSslError>); + void changeState(State newState, QString reason=QString()); public slots: virtual void abort() override; void abortByTimeout(); + State state(); protected: // FIXME: segfault disaster waiting to happen MojangAccount *m_account = nullptr; diff --git a/logic/auth/flows/AuthenticateTask.cpp b/logic/auth/flows/AuthenticateTask.cpp index 6548c4e9..340235e3 100644 --- a/logic/auth/flows/AuthenticateTask.cpp +++ b/logic/auth/flows/AuthenticateTask.cpp @@ -71,7 +71,7 @@ QJsonObject AuthenticateTask::getRequestContent() const return req; } -bool AuthenticateTask::processResponse(QJsonObject responseData) +void AuthenticateTask::processResponse(QJsonObject responseData) { // Read the response data. We need to get the client token, access token, and the selected // profile. @@ -84,16 +84,13 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) if (clientToken.isEmpty()) { // Fail if the server gave us an empty client token - // TODO: Set an error properly to display to the user. - QLOG_ERROR() << "Server didn't send a client token."; - return false; + changeState(STATE_FAILED_HARD, tr("Authentication server didn't send a client token.")); + return; } if (!m_account->m_clientToken.isEmpty() && clientToken != m_account->m_clientToken) { - // The server changed our client token! Obey its wishes, but complain. That's what I do - // for my parents, so... - QLOG_WARN() << "Server changed our client token to '" << clientToken - << "'. This shouldn't happen, but it isn't really a big deal."; + changeState(STATE_FAILED_HARD, tr("Authentication server attempted to change the client token. This isn't supported.")); + return; } // Set the client token. m_account->m_clientToken = clientToken; @@ -104,8 +101,8 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) if (accessToken.isEmpty()) { // Fail if the server didn't give us an access token. - // TODO: Set an error properly to display to the user. - QLOG_ERROR() << "Server didn't send an access token."; + changeState(STATE_FAILED_HARD, tr("Authentication server didn't send an access token.")); + return; } // Set the access token. m_account->m_accessToken = accessToken; @@ -149,16 +146,13 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) QString currentProfileId = currentProfile.value("id").toString(""); if (currentProfileId.isEmpty()) { - // TODO: Set an error to display to the user. - QLOG_ERROR() << "Server didn't specify a currently selected profile."; - return false; + changeState(STATE_FAILED_HARD, tr("Authentication server didn't specify a currently selected profile. The account exists, but likely isn't premium.")); + return; } if (!m_account->setCurrentProfile(currentProfileId)) { - // TODO: Set an error to display to the user. - QLOG_ERROR() << "Server specified a selected profile that wasn't in the available " - "profiles list."; - return false; + changeState(STATE_FAILED_HARD, tr("Authentication server specified a selected profile that wasn't in the available profiles list.")); + return; } // this is what the vanilla launcher passes to the userProperties launch param @@ -181,7 +175,7 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) // We've made it through the minefield of possible errors. Return true to indicate that // we've succeeded. QLOG_DEBUG() << "Finished reading authentication response."; - return true; + changeState(STATE_SUCCEEDED); } QString AuthenticateTask::getEndpoint() const @@ -189,15 +183,15 @@ QString AuthenticateTask::getEndpoint() const return "authenticate"; } -QString AuthenticateTask::getStateMessage(const YggdrasilTask::State state) const +QString AuthenticateTask::getStateMessage() const { - switch (state) + switch (m_state) { case STATE_SENDING_REQUEST: return tr("Authenticating: Sending request..."); case STATE_PROCESSING_RESPONSE: return tr("Authenticating: Processing response..."); default: - return YggdrasilTask::getStateMessage(state); + return YggdrasilTask::getStateMessage(); } } diff --git a/logic/auth/flows/AuthenticateTask.h b/logic/auth/flows/AuthenticateTask.h index b6564657..13a000aa 100644 --- a/logic/auth/flows/AuthenticateTask.h +++ b/logic/auth/flows/AuthenticateTask.h @@ -33,13 +33,13 @@ public: AuthenticateTask(MojangAccount *account, const QString &password, QObject *parent = 0); protected: - virtual QJsonObject getRequestContent() const; + virtual QJsonObject getRequestContent() const override; - virtual QString getEndpoint() const; + virtual QString getEndpoint() const override; - virtual bool processResponse(QJsonObject responseData); + virtual void processResponse(QJsonObject responseData) override; - QString getStateMessage(const YggdrasilTask::State state) const; + virtual QString getStateMessage() const override; private: QString m_password; diff --git a/logic/auth/flows/RefreshTask.cpp b/logic/auth/flows/RefreshTask.cpp index 5a55ed91..7e926c2b 100644 --- a/logic/auth/flows/RefreshTask.cpp +++ b/logic/auth/flows/RefreshTask.cpp @@ -60,7 +60,7 @@ QJsonObject RefreshTask::getRequestContent() const return req; } -bool RefreshTask::processResponse(QJsonObject responseData) +void RefreshTask::processResponse(QJsonObject responseData) { // Read the response data. We need to get the client token, access token, and the selected // profile. @@ -73,17 +73,13 @@ bool RefreshTask::processResponse(QJsonObject responseData) if (clientToken.isEmpty()) { // Fail if the server gave us an empty client token - // TODO: Set an error properly to display to the user. - QLOG_ERROR() << "Server didn't send a client token."; - return false; + changeState(STATE_FAILED_HARD, tr("Authentication server didn't send a client token.")); + return; } if (!m_account->m_clientToken.isEmpty() && clientToken != m_account->m_clientToken) { - // The server changed our client token! Obey its wishes, but complain. That's what I do - // for my parents, so... - QLOG_ERROR() << "Server changed our client token to '" << clientToken - << "'. This shouldn't happen, but it isn't really a big deal."; - return false; + changeState(STATE_FAILED_HARD, tr("Authentication server attempted to change the client token. This isn't supported.")); + return; } // Now, we set the access token. @@ -92,9 +88,8 @@ bool RefreshTask::processResponse(QJsonObject responseData) if (accessToken.isEmpty()) { // Fail if the server didn't give us an access token. - // TODO: Set an error properly to display to the user. - QLOG_ERROR() << "Server didn't send an access token."; - return false; + changeState(STATE_FAILED_HARD, tr("Authentication server didn't send an access token.")); + return; } // we validate that the server responded right. (our current profile = returned current @@ -103,9 +98,8 @@ bool RefreshTask::processResponse(QJsonObject responseData) QString currentProfileId = currentProfile.value("id").toString(""); if (m_account->currentProfile()->id != currentProfileId) { - // TODO: Set an error to display to the user. - QLOG_ERROR() << "Server didn't specify the same selected profile as ours."; - return false; + changeState(STATE_FAILED_HARD, tr("Authentication server didn't specify the same prefile as expected.")); + return; } // this is what the vanilla launcher passes to the userProperties launch param @@ -130,7 +124,7 @@ bool RefreshTask::processResponse(QJsonObject responseData) QLOG_DEBUG() << "Finished reading refresh response."; // Reset the access token. m_account->m_accessToken = accessToken; - return true; + changeState(STATE_SUCCEEDED); } QString RefreshTask::getEndpoint() const @@ -138,15 +132,15 @@ QString RefreshTask::getEndpoint() const return "refresh"; } -QString RefreshTask::getStateMessage(const YggdrasilTask::State state) const +QString RefreshTask::getStateMessage() const { - switch (state) + switch (m_state) { case STATE_SENDING_REQUEST: return tr("Refreshing login token..."); case STATE_PROCESSING_RESPONSE: return tr("Refreshing login token: Processing response..."); default: - return YggdrasilTask::getStateMessage(state); + return YggdrasilTask::getStateMessage(); } } diff --git a/logic/auth/flows/RefreshTask.h b/logic/auth/flows/RefreshTask.h index 0dadc025..ad07ba2d 100644 --- a/logic/auth/flows/RefreshTask.h +++ b/logic/auth/flows/RefreshTask.h @@ -33,12 +33,12 @@ public: RefreshTask(MojangAccount * account); protected: - virtual QJsonObject getRequestContent() const; + virtual QJsonObject getRequestContent() const override; - virtual QString getEndpoint() const; + virtual QString getEndpoint() const override; - virtual bool processResponse(QJsonObject responseData); + virtual void processResponse(QJsonObject responseData) override; - QString getStateMessage(const YggdrasilTask::State state) const; + virtual QString getStateMessage() const override; }; diff --git a/logic/auth/flows/ValidateTask.cpp b/logic/auth/flows/ValidateTask.cpp index 4f7323fd..f3fc1e71 100644 --- a/logic/auth/flows/ValidateTask.cpp +++ b/logic/auth/flows/ValidateTask.cpp @@ -38,11 +38,10 @@ QJsonObject ValidateTask::getRequestContent() const return req; } -bool ValidateTask::processResponse(QJsonObject responseData) +void ValidateTask::processResponse(QJsonObject responseData) { // Assume that if processError wasn't called, then the request was successful. - emitSucceeded(); - return true; + changeState(YggdrasilTask::STATE_SUCCEEDED); } QString ValidateTask::getEndpoint() const @@ -50,15 +49,15 @@ QString ValidateTask::getEndpoint() const return "validate"; } -QString ValidateTask::getStateMessage(const YggdrasilTask::State state) const +QString ValidateTask::getStateMessage() const { - switch (state) + switch (m_state) { - case STATE_SENDING_REQUEST: + case YggdrasilTask::STATE_SENDING_REQUEST: return tr("Validating access token: Sending request..."); - case STATE_PROCESSING_RESPONSE: + case YggdrasilTask::STATE_PROCESSING_RESPONSE: return tr("Validating access token: Processing response..."); default: - return YggdrasilTask::getStateMessage(state); + return YggdrasilTask::getStateMessage(); } } diff --git a/logic/auth/flows/ValidateTask.h b/logic/auth/flows/ValidateTask.h index 0e34f0c3..7bc2fe01 100644 --- a/logic/auth/flows/ValidateTask.h +++ b/logic/auth/flows/ValidateTask.h @@ -35,13 +35,13 @@ public: ValidateTask(MojangAccount *account, QObject *parent = 0); protected: - virtual QJsonObject getRequestContent() const; + virtual QJsonObject getRequestContent() const override; - virtual QString getEndpoint() const; + virtual QString getEndpoint() const override; - virtual bool processResponse(QJsonObject responseData); + virtual void processResponse(QJsonObject responseData) override; - QString getStateMessage(const YggdrasilTask::State state) const; + virtual QString getStateMessage() const override; private: }; diff --git a/logic/net/URLConstants.cpp b/logic/net/URLConstants.cpp index 14b28085..de919448 100644 --- a/logic/net/URLConstants.cpp +++ b/logic/net/URLConstants.cpp @@ -16,4 +16,6 @@ const QString MOJANG_STATUS_URL("http://status.mojang.com/check"); const QString MOJANG_STATUS_NEWS_URL("http://status.mojang.com/news"); const QString LITELOADER_URL("http://dl.liteloader.com/versions/versions.json"); const QString IMGUR_BASE_URL("https://api.imgur.com/3/"); +const QString FMLLIBS_OUR_BASE_URL("http://files.multimc.org/fmllibs/"); +const QString FMLLIBS_FORGE_BASE_URL("http://files.minecraftforge.net/fmllibs/"); }
\ No newline at end of file diff --git a/logic/net/URLConstants.h b/logic/net/URLConstants.h index c1064115..392d7362 100644 --- a/logic/net/URLConstants.h +++ b/logic/net/URLConstants.h @@ -34,4 +34,6 @@ extern const QString MOJANG_STATUS_URL; extern const QString MOJANG_STATUS_NEWS_URL; extern const QString LITELOADER_URL; extern const QString IMGUR_BASE_URL; +extern const QString FMLLIBS_OUR_BASE_URL; +extern const QString FMLLIBS_FORGE_BASE_URL; } |