diff options
| author | Petr Mrázek <peterix@gmail.com> | 2014-05-10 01:53:32 +0200 |
|---|---|---|
| committer | Petr Mrázek <peterix@gmail.com> | 2014-06-09 01:38:30 +0200 |
| commit | 92abe4c603e1f4931cd02ae6b752cb7054d8e30d (patch) | |
| tree | 571c6bc638b474af7e44f4db626f15e301286a65 | |
| parent | 9860d5ee12acde8f7893848dac53f59ea66da281 (diff) | |
| download | PrismLauncher-92abe4c603e1f4931cd02ae6b752cb7054d8e30d.tar.gz PrismLauncher-92abe4c603e1f4931cd02ae6b752cb7054d8e30d.tar.bz2 PrismLauncher-92abe4c603e1f4931cd02ae6b752cb7054d8e30d.zip | |
All of the broken legacy things work.
| -rw-r--r-- | CMakeLists.txt | 6 | ||||
| -rw-r--r-- | depends/launcher/net/minecraft/Launcher.java | 15 | ||||
| -rw-r--r-- | depends/launcher/org/multimc/onesix/OneSixLauncher.java | 2 | ||||
| -rw-r--r-- | gui/dialogs/NewInstanceDialog.cpp | 8 | ||||
| -rw-r--r-- | gui/dialogs/NewInstanceDialog.h | 2 | ||||
| -rw-r--r-- | logic/OneSixInstance.cpp | 5 | ||||
| -rw-r--r-- | logic/OneSixUpdate.cpp | 12 | ||||
| -rw-r--r-- | logic/minecraft/MinecraftVersion.cpp | 93 | ||||
| -rw-r--r-- | logic/minecraft/MinecraftVersion.h | 102 | ||||
| -rw-r--r-- | logic/minecraft/MinecraftVersionList.cpp | 167 | ||||
| -rw-r--r-- | logic/minecraft/ParseUtils.cpp | 23 | ||||
| -rw-r--r-- | logic/minecraft/ParseUtils.h | 14 | ||||
| -rw-r--r-- | logic/minecraft/VersionBuildError.h | 58 | ||||
| -rw-r--r-- | logic/minecraft/VersionBuilder.cpp | 220 | ||||
| -rw-r--r-- | logic/minecraft/VersionBuilder.h | 13 | ||||
| -rw-r--r-- | logic/minecraft/VersionFile.cpp | 69 | ||||
| -rw-r--r-- | logic/minecraft/VersionFile.h | 83 | ||||
| -rw-r--r-- | logic/minecraft/VersionFinal.cpp | 99 | ||||
| -rw-r--r-- | logic/minecraft/VersionFinal.h | 20 | ||||
| -rw-r--r-- | logic/minecraft/VersionPatch.h | 16 | ||||
| -rw-r--r-- | resources/versions/minecraft.json | 12 |
21 files changed, 692 insertions, 347 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 84eb7665..0be887dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -479,6 +479,8 @@ SET(MULTIMC_SOURCES logic/minecraft/OneSixRule.h logic/minecraft/OpSys.cpp logic/minecraft/OpSys.h + logic/minecraft/ParseUtils.cpp + logic/minecraft/ParseUtils.h logic/minecraft/RawLibrary.cpp logic/minecraft/RawLibrary.h logic/minecraft/VersionBuilder.cpp @@ -489,10 +491,6 @@ SET(MULTIMC_SOURCES logic/minecraft/VersionFinal.h logic/minecraft/VersionPatch.h - # Trivial operating system utilities - logic/minecraft/OpSys.h - logic/minecraft/OpSys.cpp - # Various base classes logic/BaseInstaller.h logic/BaseInstaller.cpp diff --git a/depends/launcher/net/minecraft/Launcher.java b/depends/launcher/net/minecraft/Launcher.java index c9b137e1..a53501ec 100644 --- a/depends/launcher/net/minecraft/Launcher.java +++ b/depends/launcher/net/minecraft/Launcher.java @@ -24,6 +24,7 @@ import java.awt.BorderLayout; import java.awt.Graphics; import java.applet.Applet; import java.applet.AppletStub; +import java.net.MalformedURLException; public class Launcher extends Applet implements AppletStub { @@ -130,13 +131,23 @@ public class Launcher extends Applet implements AppletStub @Override public URL getCodeBase() { - return wrappedApplet.getCodeBase(); + try { + return new URL("http://www.minecraft.net/game/"); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + return null; } @Override public URL getDocumentBase() { - return documentBase; + try { + return new URL("http://www.minecraft.net/game/"); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + return null; } @Override diff --git a/depends/launcher/org/multimc/onesix/OneSixLauncher.java b/depends/launcher/org/multimc/onesix/OneSixLauncher.java index 4a0c9589..7bf71b3d 100644 --- a/depends/launcher/org/multimc/onesix/OneSixLauncher.java +++ b/depends/launcher/org/multimc/onesix/OneSixLauncher.java @@ -53,7 +53,7 @@ public class OneSixLauncher implements Launcher { libraries = params.all("cp"); extlibs = params.all("ext"); - mcparams = params.all("param"); + mcparams = params.allSafe("param", new ArrayList<String>() ); mainClass = params.firstSafe("mainClass", "net.minecraft.client.Minecraft"); appletClass = params.firstSafe("appletClass", "net.minecraft.client.MinecraftApplet"); mods = params.allSafe("mods", new ArrayList<String>()); diff --git a/gui/dialogs/NewInstanceDialog.cpp b/gui/dialogs/NewInstanceDialog.cpp index 3192a1cd..41ae329c 100644 --- a/gui/dialogs/NewInstanceDialog.cpp +++ b/gui/dialogs/NewInstanceDialog.cpp @@ -47,7 +47,7 @@ NewInstanceDialog::NewInstanceDialog(QWidget *parent) taskDlg->exec(loadTask); } */ - setSelectedVersion(MMC->minecraftlist()->getLatestStable()); + setSelectedVersion(MMC->minecraftlist()->getLatestStable(), true); InstIconKey = "infinity"; ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey)); } @@ -63,13 +63,17 @@ void NewInstanceDialog::updateDialogState() ->setEnabled(!instName().isEmpty() && m_selectedVersion); } -void NewInstanceDialog::setSelectedVersion(BaseVersionPtr version) +void NewInstanceDialog::setSelectedVersion(BaseVersionPtr version, bool initial) { m_selectedVersion = version; if (m_selectedVersion) { ui->versionTextBox->setText(version->name()); + if(ui->instNameTextBox->text().isEmpty() && !initial) + { + ui->instNameTextBox->setText(version->name()); + } } else { diff --git a/gui/dialogs/NewInstanceDialog.h b/gui/dialogs/NewInstanceDialog.h index 4357c28d..17045ec0 100644 --- a/gui/dialogs/NewInstanceDialog.h +++ b/gui/dialogs/NewInstanceDialog.h @@ -33,7 +33,7 @@ public: void updateDialogState(); - void setSelectedVersion(BaseVersionPtr version); + void setSelectedVersion(BaseVersionPtr version, bool initial = false); void loadVersionList(); diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp index 2c67f7a9..574dfc69 100644 --- a/logic/OneSixInstance.cpp +++ b/logic/OneSixInstance.cpp @@ -224,7 +224,10 @@ bool OneSixInstance::prepareForLaunch(AuthSessionPtr account, QString &launchScr } launchScript += "cp " + versionsPath().absoluteFilePath(minecraftjarpath) + "\n"; } - launchScript += "mainClass " + version->mainClass + "\n"; + if(!version->mainClass.isEmpty()) + { + launchScript += "mainClass " + version->mainClass + "\n"; + } if(!version->appletClass.isEmpty()) { launchScript += "appletClass " + version->appletClass + "\n"; diff --git a/logic/OneSixUpdate.cpp b/logic/OneSixUpdate.cpp index beb293ff..f77913dc 100644 --- a/logic/OneSixUpdate.cpp +++ b/logic/OneSixUpdate.cpp @@ -62,12 +62,14 @@ void OneSixUpdate::executeTask() emitFailed(tr("The specified Minecraft version is invalid. Choose a different one.")); return; } - versionFileStart(); - } - else - { - jarlibStart(); + // builtins need no updates, so only update for Mojang + if(targetVersion->m_versionSource == MinecraftVersion::Mojang) + { + versionFileStart(); + return; + } } + jarlibStart(); } void OneSixUpdate::versionFileStart() diff --git a/logic/minecraft/MinecraftVersion.cpp b/logic/minecraft/MinecraftVersion.cpp index a2e5a50a..2191e8af 100644 --- a/logic/minecraft/MinecraftVersion.cpp +++ b/logic/minecraft/MinecraftVersion.cpp @@ -1,2 +1,95 @@ #include "MinecraftVersion.h" +#include "VersionFinal.h" +bool MinecraftVersion::usesLegacyLauncher() +{ + return m_traits.contains("legacyLaunch") || m_traits.contains("aplhaLaunch"); +} +QString MinecraftVersion::descriptor() +{ + return m_descriptor; +} +QString MinecraftVersion::name() +{ + return m_name; +} +QString MinecraftVersion::typeString() const +{ + if (is_latest && is_snapshot) + { + return QObject::tr("Latest snapshot"); + } + else if (is_latest) + { + return QObject::tr("Latest release"); + } + else if (is_snapshot) + { + return QObject::tr("Snapshot"); + } + else + { + return QObject::tr("Regular release"); + } +} +bool MinecraftVersion::hasJarMods() +{ + return false; +} +bool MinecraftVersion::isVanilla() +{ + return true; +} + +void MinecraftVersion::applyTo(VersionFinal *version) +{ + // FIXME: make this work. + if(m_versionSource != Builtin) + { + return; + } + if (!m_descriptor.isNull()) + { + version->id = m_descriptor; + } + if (!m_mainClass.isNull()) + { + version->mainClass = m_mainClass; + } + if (!m_appletClass.isNull()) + { + version->appletClass = m_appletClass; + } + if (!m_processArguments.isNull()) + { + version->vanillaProcessArguments = m_processArguments; + version->processArguments = m_processArguments; + } + if (!m_type.isNull()) + { + version->type = m_type; + } + if (!m_releaseTimeString.isNull()) + { + version->m_releaseTimeString = m_releaseTimeString; + version->m_releaseTime = m_releaseTime; + } + if (!m_updateTimeString.isNull()) + { + version->m_updateTimeString = m_updateTimeString; + version->m_updateTime = m_updateTime; + } + version->traits.unite(m_traits); +} +int MinecraftVersion::getOrder() +{ + return order; +} +void MinecraftVersion::setOrder(int order) +{ + this->order = order; +} +QList<JarmodPtr> MinecraftVersion::getJarMods() +{ + return QList<JarmodPtr>(); +} diff --git a/logic/minecraft/MinecraftVersion.h b/logic/minecraft/MinecraftVersion.h index dab08bb1..6a1c54cb 100644 --- a/logic/minecraft/MinecraftVersion.h +++ b/logic/minecraft/MinecraftVersion.h @@ -15,16 +15,18 @@ #pragma once -#include "logic/BaseVersion.h" -#include "VersionPatch.h" #include <QStringList> #include <QSet> +#include <QDateTime> + +#include "logic/BaseVersion.h" +#include "VersionPatch.h" +#include "VersionFile.h" + +class VersionFinal; struct MinecraftVersion : public BaseVersion, public VersionPatch { - /// The version's timestamp - this is primarily used for sorting versions in a list. - qint64 timestamp; - /// The URL that this version will be downloaded from. maybe. QString download_url; @@ -34,16 +36,20 @@ struct MinecraftVersion : public BaseVersion, public VersionPatch /// is this a snapshot? bool is_snapshot = false; - /// is this a built-in version that comes with MultiMC? - bool is_builtin = false; - + /// where is this from? + enum VersionSource + { + Builtin, + Mojang + } m_versionSource = Builtin; + /// the human readable version name QString m_name; /// the version ID. QString m_descriptor; - /// version traits. generally launcher business... + /// version traits. added by MultiMC QSet<QString> m_traits; /// The main class this version uses (if any, can be empty). @@ -52,57 +58,47 @@ struct MinecraftVersion : public BaseVersion, public VersionPatch /// The applet class this version uses (if any, can be empty). QString m_appletClass; - bool usesLegacyLauncher() - { - return m_traits.contains("legacyLaunch") || m_traits.contains("aplhaLaunch"); - } - - virtual QString descriptor() override - { - return m_descriptor; - } + /// The process arguments used by this version + QString m_processArguments; - virtual QString name() override - { - return m_name; - } + /// The type of this release + QString m_type; - virtual QString typeString() const override + /// the time this version was actually released by Mojang, as string and as QDateTime + QString m_releaseTimeString; + QDateTime m_releaseTime; + + /// the time this version was last updated by Mojang, as string and as QDateTime + QString m_updateTimeString; + QDateTime m_updateTime; + + /// order of this file... default = -2 + int order = -2; + + bool usesLegacyLauncher(); + virtual QString descriptor() override; + virtual QString name() override; + virtual QString typeString() const override; + virtual bool hasJarMods() override; + virtual bool isVanilla() override; + virtual void applyTo(VersionFinal *version) override; + virtual int getOrder(); + virtual void setOrder(int order); + virtual QList<JarmodPtr> getJarMods() override; + virtual QString getPatchID() { - if (is_latest && is_snapshot) - { - return QObject::tr("Latest snapshot"); - } - else if(is_latest) - { - return QObject::tr("Latest release"); - } - else if(is_snapshot) - { - return QObject::tr("Snapshot"); - } - else if(is_builtin) - { - return QObject::tr("Museum piece"); - } - else - { - return QObject::tr("Regular release"); - } + return "net.minecraft"; } - - virtual bool hasJarMods() override + virtual QString getPatchVersion() { - return false; + return m_descriptor; } - - virtual bool isVanilla() override + virtual QString getPatchName() { - return true; + return "Minecraft"; } - - virtual void applyTo(VersionFinal *version) + virtual QString getPatchFilename() { - // umm... what now? - } + return QString(); + }; }; diff --git a/logic/minecraft/MinecraftVersionList.cpp b/logic/minecraft/MinecraftVersionList.cpp index cdf5fa77..1aa220e8 100644 --- a/logic/minecraft/MinecraftVersionList.cpp +++ b/logic/minecraft/MinecraftVersionList.cpp @@ -16,7 +16,8 @@ #include "MinecraftVersionList.h" #include "MultiMC.h" #include "logic/net/URLConstants.h" -#include <logic/MMCJson.h> +#include "logic/MMCJson.h" +#include "ParseUtils.h" #include <QtXml> @@ -30,11 +31,6 @@ #include <QtNetwork> -inline QDateTime timeFromS3Time(QString str) -{ - return QDateTime::fromString(str, Qt::ISODate); -} - MinecraftVersionList::MinecraftVersionList(QObject *parent) : BaseVersionList(parent) { loadBuiltinList(); @@ -64,7 +60,7 @@ static bool cmpVersions(BaseVersionPtr first, BaseVersionPtr second) { auto left = std::dynamic_pointer_cast<MinecraftVersion>(first); auto right = std::dynamic_pointer_cast<MinecraftVersion>(second); - return left->timestamp > right->timestamp; + return left->m_releaseTime > right->m_releaseTime; } void MinecraftVersionList::sortInternal() @@ -79,55 +75,55 @@ void MinecraftVersionList::loadBuiltinList() QFile filez(versionList.absoluteFilePath()); filez.open(QIODevice::ReadOnly); auto data = filez.readAll(); - + // parse the data as json QJsonParseError jsonError; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); QJsonObject root = jsonDoc.object(); - + // parse all the versions for (const auto version : MMCJson::ensureArray(root.value("versions"))) { QJsonObject versionObj = version.toObject(); QString versionID = versionObj.value("id").toString(""); - QString versionTimeStr = versionObj.value("releaseTime").toString(""); QString versionTypeStr = versionObj.value("type").toString(""); - QSet<QString> traits; - if (versionObj.contains("+traits")) + if (versionID.isEmpty() || versionTypeStr.isEmpty()) { - for (auto traitVal : MMCJson::ensureArray(versionObj.value("+traits"))) - { - traits.insert(MMCJson::ensureString(traitVal)); - } - } - if (versionID.isEmpty() || versionTimeStr.isEmpty() || versionTypeStr.isEmpty()) - { - // FIXME: log this somewhere + QLOG_ERROR() << "Parsed version is missing ID or type"; continue; } + + // Now, we construct the version object and add it to the list. + std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion()); + mcVersion->m_name = mcVersion->m_descriptor = versionID; + // Parse the timestamp. - QDateTime versionTime = timeFromS3Time(versionTimeStr); - if (!versionTime.isValid()) + try + { + parse_timestamp(versionObj.value("releaseTime").toString(""), + mcVersion->m_releaseTimeString, mcVersion->m_releaseTime); + } + catch (MMCError &e) { - // FIXME: log this somewhere + QLOG_ERROR() << "Error while parsing version" << versionID << ":" << e.cause(); continue; } - // Get the download URL. - QString dlUrl = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/"; - // main class and applet class - QString mainClass = versionObj.value("type").toString(""); - QString appletClass = versionObj.value("type").toString(""); + // Get the download URL. + mcVersion->download_url = + "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/"; - // Now, we construct the version object and add it to the list. - std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion()); - mcVersion->m_name = mcVersion->m_descriptor = versionID; - mcVersion->timestamp = versionTime.toMSecsSinceEpoch(); - mcVersion->download_url = dlUrl; - mcVersion->is_builtin = true; - mcVersion->m_appletClass = appletClass; - mcVersion->m_mainClass = mainClass; - mcVersion->m_traits = traits; + mcVersion->m_versionSource = MinecraftVersion::Builtin; + mcVersion->m_appletClass = versionObj.value("appletClass").toString(""); + mcVersion->m_mainClass = versionObj.value("mainClass").toString(""); + mcVersion->m_processArguments = versionObj.value("processArguments").toString("legacy"); + if (versionObj.contains("+traits")) + { + for (auto traitVal : MMCJson::ensureArray(versionObj.value("+traits"))) + { + mcVersion->m_traits.insert(MMCJson::ensureString(traitVal)); + } + } m_vlist.append(mcVersion); } } @@ -265,62 +261,77 @@ void MCVListLoadTask::list_downloaded() // Load the version info. if (!version.isObject()) { - // FIXME: log this somewhere + QLOG_ERROR() << "Error while parsing version list : invalid JSON structure"; continue; } QJsonObject versionObj = version.toObject(); QString versionID = versionObj.value("id").toString(""); - QString versionTimeStr = versionObj.value("releaseTime").toString(""); - QString versionTypeStr = versionObj.value("type").toString(""); - if (versionID.isEmpty() || versionTimeStr.isEmpty() || versionTypeStr.isEmpty()) + if (versionID.isEmpty()) { - // FIXME: log this somewhere + QLOG_ERROR() << "Error while parsing version : version ID is missing"; continue; } + // Get the download URL. + QString dlUrl = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/"; - // Parse the timestamp. - QDateTime versionTime = timeFromS3Time(versionTimeStr); - if (!versionTime.isValid()) - { - // FIXME: log this somewhere - continue; - } - // OneSix or Legacy. use filter to determine type - if (versionTypeStr == "release") - { - is_latest = (versionID == latestReleaseID); - is_snapshot = false; - } - else if (versionTypeStr == "snapshot") // It's a snapshot... yay - { - is_latest = (versionID == latestSnapshotID); - is_snapshot = true; - } - else if (versionTypeStr == "old_alpha") - { - is_latest = false; - is_snapshot = false; - } - else if (versionTypeStr == "old_beta") + // Now, we construct the version object and add it to the list. + std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion()); + mcVersion->m_name = mcVersion->m_descriptor = versionID; + + try { - is_latest = false; - is_snapshot = false; + // Parse the timestamps. + parse_timestamp(versionObj.value("releaseTime").toString(""), + mcVersion->m_releaseTimeString, mcVersion->m_releaseTime); + + parse_timestamp(versionObj.value("time").toString(""), + mcVersion->m_updateTimeString, mcVersion->m_updateTime); } - else + catch (MMCError &e) { - // FIXME: log this somewhere + QLOG_ERROR() << "Error while parsing version" << versionID << ":" << e.cause(); continue; } - // Get the download URL. - QString dlUrl = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/"; - // Now, we construct the version object and add it to the list. - std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion()); - mcVersion->m_name = mcVersion->m_descriptor = versionID; - mcVersion->timestamp = versionTime.toMSecsSinceEpoch(); + mcVersion->m_versionSource = MinecraftVersion::Builtin; mcVersion->download_url = dlUrl; - mcVersion->is_latest = is_latest; - mcVersion->is_snapshot = is_snapshot; + { + QString versionTypeStr = versionObj.value("type").toString(""); + if (versionTypeStr.isEmpty()) + { + // FIXME: log this somewhere + continue; + } + // OneSix or Legacy. use filter to determine type + if (versionTypeStr == "release") + { + is_latest = (versionID == latestReleaseID); + is_snapshot = false; + } + else if (versionTypeStr == "snapshot") // It's a snapshot... yay + { + is_latest = (versionID == latestSnapshotID); + is_snapshot = true; + } + else if (versionTypeStr == "old_alpha") + { + is_latest = false; + is_snapshot = false; + } + else if (versionTypeStr == "old_beta") + { + is_latest = false; + is_snapshot = false; + } + else + { + // FIXME: log this somewhere + continue; + } + mcVersion->m_type = versionTypeStr; + mcVersion->is_latest = is_latest; + mcVersion->is_snapshot = is_snapshot; + } tempList.append(mcVersion); } m_list->updateListData(tempList); diff --git a/logic/minecraft/ParseUtils.cpp b/logic/minecraft/ParseUtils.cpp new file mode 100644 index 00000000..67460ca4 --- /dev/null +++ b/logic/minecraft/ParseUtils.cpp @@ -0,0 +1,23 @@ +#include <QDateTime> +#include <QString> +#include "ParseUtils.h" +#include <logic/MMCJson.h> + +QDateTime timeFromS3Time(QString str) +{ + return QDateTime::fromString(str, Qt::ISODate); +} + +void parse_timestamp (const QString & raw, QString & save_here, QDateTime & parse_here) +{ + save_here = raw; + if (save_here.isEmpty()) + { + throw JSONValidationError("The timestamp is empty!"); + } + parse_here = timeFromS3Time(save_here); + if (!parse_here.isValid()) + { + throw JSONValidationError("The timestamp not a valid timestamp!"); + } +} diff --git a/logic/minecraft/ParseUtils.h b/logic/minecraft/ParseUtils.h new file mode 100644 index 00000000..73cf526a --- /dev/null +++ b/logic/minecraft/ParseUtils.h @@ -0,0 +1,14 @@ +#pragma once +#include <QString> +#include <QDateTime> + +/** + * parse the S3 timestamp in 'raw' and fill the forwarded variables. + * return true/false for success/failure + */ +void parse_timestamp (const QString &raw, QString &save_here, QDateTime &parse_here); + +/** + * take the timestamp used by S3 and turn it into QDateTime + */ +QDateTime timeFromS3Time(QString str); diff --git a/logic/minecraft/VersionBuildError.h b/logic/minecraft/VersionBuildError.h new file mode 100644 index 00000000..ae479851 --- /dev/null +++ b/logic/minecraft/VersionBuildError.h @@ -0,0 +1,58 @@ +#include "MMCError.h" + +class VersionBuildError : public MMCError +{ +public: + VersionBuildError(QString cause) : MMCError(cause) {}; + virtual ~VersionBuildError() noexcept + { + } +}; + +/** + * the base version file was meant for a newer version of the vanilla launcher than we support + */ +class LauncherVersionError : public VersionBuildError +{ +public: + LauncherVersionError(int actual, int supported) + : VersionBuildError(QObject::tr( + "The base version file of this instance was meant for a newer (%1) " + "version of the vanilla launcher than this version of MultiMC supports (%2).") + .arg(actual) + .arg(supported)) {}; + virtual ~LauncherVersionError() noexcept + { + } +}; + +/** + * some patch was intended for a different version of minecraft + */ +class MinecraftVersionMismatch : public VersionBuildError +{ +public: + MinecraftVersionMismatch(QString fileId, QString mcVersion, QString parentMcVersion) + : VersionBuildError(QObject::tr("The patch %1 is for a different version of Minecraft " + "(%2) than that of the instance (%3).") + .arg(fileId) + .arg(mcVersion) + .arg(parentMcVersion)) {}; + virtual ~MinecraftVersionMismatch() noexcept + { + } +}; + +/** + * files required for the version are not (yet?) present + */ +class VersionIncomplete : public VersionBuildError +{ +public: + VersionIncomplete(QString missingPatch) + : VersionBuildError(QObject::tr("Version is incomplete: missing %1.") + .arg(missingPatch)) {}; + virtual ~VersionIncomplete() noexcept + { + } +};
\ No newline at end of file diff --git a/logic/minecraft/VersionBuilder.cpp b/logic/minecraft/VersionBuilder.cpp index 56eef424..d19c2877 100644 --- a/logic/minecraft/VersionBuilder.cpp +++ b/logic/minecraft/VersionBuilder.cpp @@ -23,12 +23,17 @@ #include <QObject> #include <QDir> #include <QDebug> +#include <qresource.h> #include <modutils.h> +#include "MultiMC.h" #include "logic/minecraft/VersionBuilder.h" #include "logic/minecraft/VersionFinal.h" #include "logic/minecraft/OneSixRule.h" +#include "logic/minecraft/VersionPatch.h" #include "logic/minecraft/VersionFile.h" +#include "VersionBuildError.h" +#include "MinecraftVersionList.h" #include "logic/OneSixInstance.h" #include "logic/MMCJson.h" @@ -39,16 +44,17 @@ VersionBuilder::VersionBuilder() { } -void VersionBuilder::build(VersionFinal *version, OneSixInstance *instance, const QStringList &external) +void VersionBuilder::build(VersionFinal *version, OneSixInstance *instance, + const QStringList &external) { VersionBuilder builder; builder.m_version = version; builder.m_instance = instance; - builder.buildInternal(external); + builder.external_patches = external; + builder.buildInternal(); } -void VersionBuilder::readJsonAndApplyToVersion(VersionFinal *version, - const QJsonObject &obj) +void VersionBuilder::readJsonAndApplyToVersion(VersionFinal *version, const QJsonObject &obj) { VersionBuilder builder; builder.m_version = version; @@ -56,88 +62,143 @@ void VersionBuilder::readJsonAndApplyToVersion(VersionFinal *version, builder.readJsonAndApply(obj); } -void VersionBuilder::buildInternal(const QStringList &external) +void VersionBuilder::buildFromCustomJson() { - m_version->versionFiles.clear(); + QLOG_INFO() << "Building version from custom.json within the instance."; + QLOG_INFO() << "Reading custom.json"; + auto file = parseJsonFile(QFileInfo(instance_root.absoluteFilePath("custom.json")), false); + file->name = "custom.json"; + file->filename = "custom.json"; + file->fileId = "org.multimc.custom.json"; + file->order = -1; + file->version = QString(); + m_version->VersionPatches.append(file); + // QObject::tr("The version descriptors of this instance are not compatible with the + // current version of MultiMC")); + // QObject::tr("Error while applying %1. Please check MultiMC-0.log for more info.") + // some final touches + m_version->finalize(); + return; +} - QDir root(m_instance->instanceRoot()); - QDir patches(root.absoluteFilePath("patches/")); +void VersionBuilder::buildFromVersionJson() +{ + QLOG_INFO() << "Building version from version.json and patches within the instance."; + QLOG_INFO() << "Reading version.json"; + auto file = parseJsonFile(QFileInfo(instance_root.absoluteFilePath("version.json")), false); + file->name = "Minecraft"; + file->fileId = "org.multimc.version.json"; + file->order = -1; + file->version = m_instance->intendedVersionId(); + file->mcVersion = m_instance->intendedVersionId(); + m_version->VersionPatches.append(file); - // if we do external files, do just those. - if (!external.isEmpty()) + // load all patches, put into map for ordering, apply in the right order + readInstancePatches(); + + // some final touches + m_version->finalize(); +} + +void VersionBuilder::readInstancePatches() +{ + QDir patches(instance_root.absoluteFilePath("patches/")); + QMap<int, QPair<QString, VersionFilePtr>> files; + for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files)) { - int externalOrder = -1; - for (auto fileName : external) + QLOG_INFO() << "Reading" << info.fileName(); + auto file = parseJsonFile(info, true); + if(file->fileId == "net.minecraft") + continue; + if(file->fileId == "org.lwjgl") + continue; + if (files.contains(file->order)) { - QLOG_INFO() << "Reading" << fileName; - auto file = - parseJsonFile(QFileInfo(fileName), false, fileName.endsWith("pack.json")); - file->name = QFileInfo(fileName).fileName(); - file->fileId = "org.multimc.external." + file->name; - file->order = (externalOrder += 1); - file->version = QString(); - file->mcVersion = QString(); - m_version->versionFiles.append(file); + throw VersionBuildError(QObject::tr("%1 has the same order as %2") + .arg(file->fileId, files[file->order].second->fileId)); } + files.insert(file->order, qMakePair(info.fileName(), file)); } - // else, if there's custom json, we just do that. - else if (QFile::exists(root.absoluteFilePath("custom.json"))) - { - QLOG_INFO() << "Reading custom.json"; - auto file = parseJsonFile(QFileInfo(root.absoluteFilePath("custom.json")), false); - file->name = "custom.json"; - file->filename = "custom.json"; - file->fileId = "org.multimc.custom.json"; - file->order = -1; - file->version = QString(); - m_version->versionFiles.append(file); - // QObject::tr("The version descriptors of this instance are not compatible with the - // current version of MultiMC")); - // QObject::tr("Error while applying %1. Please check MultiMC-0.log for more info.") + for (auto order : files.keys()) + { + auto &filePair = files[order]; + m_version->VersionPatches.append(filePair.second); } - // version.json -> patches/*.json -> user.json - else - do - { - // version.json - QLOG_INFO() << "Reading version.json"; - auto file = parseJsonFile(QFileInfo( |
