diff options
Diffstat (limited to 'libmultimc/src')
-rw-r--r-- | libmultimc/src/fullversion.cpp | 5 | ||||
-rw-r--r-- | libmultimc/src/fullversionfactory.cpp | 206 | ||||
-rw-r--r-- | libmultimc/src/gameupdatetask.cpp | 235 | ||||
-rw-r--r-- | libmultimc/src/instance.cpp | 15 | ||||
-rw-r--r-- | libmultimc/src/library.cpp | 37 |
5 files changed, 399 insertions, 99 deletions
diff --git a/libmultimc/src/fullversion.cpp b/libmultimc/src/fullversion.cpp new file mode 100644 index 00000000..53664c2a --- /dev/null +++ b/libmultimc/src/fullversion.cpp @@ -0,0 +1,5 @@ +#include <QtCore> +#include "fullversion.h" +#include <library.h> + +// ECHO, echo, echo, ....
\ No newline at end of file diff --git a/libmultimc/src/fullversionfactory.cpp b/libmultimc/src/fullversionfactory.cpp new file mode 100644 index 00000000..bb55b4a9 --- /dev/null +++ b/libmultimc/src/fullversionfactory.cpp @@ -0,0 +1,206 @@ +#include "fullversionfactory.h" +#include "fullversion.h" +#include <library.h> + +class LibraryFinalizer +{ +public: + LibraryFinalizer(QSharedPointer<Library> library) + { + m_library = library; + } + + QSharedPointer<Library> m_library; +}; + +// Library rules (if any) +QList<QSharedPointer<Rule> > FullVersionFactory::parse4rules(QJsonObject & baseObj) +{ + QList<QSharedPointer<Rule> > rules; + auto rulesVal = baseObj.value("rules"); + if(rulesVal.isArray()) + { + QJsonArray ruleList = rulesVal.toArray(); + for(auto ruleVal : ruleList) + { + QSharedPointer<Rule> rule; + if(!ruleVal.isObject()) + continue; + auto ruleObj = ruleVal.toObject(); + auto actionVal = ruleObj.value("action"); + if(!actionVal.isString()) + continue; + auto action = RuleAction_fromString(actionVal.toString()); + if(action == Defer) + continue; + + auto osVal = ruleObj.value("os"); + if(!osVal.isObject()) + { + // add a new implicit action rule + rules.append(ImplicitRule::create(action)); + } + else + { + auto osObj = osVal.toObject(); + auto osNameVal = osObj.value("name"); + if(!osNameVal.isString()) + continue; + OpSys requiredOs = OpSys_fromString(osNameVal.toString()); + QString versionRegex = osObj.value("version").toString(); + // add a new OS rule + rules.append(OsRule::create(action, requiredOs, versionRegex)); + } + } + } + return rules; +} + + +QSharedPointer<FullVersion> FullVersionFactory::parse4(QJsonObject root, QSharedPointer<FullVersion> fullVersion) +{ + fullVersion->id = root.value("id").toString(); + + // if it's on our legacy list, it's legacy + if(legacyWhitelist.contains(fullVersion->id)) + fullVersion->isLegacy = true; + + fullVersion->mainClass = root.value("mainClass").toString(); + auto procArgsValue = root.value("processArguments"); + if(procArgsValue.isString()) + { + fullVersion->processArguments = procArgsValue.toString(); + QString toCompare = fullVersion->processArguments.toLower(); + if(toCompare == "legacy") + { + fullVersion->minecraftArguments = " ${auth_player_name} ${auth_session}"; + fullVersion->isLegacy = true; + } + else if(toCompare == "username_session") + { + fullVersion->minecraftArguments = "--username ${auth_player_name} --session ${auth_session}"; + } + else if(toCompare == "username_session_version") + { + fullVersion->minecraftArguments = "--username ${auth_player_name} --session ${auth_session} --version ${profile_name}"; + } + } + + auto minecraftArgsValue = root.value("minecraftArguments"); + if(minecraftArgsValue.isString()) + { + fullVersion->minecraftArguments = minecraftArgsValue.toString(); + } + + fullVersion->releaseTime = root.value("releaseTime").toString(); + fullVersion->time = root.value("time").toString(); + + // Iterate through the list, if it's a list. + auto librariesValue = root.value("libraries"); + if(!librariesValue.isArray()) + return fullVersion; + + QJsonArray libList = root.value("libraries").toArray(); + for (auto libVal : libList) + { + if (!libVal.isObject()) + { + continue; + } + + QJsonObject libObj = libVal.toObject(); + + // Library name + auto nameVal = libObj.value("name"); + if(!nameVal.isString()) + continue; + QSharedPointer<Library> library(new Library(nameVal.toString())); + + // Extract excludes (if any) + auto extractVal = libObj.value("extract"); + if(extractVal.isObject()) + { + QStringList excludes; + auto extractObj = extractVal.toObject(); + auto excludesVal = extractObj.value("exclude"); + if(!excludesVal.isArray()) + goto SKIP_EXTRACTS; + auto excludesList = excludesVal.toArray(); + for(auto excludeVal : excludesList) + { + if(excludeVal.isString()) + excludes.append(excludeVal.toString()); + } + library->extract_excludes = excludes; + } + SKIP_EXTRACTS: + + auto nativesVal = libObj.value("natives"); + if(nativesVal.isObject()) + { + library->setIsNative(); + auto nativesObj = nativesVal.toObject(); + auto iter = nativesObj.begin(); + while(iter != nativesObj.end()) + { + auto osType = OpSys_fromString(iter.key()); + if(osType == Os_Other) + continue; + if(!iter.value().isString()) + continue; + library->addNative(osType, iter.value().toString()); + iter++; + } + } + library->setRules(parse4rules(libObj)); + library->finalize(); + fullVersion->libraries.append(library); + } + return fullVersion; +} + +QSharedPointer<FullVersion> FullVersionFactory::parse(QByteArray data) +{ + QSharedPointer<FullVersion> readVersion(new FullVersion()); + + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); + + if (jsonError.error != QJsonParseError::NoError) + { + error_string = QString( "Error reading version file :") + " " + jsonError.errorString(); + m_error = FullVersionFactory::ParseError; + return QSharedPointer<FullVersion>(); + } + + if(!jsonDoc.isObject()) + { + error_string = "Error reading version file."; + m_error = FullVersionFactory::ParseError; + return QSharedPointer<FullVersion>(); + } + QJsonObject root = jsonDoc.object(); + + readVersion->minimumLauncherVersion = root.value("minimumLauncherVersion").toDouble(); + switch(readVersion->minimumLauncherVersion) + { + case 1: + case 2: + case 3: + case 4: + return parse4(root, readVersion); + // ADD MORE HERE :D + default: + error_string = "Version file was for an unrecognized launcher version. RIP"; + m_error = FullVersionFactory::UnsupportedVersion; + return QSharedPointer<FullVersion>(); + } +} + + +FullVersionFactory::FullVersionFactory() +{ + m_error = FullVersionFactory::AllOK; + legacyWhitelist.append("1.5.1"); + legacyWhitelist.append("1.5.2"); +} diff --git a/libmultimc/src/gameupdatetask.cpp b/libmultimc/src/gameupdatetask.cpp index c718ce71..bae85c17 100644 --- a/libmultimc/src/gameupdatetask.cpp +++ b/libmultimc/src/gameupdatetask.cpp @@ -25,40 +25,34 @@ #include <QDebug> #include "minecraftversionlist.h" +#include "fullversionfactory.h" +#include <fullversion.h> #include "pathutils.h" -#include "netutils.h" + GameUpdateTask::GameUpdateTask(const LoginResponse &response, Instance *inst, QObject *parent) : Task(parent), m_response(response) { m_inst = inst; m_updateState = StateInit; - m_currentDownload = 0; } void GameUpdateTask::executeTask() { updateStatus(); - QNetworkAccessManager networkMgr; - netMgr = &networkMgr; - // Get a pointer to the version object that corresponds to the instance's version. - MinecraftVersion *targetVersion = (MinecraftVersion *)MinecraftVersionList::getMainList(). + targetVersion = (MinecraftVersion *)MinecraftVersionList::getMainList(). findVersion(m_inst->intendedVersion()); - Q_ASSERT_X(targetVersion != NULL, "game update", "instance's intended version is not an actual version"); - - // Make directories - QDir binDir(m_inst->binDir()); - if (!binDir.exists() && !binDir.mkpath(".")) + if(targetVersion == NULL) { - error("Failed to create bin folder."); + //Q_ASSERT_X(targetVersion != NULL, "game update", "instance's intended version is not an actual version"); + setState(StateFinished); + emit gameUpdateComplete(m_response); return; } - - ///////////////////////// // BUILD DOWNLOAD LIST // ///////////////////////// @@ -66,90 +60,150 @@ void GameUpdateTask::executeTask() setState(StateDetermineURLs); + if (targetVersion->launcherVersion() == MinecraftVersion::Launcher16) + { + determineNewVersion(); + } + else + { + getLegacyJar(); + } + QEventLoop loop; + loop.exec(); +} + +void GameUpdateTask::determineNewVersion() +{ + QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/"); + urlstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".json"; + auto dljob = DownloadJob::create(QUrl(urlstr)); + specificVersionDownloadJob.reset(new JobList()); + specificVersionDownloadJob->add(dljob); + connect(specificVersionDownloadJob.data(), SIGNAL(finished()), SLOT(versionFileFinished())); + connect(specificVersionDownloadJob.data(), SIGNAL(failed()), SLOT(versionFileFailed())); + connect(specificVersionDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + download_queue.enqueue(specificVersionDownloadJob); +} + +void GameUpdateTask::versionFileFinished() +{ + JobPtr firstJob = specificVersionDownloadJob->getFirstJob(); + auto DlJob = firstJob.dynamicCast<DownloadJob>(); + FullVersionFactory parser; + auto version = parser.parse(DlJob->m_data); - // Add the URL for minecraft.jar + if(!version) + { + error(parser.error_string); + exit(0); + } + + if(version->isLegacy) + { + getLegacyJar(); + return; + } + // save the version file in $instanceId/version.json and versions/$version/$version.json + QString version_id = targetVersion->descriptor(); + QString mc_dir = m_inst->minecraftDir(); + QString inst_dir = m_inst->rootDir(); + QString version1 = PathCombine(inst_dir, "/version.json"); + QString version2 = QString("versions/") + version_id + "/" + version_id + ".json"; + DownloadJob::ensurePathExists(version1); + DownloadJob::ensurePathExists(version2); + QFile vfile1 (version1); + QFile vfile2 (version2); + vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly ); + vfile2.open(QIODevice::Truncate | QIODevice::WriteOnly ); + vfile1.write(DlJob->m_data); + vfile2.write(DlJob->m_data); + vfile1.close(); + vfile2.close(); + + // download the right jar, save it in versions/$version/$version.jar + QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/"); + urlstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".jar"; + QString targetstr ("versions/"); + targetstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".jar"; + auto dljob = DownloadJob::create(QUrl(urlstr), targetstr); + + jarlibDownloadJob.reset(new JobList()); + jarlibDownloadJob->add(dljob); + connect(jarlibDownloadJob.data(), SIGNAL(finished()), SLOT(jarlibFinished())); + connect(jarlibDownloadJob.data(), SIGNAL(failed()), SLOT(jarlibFailed())); + connect(jarlibDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + // determine and download all the libraries, save them in libraries/whatever... + download_queue.enqueue(jarlibDownloadJob); +} + +void GameUpdateTask::jarlibFinished() +{ + m_inst->setCurrentVersion(targetVersion->descriptor()); + m_inst->setShouldUpdate(false); + m_inst->setIsForNewLauncher(true); + exit(1); +} + +void GameUpdateTask::jarlibFailed() +{ + error("Failed to download the binary garbage. Try again. Maybe. IF YOU DARE"); + exit(0); +} + +void GameUpdateTask::versionFileFailed() +{ + error("Failed to download the version description. Try again."); + exit(0); +} + + +// this is legacy minecraft... +void GameUpdateTask::getLegacyJar() +{ + // Make directories + QDir binDir(m_inst->binDir()); + if (!binDir.exists() && !binDir.mkpath(".")) + { + error("Failed to create bin folder."); + return; + } + + // Add the URL for minecraft.jar // This will be either 'minecraft' or the version number, depending on where // we're downloading from. QString jarFilename = "minecraft"; - - // FIXME: this is NOT enough if (targetVersion->launcherVersion() == MinecraftVersion::Launcher16) + { jarFilename = targetVersion->descriptor(); + } QUrl mcJarURL = targetVersion->downloadURL() + jarFilename + ".jar"; qDebug() << mcJarURL.toString(); - m_downloadList.append(FileToDownload::Create(mcJarURL, PathCombine(m_inst->minecraftDir(), "bin/minecraft.jar"))); - - + auto dljob = DownloadJob::create(mcJarURL, PathCombine(m_inst->minecraftDir(), "bin/minecraft.jar")); - //////////////////// - // DOWNLOAD FILES // - //////////////////// - setState(StateDownloadFiles); - for (int i = 0; i < m_downloadList.length(); i++) - { - m_currentDownload = i; - if (!downloadFile(m_downloadList[i])) - return; - } - - - - /////////////////// - // INSTALL FILES // - /////////////////// - setState(StateInstall); - - // Nothing to do here yet + legacyDownloadJob.reset(new JobList()); + legacyDownloadJob->add(dljob); + connect(legacyDownloadJob.data(), SIGNAL(finished()), SLOT(legacyJarFinished())); + connect(legacyDownloadJob.data(), SIGNAL(failed()), SLOT(legacyJarFailed())); + connect(legacyDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); - - - ////////////// - // FINISHED // - ////////////// + download_queue.enqueue(legacyDownloadJob); +} + + +void GameUpdateTask::legacyJarFinished() +{ setState(StateFinished); emit gameUpdateComplete(m_response); + m_inst->setIsForNewLauncher(true); + exit(1); } -bool GameUpdateTask::downloadFile( const FileToDownloadPtr file ) +void GameUpdateTask::legacyJarFailed() { - setSubStatus("Downloading " + file->url().toString()); - QNetworkReply *reply = netMgr->get(QNetworkRequest(file->url())); - - this->connect(reply, SIGNAL(downloadProgress(qint64,qint64)), - SLOT(updateDownloadProgress(qint64,qint64))); - - NetUtils::waitForNetRequest(reply); - - if (reply->error() == QNetworkReply::NoError) - { - QString filePath = file->path(); - QFile outFile(filePath); - if (outFile.exists() && !outFile.remove()) - { - error("Can't delete old file " + file->path() + ": " + outFile.errorString()); - return false; - } - - if (!outFile.open(QIODevice::WriteOnly)) - { - error("Can't write to " + file->path() + ": " + outFile.errorString()); - return false; - } - - outFile.write(reply->readAll()); - outFile.close(); - } - else - { - error("Can't download " + file->url().toString() + ": " + reply->errorString()); - return false; - } - - // TODO: Check file integrity after downloading. - - return true; + emit gameUpdateError("failed to download the minecraft.jar"); + exit(0); } int GameUpdateTask::state() const @@ -223,22 +277,7 @@ void GameUpdateTask::error(const QString &msg) void GameUpdateTask::updateDownloadProgress(qint64 current, qint64 total) { // The progress on the current file is current / total - float currentDLProgress = (float) current / (float) total; // Cast ALL the values! - - // The overall progress is (current progress + files downloaded) / total files to download - float overallDLProgress = ((currentDLProgress + m_currentDownload) / (float) m_downloadList.length()); - - // Multiply by 100 to make it a percentage. - setProgress((int)(overallDLProgress * 100)); -} - -FileToDownloadPtr FileToDownload::Create(const QUrl &url, const QString &path, QObject *parent) -{ - return FileToDownloadPtr(new FileToDownload (url, path, parent)); + float currentDLProgress = (float) current / (float) total; + setProgress((int)(currentDLProgress * 100)); // convert to percentage } -FileToDownload::FileToDownload(const QUrl &url, const QString &path, QObject *parent) : - QObject(parent), m_dlURL(url), m_dlPath(path) -{ - -} diff --git a/libmultimc/src/instance.cpp b/libmultimc/src/instance.cpp index 08cd6605..5fdb5064 100644 --- a/libmultimc/src/instance.cpp +++ b/libmultimc/src/instance.cpp @@ -34,7 +34,8 @@ Instance::Instance(const QString &rootDir, QObject *parent) : settings().registerSetting(new Setting("iconKey", "default")); settings().registerSetting(new Setting("notes", "")); settings().registerSetting(new Setting("NeedsRebuild", true)); - settings().registerSetting(new Setting("ShouldForceUpdate", false)); + settings().registerSetting(new Setting("IsForNewLauncher", false)); + settings().registerSetting(new Setting("ShouldUpdate", false)); settings().registerSetting(new Setting("JarVersion", "Unknown")); settings().registerSetting(new Setting("LwjglVersion", "2.9.0")); settings().registerSetting(new Setting("IntendedJarVersion", "")); @@ -62,6 +63,18 @@ Instance::Instance(const QString &rootDir, QObject *parent) : // Auto login settings().registerSetting(new OverrideSetting("AutoLogin", globalSettings->getSetting("AutoLogin"))); + + // Console + settings().registerSetting(new OverrideSetting("ShowConsole", globalSettings->getSetting("ShowConsole"))); + settings().registerSetting(new OverrideSetting("AutoCloseConsole", globalSettings->getSetting("AutoCloseConsole"))); + + // Overrides + settings().registerSetting(new Setting("OverrideConsole", false)); + settings().registerSetting(new Setting("OverrideWindow", false)); + settings().registerSetting(new Setting("OverrideLogin", false)); + settings().registerSetting(new Setting("OverrideMemory", false)); + settings().registerSetting(new Setting("OverrideJava", false)); + settings().registerSetting(new Setting("OverrideCommands", false)); } QString Instance::id() const diff --git a/libmultimc/src/library.cpp b/libmultimc/src/library.cpp new file mode 100644 index 00000000..9d4cc6e3 --- /dev/null +++ b/libmultimc/src/library.cpp @@ -0,0 +1,37 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/library.h" + +RuleAction RuleAction_fromString(QString name) +{ + if(name == "allow") + return Allow; + if(name == "disallow") + return Disallow; + return Defer; +} + +OpSys OpSys_fromString(QString name) +{ + if(name == "linux") + return Os_Linux; + if(name == "windows") + return Os_Windows; + if(name == "osx") + return Os_OSX; + return Os_Other; +} +// default url for lib: |