Make 1.6+ work with new instance format.
This commit is contained in:
parent
92abe4c603
commit
69c3e7111f
@ -485,11 +485,13 @@ SET(MULTIMC_SOURCES
|
|||||||
logic/minecraft/RawLibrary.h
|
logic/minecraft/RawLibrary.h
|
||||||
logic/minecraft/VersionBuilder.cpp
|
logic/minecraft/VersionBuilder.cpp
|
||||||
logic/minecraft/VersionBuilder.h
|
logic/minecraft/VersionBuilder.h
|
||||||
|
logic/minecraft/VersionBuildError.h
|
||||||
logic/minecraft/VersionFile.cpp
|
logic/minecraft/VersionFile.cpp
|
||||||
logic/minecraft/VersionFile.h
|
logic/minecraft/VersionFile.h
|
||||||
logic/minecraft/VersionFinal.cpp
|
logic/minecraft/VersionFinal.cpp
|
||||||
logic/minecraft/VersionFinal.h
|
logic/minecraft/VersionFinal.h
|
||||||
logic/minecraft/VersionPatch.h
|
logic/minecraft/VersionPatch.h
|
||||||
|
logic/minecraft/VersionSource.h
|
||||||
|
|
||||||
# Various base classes
|
# Various base classes
|
||||||
logic/BaseInstaller.h
|
logic/BaseInstaller.h
|
||||||
|
@ -11,7 +11,7 @@ bool MMCJson::ensureBoolean(const QJsonValue val, const QString what)
|
|||||||
|
|
||||||
QJsonValue MMCJson::ensureExists(QJsonValue val, const QString what)
|
QJsonValue MMCJson::ensureExists(QJsonValue val, const QString what)
|
||||||
{
|
{
|
||||||
if(val.isNull())
|
if(val.isUndefined() || val.isUndefined())
|
||||||
throw JSONValidationError(what + " does not exist");
|
throw JSONValidationError(what + " does not exist");
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@ -59,3 +59,24 @@ QString MMCJson::ensureString(const QJsonValue val, const QString what)
|
|||||||
return val.toString();
|
return val.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MMCJson::writeString(QJsonObject &to, QString key, QString value)
|
||||||
|
{
|
||||||
|
if(value.size())
|
||||||
|
{
|
||||||
|
to.insert(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MMCJson::writeStringList(QJsonObject &to, QString key, QStringList values)
|
||||||
|
{
|
||||||
|
if(values.size())
|
||||||
|
{
|
||||||
|
QJsonArray array;
|
||||||
|
for(auto value: values)
|
||||||
|
{
|
||||||
|
array.append(value);
|
||||||
|
}
|
||||||
|
to.insert(key, array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -43,4 +43,23 @@ int ensureInteger(const QJsonValue val, QString what = "value");
|
|||||||
|
|
||||||
/// make sure the value is converted into a double precision floating number. throw otherwise.
|
/// make sure the value is converted into a double precision floating number. throw otherwise.
|
||||||
double ensureDouble(const QJsonValue val, QString what = "value");
|
double ensureDouble(const QJsonValue val, QString what = "value");
|
||||||
|
|
||||||
|
void writeString(QJsonObject & to, QString key, QString value);
|
||||||
|
|
||||||
|
void writeStringList (QJsonObject & to, QString key, QStringList values);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void writeObjectList (QJsonObject & to, QString key, QList<T> values)
|
||||||
|
{
|
||||||
|
if(values.size())
|
||||||
|
{
|
||||||
|
QJsonArray array;
|
||||||
|
for(auto value: values)
|
||||||
|
{
|
||||||
|
array.append(value->toJson());
|
||||||
|
}
|
||||||
|
to.insert(key, array);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -34,15 +34,12 @@
|
|||||||
#include "logic/net/URLConstants.h"
|
#include "logic/net/URLConstants.h"
|
||||||
#include "logic/assets/AssetsUtils.h"
|
#include "logic/assets/AssetsUtils.h"
|
||||||
|
|
||||||
OneSixUpdate::OneSixUpdate(OneSixInstance *inst, QObject *parent)
|
OneSixUpdate::OneSixUpdate(OneSixInstance *inst, QObject *parent) : Task(parent), m_inst(inst)
|
||||||
: Task(parent), m_inst(inst)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixUpdate::executeTask()
|
void OneSixUpdate::executeTask()
|
||||||
{
|
{
|
||||||
QString intendedVersion = m_inst->intendedVersionId();
|
|
||||||
|
|
||||||
// Make directories
|
// Make directories
|
||||||
QDir mcDir(m_inst->minecraftRoot());
|
QDir mcDir(m_inst->minecraftRoot());
|
||||||
if (!mcDir.exists() && !mcDir.mkpath("."))
|
if (!mcDir.exists() && !mcDir.mkpath("."))
|
||||||
@ -51,97 +48,37 @@ void OneSixUpdate::executeTask()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_inst->shouldUpdate())
|
|
||||||
{
|
|
||||||
// Get a pointer to the version object that corresponds to the instance's version.
|
// Get a pointer to the version object that corresponds to the instance's version.
|
||||||
targetVersion = std::dynamic_pointer_cast<MinecraftVersion>(
|
targetVersion = std::dynamic_pointer_cast<MinecraftVersion>(
|
||||||
MMC->minecraftlist()->findVersion(intendedVersion));
|
MMC->minecraftlist()->findVersion(m_inst->intendedVersionId()));
|
||||||
if (targetVersion == nullptr)
|
if (targetVersion == nullptr)
|
||||||
{
|
{
|
||||||
// don't do anything if it was invalid
|
// don't do anything if it was invalid
|
||||||
emitFailed(tr("The specified Minecraft version is invalid. Choose a different one."));
|
emitFailed(tr("The specified Minecraft version is invalid. Choose a different one."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// builtins need no updates, so only update for Mojang
|
if (m_inst->providesVersionFile() || !targetVersion->needsUpdate())
|
||||||
if(targetVersion->m_versionSource == MinecraftVersion::Mojang)
|
|
||||||
{
|
|
||||||
versionFileStart();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jarlibStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OneSixUpdate::versionFileStart()
|
|
||||||
{
|
|
||||||
if (m_inst->providesVersionFile())
|
|
||||||
{
|
{
|
||||||
jarlibStart();
|
jarlibStart();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QLOG_INFO() << m_inst->name() << ": getting version file.";
|
versionUpdateTask = MMC->minecraftlist()->createUpdateTask(m_inst->intendedVersionId());
|
||||||
setStatus(tr("Getting the version files from Mojang..."));
|
if (!versionUpdateTask)
|
||||||
|
{
|
||||||
QString urlstr = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS +
|
jarlibStart();
|
||||||
targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".json";
|
return;
|
||||||
auto job = new NetJob("Version index");
|
}
|
||||||
job->addNetAction(ByteArrayDownload::make(QUrl(urlstr)));
|
connect(versionUpdateTask.get(), SIGNAL(succeeded()), SLOT(jarlibStart()));
|
||||||
specificVersionDownloadJob.reset(job);
|
connect(versionUpdateTask.get(), SIGNAL(failed(QString)), SLOT(versionUpdateFailed(QString)));
|
||||||
connect(specificVersionDownloadJob.get(), SIGNAL(succeeded()), SLOT(versionFileFinished()));
|
connect(versionUpdateTask.get(), SIGNAL(progress(qint64, qint64)),
|
||||||
connect(specificVersionDownloadJob.get(), SIGNAL(failed()), SLOT(versionFileFailed()));
|
|
||||||
connect(specificVersionDownloadJob.get(), SIGNAL(progress(qint64, qint64)),
|
|
||||||
SIGNAL(progress(qint64, qint64)));
|
SIGNAL(progress(qint64, qint64)));
|
||||||
specificVersionDownloadJob->start();
|
setStatus(tr("Getting the version files from Mojang..."));
|
||||||
|
versionUpdateTask->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixUpdate::versionFileFinished()
|
void OneSixUpdate::versionUpdateFailed(QString reason)
|
||||||
{
|
{
|
||||||
NetActionPtr DlJob = specificVersionDownloadJob->first();
|
emitFailed(reason);
|
||||||
|
|
||||||
QString version_id = targetVersion->descriptor();
|
|
||||||
QString inst_dir = m_inst->instanceRoot();
|
|
||||||
// save the version file in $instanceId/version.json
|
|
||||||
{
|
|
||||||
QString version1 = PathCombine(inst_dir, "/version.json");
|
|
||||||
ensureFilePathExists(version1);
|
|
||||||
// FIXME: detect errors here, download to a temp file, swap
|
|
||||||
QSaveFile vfile1(version1);
|
|
||||||
if (!vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly))
|
|
||||||
{
|
|
||||||
emitFailed(tr("Can't open %1 for writing.").arg(version1));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto data = std::dynamic_pointer_cast<ByteArrayDownload>(DlJob)->m_data;
|
|
||||||
qint64 actual = 0;
|
|
||||||
if ((actual = vfile1.write(data)) != data.size())
|
|
||||||
{
|
|
||||||
emitFailed(tr("Failed to write into %1. Written %2 out of %3.").arg(version1).arg(actual).arg(data.size()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!vfile1.commit())
|
|
||||||
{
|
|
||||||
emitFailed(tr("Can't commit changes to %1").arg(version1));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// the version is downloaded safely. update is 'done' at this point
|
|
||||||
m_inst->setShouldUpdate(false);
|
|
||||||
|
|
||||||
// delete any custom version inside the instance (it's no longer relevant, we did an update)
|
|
||||||
QString custom = PathCombine(inst_dir, "/custom.json");
|
|
||||||
QFile finfo(custom);
|
|
||||||
if (finfo.exists())
|
|
||||||
{
|
|
||||||
finfo.remove();
|
|
||||||
}
|
|
||||||
// NOTE: Version is reloaded in jarlibStart
|
|
||||||
jarlibStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OneSixUpdate::versionFileFailed()
|
|
||||||
{
|
|
||||||
emitFailed(tr("Failed to download the version description. Try again."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixUpdate::assetIndexStart()
|
void OneSixUpdate::assetIndexStart()
|
||||||
@ -236,12 +173,12 @@ void OneSixUpdate::jarlibStart()
|
|||||||
{
|
{
|
||||||
inst->reloadVersion();
|
inst->reloadVersion();
|
||||||
}
|
}
|
||||||
catch(MMCError & e)
|
catch (MMCError &e)
|
||||||
{
|
{
|
||||||
emitFailed(e.cause());
|
emitFailed(e.cause());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch(...)
|
catch (...)
|
||||||
{
|
{
|
||||||
emitFailed(tr("Failed to load the version description file for reasons unknown."));
|
emitFailed(tr("Failed to load the version description file for reasons unknown."));
|
||||||
return;
|
return;
|
||||||
@ -275,7 +212,7 @@ void OneSixUpdate::jarlibStart()
|
|||||||
{
|
{
|
||||||
if (lib->hint() == "local")
|
if (lib->hint() == "local")
|
||||||
{
|
{
|
||||||
if(!lib->filesExist(m_inst->librariesPath()))
|
if (!lib->filesExist(m_inst->librariesPath()))
|
||||||
brokenLocalLibs.append(lib);
|
brokenLocalLibs.append(lib);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -312,16 +249,19 @@ void OneSixUpdate::jarlibStart()
|
|||||||
f(raw_storage, raw_dl);
|
f(raw_storage, raw_dl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!brokenLocalLibs.empty())
|
if (!brokenLocalLibs.empty())
|
||||||
{
|
{
|
||||||
jarlibDownloadJob.reset();
|
jarlibDownloadJob.reset();
|
||||||
QStringList failed;
|
QStringList failed;
|
||||||
for(auto brokenLib : brokenLocalLibs)
|
for (auto brokenLib : brokenLocalLibs)
|
||||||
{
|
{
|
||||||
failed.append(brokenLib->files());
|
failed.append(brokenLib->files());
|
||||||
}
|
}
|
||||||
QString failed_all = failed.join("\n");
|
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));
|
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;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: think about how to propagate this from the original json file... or IF AT ALL
|
// TODO: think about how to propagate this from the original json file... or IF AT ALL
|
||||||
@ -346,9 +286,9 @@ void OneSixUpdate::jarlibFinished()
|
|||||||
std::shared_ptr<VersionFinal> version = inst->getFullVersion();
|
std::shared_ptr<VersionFinal> version = inst->getFullVersion();
|
||||||
|
|
||||||
// create stripped jar, if needed
|
// create stripped jar, if needed
|
||||||
if(version->hasJarMods())
|
if (version->hasJarMods())
|
||||||
{
|
{
|
||||||
//FIXME: good candidate for moving elsewhere (jar location resolving/version caching).
|
// FIXME: good candidate for moving elsewhere (jar location resolving/version caching).
|
||||||
QString version_id = version->id;
|
QString version_id = version->id;
|
||||||
QString localPath = version_id + "/" + version_id + ".jar";
|
QString localPath = version_id + "/" + version_id + ".jar";
|
||||||
QString strippedPath = version_id + "/" + version_id + "-stripped.jar";
|
QString strippedPath = version_id + "/" + version_id + "-stripped.jar";
|
||||||
@ -359,12 +299,12 @@ void OneSixUpdate::jarlibFinished()
|
|||||||
QString fullJarPath = entry->getFullPath();
|
QString fullJarPath = entry->getFullPath();
|
||||||
QString fullStrippedJarPath = entryStripped->getFullPath();
|
QString fullStrippedJarPath = entryStripped->getFullPath();
|
||||||
|
|
||||||
if(entry->md5sum != jarHashOnEntry || !QFileInfo::exists(fullStrippedJarPath))
|
if (entry->md5sum != jarHashOnEntry || !QFileInfo::exists(fullStrippedJarPath))
|
||||||
{
|
{
|
||||||
stripJar(fullJarPath, fullStrippedJarPath);
|
stripJar(fullJarPath, fullStrippedJarPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(version->traits.contains("legacyFML"))
|
if (version->traits.contains("legacyFML"))
|
||||||
{
|
{
|
||||||
fmllibsStart();
|
fmllibsStart();
|
||||||
}
|
}
|
||||||
@ -378,7 +318,8 @@ void OneSixUpdate::jarlibFailed()
|
|||||||
{
|
{
|
||||||
QStringList failed = jarlibDownloadJob->getFailedFiles();
|
QStringList failed = jarlibDownloadJob->getFailedFiles();
|
||||||
QString failed_all = failed.join("\n");
|
QString failed_all = failed.join("\n");
|
||||||
emitFailed(tr("Failed to download the following files:\n%1\n\nPlease try again.").arg(failed_all));
|
emitFailed(
|
||||||
|
tr("Failed to download the following files:\n%1\n\nPlease try again.").arg(failed_all));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixUpdate::stripJar(QString origPath, QString newPath)
|
void OneSixUpdate::stripJar(QString origPath, QString newPath)
|
||||||
@ -462,7 +403,6 @@ bool OneSixUpdate::MergeZipFiles(QuaZip *into, QString from)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void OneSixUpdate::fmllibsStart()
|
void OneSixUpdate::fmllibsStart()
|
||||||
{
|
{
|
||||||
// Get the mod list
|
// Get the mod list
|
||||||
@ -471,7 +411,7 @@ void OneSixUpdate::fmllibsStart()
|
|||||||
bool forge_present = false;
|
bool forge_present = false;
|
||||||
|
|
||||||
QString version = inst->intendedVersionId();
|
QString version = inst->intendedVersionId();
|
||||||
auto & fmlLibsMapping = g_VersionFilterData.fmlLibsMapping;
|
auto &fmlLibsMapping = g_VersionFilterData.fmlLibsMapping;
|
||||||
if (!fmlLibsMapping.contains(version))
|
if (!fmlLibsMapping.contains(version))
|
||||||
{
|
{
|
||||||
assetIndexStart();
|
assetIndexStart();
|
||||||
@ -528,7 +468,7 @@ void OneSixUpdate::fmllibsStart()
|
|||||||
void OneSixUpdate::fmllibsFinished()
|
void OneSixUpdate::fmllibsFinished()
|
||||||
{
|
{
|
||||||
legacyDownloadJob.reset();
|
legacyDownloadJob.reset();
|
||||||
if(!fmlLibsToProcess.isEmpty())
|
if (!fmlLibsToProcess.isEmpty())
|
||||||
{
|
{
|
||||||
setStatus(tr("Copying FML libraries into the instance..."));
|
setStatus(tr("Copying FML libraries into the instance..."));
|
||||||
OneSixInstance *inst = (OneSixInstance *)m_inst;
|
OneSixInstance *inst = (OneSixInstance *)m_inst;
|
||||||
@ -539,7 +479,7 @@ void OneSixUpdate::fmllibsFinished()
|
|||||||
progress(index, fmlLibsToProcess.size());
|
progress(index, fmlLibsToProcess.size());
|
||||||
auto entry = metacache->resolveEntry("fmllibs", lib.filename);
|
auto entry = metacache->resolveEntry("fmllibs", lib.filename);
|
||||||
auto path = PathCombine(inst->libDir(), lib.filename);
|
auto path = PathCombine(inst->libDir(), lib.filename);
|
||||||
if(!ensureFilePathExists(path))
|
if (!ensureFilePathExists(path))
|
||||||
{
|
{
|
||||||
emitFailed(tr("Failed creating FML library folder inside the instance."));
|
emitFailed(tr("Failed creating FML library folder inside the instance."));
|
||||||
return;
|
return;
|
||||||
|
@ -36,9 +36,7 @@ public:
|
|||||||
|
|
||||||
private
|
private
|
||||||
slots:
|
slots:
|
||||||
void versionFileStart();
|
void versionUpdateFailed(QString reason);
|
||||||
void versionFileFinished();
|
|
||||||
void versionFileFailed();
|
|
||||||
|
|
||||||
void jarlibStart();
|
void jarlibStart();
|
||||||
void jarlibFinished();
|
void jarlibFinished();
|
||||||
@ -58,12 +56,14 @@ slots:
|
|||||||
void stripJar(QString origPath, QString newPath);
|
void stripJar(QString origPath, QString newPath);
|
||||||
bool MergeZipFiles(QuaZip *into, QString from);
|
bool MergeZipFiles(QuaZip *into, QString from);
|
||||||
private:
|
private:
|
||||||
NetJobPtr specificVersionDownloadJob;
|
|
||||||
NetJobPtr jarlibDownloadJob;
|
NetJobPtr jarlibDownloadJob;
|
||||||
NetJobPtr legacyDownloadJob;
|
NetJobPtr legacyDownloadJob;
|
||||||
|
|
||||||
// target version, determined during this task
|
/// target version, determined during this task
|
||||||
std::shared_ptr<MinecraftVersion> targetVersion;
|
std::shared_ptr<MinecraftVersion> targetVersion;
|
||||||
|
/// the task that is spawned for version updates
|
||||||
|
std::shared_ptr<Task> versionUpdateTask;
|
||||||
|
|
||||||
OneSixInstance *m_inst = nullptr;
|
OneSixInstance *m_inst = nullptr;
|
||||||
QString jarHashOnEntry;
|
QString jarHashOnEntry;
|
||||||
QList<FMLlib> fmlLibsToProcess;
|
QList<FMLlib> fmlLibsToProcess;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "VersionFilterData.h"
|
#include "VersionFilterData.h"
|
||||||
|
#include "minecraft/ParseUtils.h"
|
||||||
|
|
||||||
extern VersionFilterData g_VersionFilterData = VersionFilterData();
|
extern VersionFilterData g_VersionFilterData = VersionFilterData();
|
||||||
|
|
||||||
@ -57,8 +58,11 @@ VersionFilterData::VersionFilterData()
|
|||||||
|
|
||||||
// don't use installers for those.
|
// don't use installers for those.
|
||||||
forgeInstallerBlacklist = QSet<QString>({"1.5.2"});
|
forgeInstallerBlacklist = QSet<QString>({"1.5.2"});
|
||||||
legacyLaunchWhitelist =
|
// these won't show up in version lists because they are extremely bad and dangerous
|
||||||
QSet<QString>({"1.5.2", "1.5.1", "1.5", "1.4.7", "1.4.6", "1.4.5", "1.4.4", "1.4.3",
|
legacyBlacklist = QSet<QString>({"rd-160052"});
|
||||||
"1.4.2", "1.4.1", "1.4", "1.3.2", "1.3.1", "1.3", "1.2.5", "1.2.4",
|
/*
|
||||||
"1.2.3", "1.2.2", "1.2.1", "1.1", "1.0.1", "1.0"});
|
* nothing older than this will be accepted from Mojang servers
|
||||||
|
* (these versions need to be tested by us first)
|
||||||
|
*/
|
||||||
|
legacyCutoffDate = timeFromS3Time("2013-06-25T15:08:56+02:00");
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
struct FMLlib
|
struct FMLlib
|
||||||
{
|
{
|
||||||
@ -17,7 +18,9 @@ struct VersionFilterData
|
|||||||
QMap<QString, QList<FMLlib>> fmlLibsMapping;
|
QMap<QString, QList<FMLlib>> fmlLibsMapping;
|
||||||
// set of minecraft versions for which using forge installers is blacklisted
|
// set of minecraft versions for which using forge installers is blacklisted
|
||||||
QSet<QString> forgeInstallerBlacklist;
|
QSet<QString> forgeInstallerBlacklist;
|
||||||
// set of 'legacy' versions (ones that use the legacy launch)
|
// set of 'legacy' versions that will not show up in the version lists.
|
||||||
QSet<QString> legacyLaunchWhitelist;
|
QSet<QString> legacyBlacklist;
|
||||||
|
// no new versions below this date will be accepted from Mojang servers
|
||||||
|
QDateTime legacyCutoffDate;
|
||||||
};
|
};
|
||||||
extern VersionFilterData g_VersionFilterData;
|
extern VersionFilterData g_VersionFilterData;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "JarMod.h"
|
#include "JarMod.h"
|
||||||
#include "logic/MMCJson.h"
|
#include "logic/MMCJson.h"
|
||||||
|
using namespace MMCJson;
|
||||||
|
|
||||||
JarmodPtr Jarmod::fromJson(const QJsonObject &libObj, const QString &filename)
|
JarmodPtr Jarmod::fromJson(const QJsonObject &libObj, const QString &filename)
|
||||||
{
|
{
|
||||||
@ -28,6 +29,7 @@ JarmodPtr Jarmod::fromJson(const QJsonObject &libObj, const QString &filename)
|
|||||||
};
|
};
|
||||||
|
|
||||||
readString("url", out->baseurl);
|
readString("url", out->baseurl);
|
||||||
|
readString("MMC-hint", out->hint);
|
||||||
readString("MMC-absoluteUrl", out->absoluteUrl);
|
readString("MMC-absoluteUrl", out->absoluteUrl);
|
||||||
if(!out->baseurl.isEmpty() && out->absoluteUrl.isEmpty())
|
if(!out->baseurl.isEmpty() && out->absoluteUrl.isEmpty())
|
||||||
{
|
{
|
||||||
@ -36,6 +38,16 @@ JarmodPtr Jarmod::fromJson(const QJsonObject &libObj, const QString &filename)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject Jarmod::toJson()
|
||||||
|
{
|
||||||
|
QJsonObject out;
|
||||||
|
writeString(out, "name", name);
|
||||||
|
writeString(out, "url", baseurl);
|
||||||
|
writeString(out, "MMC-absoluteUrl", absoluteUrl);
|
||||||
|
writeString(out, "MMC-hint", hint);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
QString Jarmod::url()
|
QString Jarmod::url()
|
||||||
{
|
{
|
||||||
if(!absoluteUrl.isEmpty())
|
if(!absoluteUrl.isEmpty())
|
||||||
|
@ -8,6 +8,7 @@ class Jarmod
|
|||||||
{
|
{
|
||||||
public: /* methods */
|
public: /* methods */
|
||||||
static JarmodPtr fromJson(const QJsonObject &libObj, const QString &filename);
|
static JarmodPtr fromJson(const QJsonObject &libObj, const QString &filename);
|
||||||
|
QJsonObject toJson();
|
||||||
QString url();
|
QString url();
|
||||||
public: /* data */
|
public: /* data */
|
||||||
QString name;
|
QString name;
|
||||||
|
@ -1,29 +1,26 @@
|
|||||||
#include "MinecraftVersion.h"
|
#include "MinecraftVersion.h"
|
||||||
#include "VersionFinal.h"
|
#include "VersionFinal.h"
|
||||||
|
#include "VersionBuildError.h"
|
||||||
|
#include "VersionBuilder.h"
|
||||||
|
|
||||||
bool MinecraftVersion::usesLegacyLauncher()
|
bool MinecraftVersion::usesLegacyLauncher()
|
||||||
{
|
{
|
||||||
return m_traits.contains("legacyLaunch") || m_traits.contains("aplhaLaunch");
|
return m_traits.contains("legacyLaunch") || m_traits.contains("aplhaLaunch");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MinecraftVersion::descriptor()
|
QString MinecraftVersion::descriptor()
|
||||||
{
|
{
|
||||||
return m_descriptor;
|
return m_descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MinecraftVersion::name()
|
QString MinecraftVersion::name()
|
||||||
{
|
{
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MinecraftVersion::typeString() const
|
QString MinecraftVersion::typeString() const
|
||||||
{
|
{
|
||||||
if (is_latest && is_snapshot)
|
if (is_snapshot)
|
||||||
{
|
|
||||||
return QObject::tr("Latest snapshot");
|
|
||||||
}
|
|
||||||
else if (is_latest)
|
|
||||||
{
|
|
||||||
return QObject::tr("Latest release");
|
|
||||||
}
|
|
||||||
else if (is_snapshot)
|
|
||||||
{
|
{
|
||||||
return QObject::tr("Snapshot");
|
return QObject::tr("Snapshot");
|
||||||
}
|
}
|
||||||
@ -32,22 +29,41 @@ QString MinecraftVersion::typeString() const
|
|||||||
return QObject::tr("Regular release");
|
return QObject::tr("Regular release");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MinecraftVersion::hasJarMods()
|
bool MinecraftVersion::hasJarMods()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool MinecraftVersion::isVanilla()
|
|
||||||
|
bool MinecraftVersion::isMinecraftVersion()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1. assume the local file is good. load, check. If it's good, apply.
|
||||||
|
// 2. if discrepancies are found, fall out and fail (impossible to apply incomplete version).
|
||||||
|
void MinecraftVersion::applyFileTo(VersionFinal *version)
|
||||||
|
{
|
||||||
|
QFileInfo versionFile(QString("versions/%1/%1.json").arg(m_descriptor));
|
||||||
|
|
||||||
|
auto versionObj = VersionBuilder::parseJsonFile(versionFile, false, false);
|
||||||
|
versionObj->applyTo(version);
|
||||||
|
}
|
||||||
|
|
||||||
void MinecraftVersion::applyTo(VersionFinal *version)
|
void MinecraftVersion::applyTo(VersionFinal *version)
|
||||||
{
|
{
|
||||||
// FIXME: make this work.
|
// do we have this one cached?
|
||||||
if(m_versionSource != Builtin)
|
if (m_versionSource == Local)
|
||||||
{
|
{
|
||||||
|
applyFileTo(version);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// if not builtin, do not proceed any further.
|
||||||
|
if (m_versionSource != Builtin)
|
||||||
|
{
|
||||||
|
throw VersionIncomplete(QObject::tr(
|
||||||
|
"Minecraft version %1 could not be applied: version files are missing.").arg(m_descriptor));
|
||||||
|
}
|
||||||
if (!m_descriptor.isNull())
|
if (!m_descriptor.isNull())
|
||||||
{
|
{
|
||||||
version->id = m_descriptor;
|
version->id = m_descriptor;
|
||||||
@ -81,15 +97,35 @@ void MinecraftVersion::applyTo(VersionFinal *version)
|
|||||||
}
|
}
|
||||||
version->traits.unite(m_traits);
|
version->traits.unite(m_traits);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MinecraftVersion::getOrder()
|
int MinecraftVersion::getOrder()
|
||||||
{
|
{
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MinecraftVersion::setOrder(int order)
|
void MinecraftVersion::setOrder(int order)
|
||||||
{
|
{
|
||||||
this->order = order;
|
this->order = order;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<JarmodPtr> MinecraftVersion::getJarMods()
|
QList<JarmodPtr> MinecraftVersion::getJarMods()
|
||||||
{
|
{
|
||||||
return QList<JarmodPtr>();
|
return QList<JarmodPtr>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString MinecraftVersion::getPatchName()
|
||||||
|
{
|
||||||
|
return "Minecraft";
|
||||||
|
}
|
||||||
|
QString MinecraftVersion::getPatchVersion()
|
||||||
|
{
|
||||||
|
return m_descriptor;
|
||||||
|
}
|
||||||
|
QString MinecraftVersion::getPatchID()
|
||||||
|
{
|
||||||
|
return "net.minecraft";
|
||||||
|
}
|
||||||
|
QString MinecraftVersion::getPatchFilename()
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
@ -22,26 +22,49 @@
|
|||||||
#include "logic/BaseVersion.h"
|
#include "logic/BaseVersion.h"
|
||||||
#include "VersionPatch.h"
|
#include "VersionPatch.h"
|
||||||
#include "VersionFile.h"
|
#include "VersionFile.h"
|
||||||
|
#include "VersionSource.h"
|
||||||
|
|
||||||
class VersionFinal;
|
class VersionFinal;
|
||||||
|
class MinecraftVersion;
|
||||||
|
typedef std::shared_ptr<MinecraftVersion> MinecraftVersionPtr;
|
||||||
|
|
||||||
struct MinecraftVersion : public BaseVersion, public VersionPatch
|
class MinecraftVersion : public BaseVersion, public VersionPatch
|
||||||
{
|
{
|
||||||
|
public: /* methods */
|
||||||
|
bool usesLegacyLauncher();
|
||||||
|
virtual QString descriptor() override;
|
||||||
|
virtual QString name() override;
|
||||||
|
virtual QString typeString() const override;
|
||||||
|
virtual bool hasJarMods() override;
|
||||||
|
virtual bool isMinecraftVersion() override;
|
||||||
|
virtual void applyTo(VersionFinal *version) override;
|
||||||
|
virtual int getOrder();
|
||||||
|
virtual void setOrder(int order);
|
||||||
|
virtual QList<JarmodPtr> getJarMods() override;
|
||||||
|
virtual QString getPatchID() override;
|
||||||
|
virtual QString getPatchVersion() override;
|
||||||
|
virtual QString getPatchName() override;
|
||||||
|
virtual QString getPatchFilename() override;
|
||||||
|
bool needsUpdate()
|
||||||
|
{
|
||||||
|
return m_versionSource == Remote;
|
||||||
|
}
|
||||||
|
bool hasUpdate()
|
||||||
|
{
|
||||||
|
return m_versionSource == Remote || (m_versionSource == Local && upstreamUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private: /* methods */
|
||||||
|
void applyFileTo(VersionFinal *version);
|
||||||
|
|
||||||
|
public: /* data */
|
||||||
/// The URL that this version will be downloaded from. maybe.
|
/// The URL that this version will be downloaded from. maybe.
|
||||||
QString download_url;
|
QString download_url;
|
||||||
|
|
||||||
/// is this the latest version?
|
|
||||||
bool is_latest = false;
|
|
||||||
|
|
||||||
/// is this a snapshot?
|
/// is this a snapshot?
|
||||||
bool is_snapshot = false;
|
bool is_snapshot = false;
|
||||||
|
|
||||||
/// where is this from?
|
VersionSource m_versionSource = Builtin;
|
||||||
enum VersionSource
|
|
||||||
{
|
|
||||||
Builtin,
|
|
||||||
Mojang
|
|
||||||
} m_versionSource = Builtin;
|
|
||||||
|
|
||||||
/// the human readable version name
|
/// the human readable version name
|
||||||
QString m_name;
|
QString m_name;
|
||||||
@ -75,30 +98,6 @@ struct MinecraftVersion : public BaseVersion, public VersionPatch
|
|||||||
/// order of this file... default = -2
|
/// order of this file... default = -2
|
||||||
int order = -2;
|
int order = -2;
|
||||||
|
|
||||||
bool usesLegacyLauncher();
|
/// an update available from Mojang
|
||||||
virtual QString descriptor() override;
|
MinecraftVersionPtr upstreamUpdate;
|
||||||
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()
|
|
||||||
{
|
|
||||||
return "net.minecraft";
|
|
||||||
}
|
|
||||||
virtual QString getPatchVersion()
|
|
||||||
{
|
|
||||||
return m_descriptor;
|
|
||||||
}
|
|
||||||
virtual QString getPatchName()
|
|
||||||
{
|
|
||||||
return "Minecraft";
|
|
||||||
}
|
|
||||||
virtual QString getPatchFilename()
|
|
||||||
{
|
|
||||||
return QString();
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
@ -13,27 +13,35 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "MinecraftVersionList.h"
|
|
||||||
#include "MultiMC.h"
|
|
||||||
#include "logic/net/URLConstants.h"
|
|
||||||
#include "logic/MMCJson.h"
|
|
||||||
#include "ParseUtils.h"
|
|
||||||
|
|
||||||
#include <QtXml>
|
#include <QtXml>
|
||||||
|
#include "logic/MMCJson.h"
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonValue>
|
|
||||||
#include <QJsonParseError>
|
|
||||||
|
|
||||||
#include <QtAlgorithms>
|
#include <QtAlgorithms>
|
||||||
|
|
||||||
#include <QtNetwork>
|
#include <QtNetwork>
|
||||||
|
|
||||||
|
#include "MultiMC.h"
|
||||||
|
#include "MMCError.h"
|
||||||
|
|
||||||
|
#include "MinecraftVersionList.h"
|
||||||
|
#include "logic/net/URLConstants.h"
|
||||||
|
|
||||||
|
#include "ParseUtils.h"
|
||||||
|
#include "VersionBuilder.h"
|
||||||
|
#include <logic/VersionFilterData.h>
|
||||||
|
#include <pathutils.h>
|
||||||
|
|
||||||
|
class ListLoadError : public MMCError
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ListLoadError(QString cause) : MMCError(cause) {};
|
||||||
|
virtual ~ListLoadError() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
MinecraftVersionList::MinecraftVersionList(QObject *parent) : BaseVersionList(parent)
|
MinecraftVersionList::MinecraftVersionList(QObject *parent) : BaseVersionList(parent)
|
||||||
{
|
{
|
||||||
loadBuiltinList();
|
loadBuiltinList();
|
||||||
|
loadCachedList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Task *MinecraftVersionList::getLoadTask()
|
Task *MinecraftVersionList::getLoadTask()
|
||||||
@ -68,6 +76,35 @@ void MinecraftVersionList::sortInternal()
|
|||||||
qSort(m_vlist.begin(), m_vlist.end(), cmpVersions);
|
qSort(m_vlist.begin(), m_vlist.end(), cmpVersions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MinecraftVersionList::loadCachedList()
|
||||||
|
{
|
||||||
|
QFile localIndex("versions/versions.json");
|
||||||
|
if (!localIndex.exists())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!localIndex.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
// FIXME: this is actually a very bad thing! How do we deal with this?
|
||||||
|
QLOG_ERROR() << "The minecraft version cache can't be read.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto data = localIndex.readAll();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
loadMojangList(data, Local);
|
||||||
|
}
|
||||||
|
catch (MMCError &e)
|
||||||
|
{
|
||||||
|
// the cache has gone bad for some reason... flush it.
|
||||||
|
QLOG_ERROR() << "The minecraft version cache is corrupted. Flushing cache.";
|
||||||
|
localIndex.close();
|
||||||
|
localIndex.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_hasLocalIndex = true;
|
||||||
|
}
|
||||||
|
|
||||||
void MinecraftVersionList::loadBuiltinList()
|
void MinecraftVersionList::loadBuiltinList()
|
||||||
{
|
{
|
||||||
// grab the version list data from internal resources.
|
// grab the version list data from internal resources.
|
||||||
@ -93,19 +130,22 @@ void MinecraftVersionList::loadBuiltinList()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_VersionFilterData.legacyBlacklist.contains(versionID))
|
||||||
|
{
|
||||||
|
QLOG_ERROR() << "Blacklisted legacy version ignored: " << versionID;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Now, we construct the version object and add it to the list.
|
// Now, we construct the version object and add it to the list.
|
||||||
std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion());
|
std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion());
|
||||||
mcVersion->m_name = mcVersion->m_descriptor = versionID;
|
mcVersion->m_name = mcVersion->m_descriptor = versionID;
|
||||||
|
|
||||||
// Parse the timestamp.
|
// Parse the timestamp.
|
||||||
try
|
if (!parse_timestamp(versionObj.value("releaseTime").toString(""),
|
||||||
|
mcVersion->m_releaseTimeString, mcVersion->m_releaseTime))
|
||||||
{
|
{
|
||||||
parse_timestamp(versionObj.value("releaseTime").toString(""),
|
QLOG_ERROR() << "Error while parsing version" << versionID
|
||||||
mcVersion->m_releaseTimeString, mcVersion->m_releaseTime);
|
<< ": invalid version timestamp";
|
||||||
}
|
|
||||||
catch (MMCError &e)
|
|
||||||
{
|
|
||||||
QLOG_ERROR() << "Error while parsing version" << versionID << ":" << e.cause();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +153,7 @@ void MinecraftVersionList::loadBuiltinList()
|
|||||||
mcVersion->download_url =
|
mcVersion->download_url =
|
||||||
"http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/";
|
"http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/";
|
||||||
|
|
||||||
mcVersion->m_versionSource = MinecraftVersion::Builtin;
|
mcVersion->m_versionSource = Builtin;
|
||||||
mcVersion->m_appletClass = versionObj.value("appletClass").toString("");
|
mcVersion->m_appletClass = versionObj.value("appletClass").toString("");
|
||||||
mcVersion->m_mainClass = versionObj.value("mainClass").toString("");
|
mcVersion->m_mainClass = versionObj.value("mainClass").toString("");
|
||||||
mcVersion->m_processArguments = versionObj.value("processArguments").toString("legacy");
|
mcVersion->m_processArguments = versionObj.value("processArguments").toString("legacy");
|
||||||
@ -124,10 +164,141 @@ void MinecraftVersionList::loadBuiltinList()
|
|||||||
mcVersion->m_traits.insert(MMCJson::ensureString(traitVal));
|
mcVersion->m_traits.insert(MMCJson::ensureString(traitVal));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m_lookup[versionID] = mcVersion;
|
||||||
m_vlist.append(mcVersion);
|
m_vlist.append(mcVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MinecraftVersionList::loadMojangList(QByteArray data, VersionSource source)
|
||||||
|
{
|
||||||
|
QJsonParseError jsonError;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
||||||
|
|
||||||
|
if (jsonError.error != QJsonParseError::NoError)
|
||||||
|
{
|
||||||
|
throw ListLoadError(
|
||||||
|
tr("Error parsing version list JSON: %1").arg(jsonError.errorString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
QLOG_INFO() << ((source == Remote) ? "Remote version list: " : "Local version list:") << data;
|
||||||
|
if (!jsonDoc.isObject())
|
||||||
|
{
|
||||||
|
throw ListLoadError(tr("Error parsing version list JSON: jsonDoc is not an object"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject root = jsonDoc.object();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QJsonObject latest = MMCJson::ensureObject(root.value("latest"));
|
||||||
|
m_latestReleaseID = MMCJson::ensureString(latest.value("release"));
|
||||||
|
m_latestSnapshotID = MMCJson::ensureString(latest.value("snapshot"));
|
||||||
|
}
|
||||||
|
catch (MMCError &err)
|
||||||
|
{
|
||||||
|
QLOG_ERROR()
|
||||||
|
<< tr("Error parsing version list JSON: couldn't determine latest versions");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, get the array of versions.
|
||||||
|
if (!root.value("versions").isArray())
|
||||||
|
{
|
||||||
|
throw ListLoadError(tr("Error parsing version list JSON: version list object is "
|
||||||
|
"missing 'versions' array"));
|
||||||
|
}
|
||||||
|
QJsonArray versions = root.value("versions").toArray();
|
||||||
|
|
||||||
|
QList<BaseVersionPtr> tempList;
|
||||||
|
for (auto version : versions)
|
||||||
|
{
|
||||||
|
bool is_snapshot = false;
|
||||||
|
|
||||||
|
// Load the version info.
|
||||||
|
if (!version.isObject())
|
||||||
|
{
|
||||||
|
QLOG_ERROR() << "Error while parsing version list : invalid JSON structure";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject versionObj = version.toObject();
|
||||||
|
QString versionID = versionObj.value("id").toString("");
|
||||||
|
if (versionID.isEmpty())
|
||||||
|
{
|
||||||
|
QLOG_ERROR() << "Error while parsing version : version ID is missing";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_VersionFilterData.legacyBlacklist.contains(versionID))
|
||||||
|
{
|
||||||
|
QLOG_ERROR() << "Blacklisted legacy version ignored: " << versionID;
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!parse_timestamp(versionObj.value("releaseTime").toString(""),
|
||||||
|
mcVersion->m_releaseTimeString, mcVersion->m_releaseTime))
|
||||||
|
{
|
||||||
|
QLOG_ERROR() << "Error while parsing version" << versionID
|
||||||
|
<< ": invalid release timestamp";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!parse_timestamp(versionObj.value("time").toString(""),
|
||||||
|
mcVersion->m_updateTimeString, mcVersion->m_updateTime))
|
||||||
|
{
|
||||||
|
QLOG_ERROR() << "Error while parsing version" << versionID
|
||||||
|
<< ": invalid update timestamp";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mcVersion->m_releaseTime < g_VersionFilterData.legacyCutoffDate)
|
||||||
|
{
|
||||||
|
QLOG_ERROR() << "Ignoring Mojang version: " << versionID;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// depends on where we load the version from -- network request or local file?
|
||||||
|
mcVersion->m_versionSource = source;
|
||||||
|
|
||||||
|
QString dlUrl = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/";
|
||||||
|
mcVersion->download_url = dlUrl;
|
||||||
|
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_snapshot = false;
|
||||||
|
}
|
||||||
|
else if (versionTypeStr == "snapshot") // It's a snapshot... yay
|
||||||
|
{
|
||||||
|
is_snapshot = true;
|
||||||
|
}
|
||||||
|
else if (versionTypeStr == "old_alpha")
|
||||||
|
{
|
||||||
|
is_snapshot = false;
|
||||||
|
}
|
||||||
|
else if (versionTypeStr == "old_beta")
|
||||||
|
{
|
||||||
|
is_snapshot = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// FIXME: log this somewhere
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mcVersion->m_type = versionTypeStr;
|
||||||
|
mcVersion->is_snapshot = is_snapshot;
|
||||||
|
tempList.append(mcVersion);
|
||||||
|
}
|
||||||
|
updateListData(tempList);
|
||||||
|
}
|
||||||
|
|
||||||
void MinecraftVersionList::sort()
|
void MinecraftVersionList::sort()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
@ -137,14 +308,8 @@ void MinecraftVersionList::sort()
|
|||||||
|
|
||||||
BaseVersionPtr MinecraftVersionList::getLatestStable() const
|
BaseVersionPtr MinecraftVersionList::getLatestStable() const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_vlist.length(); i++)
|
if(m_lookup.contains(m_latestReleaseID))
|
||||||
{
|
return m_lookup[m_latestReleaseID];
|
||||||
auto ver = std::dynamic_pointer_cast<MinecraftVersion>(m_vlist.at(i));
|
|
||||||
if (ver->is_latest && !ver->is_snapshot)
|
|
||||||
{
|
|
||||||
return m_vlist.at(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return BaseVersionPtr();
|
return BaseVersionPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,17 +319,29 @@ void MinecraftVersionList::updateListData(QList<BaseVersionPtr> versions)
|
|||||||
for (auto version : versions)
|
for (auto version : versions)
|
||||||
{
|
{
|
||||||
auto descr = version->descriptor();
|
auto descr = version->descriptor();
|
||||||
for (auto builtin_v : m_vlist)
|
|
||||||
|
if (!m_lookup.contains(descr))
|
||||||
{
|
{
|
||||||
if (descr == builtin_v->descriptor())
|
|
||||||
{
|
|
||||||
goto SKIP_THIS_ONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_vlist.append(version);
|
m_vlist.append(version);
|
||||||
SKIP_THIS_ONE:
|
continue;
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
auto orig = std::dynamic_pointer_cast<MinecraftVersion>(m_lookup[descr]);
|
||||||
|
auto added = std::dynamic_pointer_cast<MinecraftVersion>(version);
|
||||||
|
// updateListData is called after Mojang list loads. those can be local or remote
|
||||||
|
// remote comes always after local
|
||||||
|
// any other options are ignored
|
||||||
|
if (orig->m_versionSource != Local || added->m_versionSource != Remote)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// is it actually an update?
|
||||||
|
if (orig->m_updateTime >= added->m_updateTime)
|
||||||
|
{
|
||||||
|
// nope.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// alright, it's an update. put it inside the original, for further processing.
|
||||||
|
orig->upstreamUpdate = added;
|
||||||
}
|
}
|
||||||
m_loaded = true;
|
m_loaded = true;
|
||||||
sortInternal();
|
sortInternal();
|
||||||
@ -187,10 +364,6 @@ MCVListLoadTask::MCVListLoadTask(MinecraftVersionList *vlist)
|
|||||||
vlistReply = nullptr;
|
vlistReply = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
MCVListLoadTask::~MCVListLoadTask()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void MCVListLoadTask::executeTask()
|
void MCVListLoadTask::executeTask()
|
||||||
{
|
{
|
||||||
setStatus(tr("Loading instance version list..."));
|
setStatus(tr("Loading instance version list..."));
|
||||||
@ -209,133 +382,196 @@ void MCVListLoadTask::list_downloaded()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto foo = vlistReply->readAll();
|
auto data = vlistReply->readAll();
|
||||||
QJsonParseError jsonError;
|
|
||||||
QLOG_INFO() << foo;
|
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(foo, &jsonError);
|
|
||||||
vlistReply->deleteLater();
|
vlistReply->deleteLater();
|
||||||
|
|
||||||
if (jsonError.error != QJsonParseError::NoError)
|
|
||||||
{
|
|
||||||
emitFailed("Error parsing version list JSON:" + jsonError.errorString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!jsonDoc.isObject())
|
|
||||||
{
|
|
||||||
emitFailed("Error parsing version list JSON: jsonDoc is not an object");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject root = jsonDoc.object();
|
|
||||||
|
|
||||||
QString latestReleaseID = "INVALID";
|
|
||||||
QString latestSnapshotID = "INVALID";
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
QJsonObject latest = MMCJson::ensureObject(root.value("latest"));
|
m_list->loadMojangList(data, Remote);
|
||||||
latestReleaseID = MMCJson::ensureString(latest.value("release"));
|
|
||||||
latestSnapshotID = MMCJson::ensureString(latest.value("snapshot"));
|
|
||||||
}
|
|
||||||
catch (MMCError &err)
|
|
||||||
{
|
|
||||||
QLOG_ERROR()
|
|
||||||
<< tr("Error parsing version list JSON: couldn't determine latest versions");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, get the array of versions.
|
|
||||||
if (!root.value("versions").isArray())
|
|
||||||
{
|
|
||||||
emitFailed(
|
|
||||||
"Error parsing version list JSON: version list object is missing 'versions' array");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QJsonArray versions = root.value("versions").toArray();
|
|
||||||
|
|
||||||
QList<BaseVersionPtr> tempList;
|
|
||||||
for (auto version : versions)
|
|
||||||
{
|
|
||||||
bool is_snapshot = false;
|
|
||||||
bool is_latest = false;
|
|
||||||
|
|
||||||
// Load the version info.
|
|
||||||
if (!version.isObject())
|
|
||||||
{
|
|
||||||
QLOG_ERROR() << "Error while parsing version list : invalid JSON structure";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
QJsonObject versionObj = version.toObject();
|
|
||||||
QString versionID = versionObj.value("id").toString("");
|
|
||||||
if (versionID.isEmpty())
|
|
||||||
{
|
|
||||||
QLOG_ERROR() << "Error while parsing version : version ID is missing";
|
|
||||||
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;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
catch (MMCError &e)
|
catch (MMCError &e)
|
||||||
{
|
{
|
||||||
QLOG_ERROR() << "Error while parsing version" << versionID << ":" << e.cause();
|
emitFailed(e.cause());
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mcVersion->m_versionSource = MinecraftVersion::Builtin;
|
|
||||||
mcVersion->download_url = dlUrl;
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MCVListVersionUpdateTask::MCVListVersionUpdateTask(MinecraftVersionList *vlist,
|
||||||
|
QString updatedVersion)
|
||||||
|
: Task()
|
||||||
|
{
|
||||||
|
m_list = vlist;
|
||||||
|
versionToUpdate = updatedVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCVListVersionUpdateTask::executeTask()
|
||||||
|
{
|
||||||
|
QString urlstr = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionToUpdate + "/" +
|
||||||
|
versionToUpdate + ".json";
|
||||||
|
auto job = new NetJob("Version index");
|
||||||
|
job->addNetAction(ByteArrayDownload::make(QUrl(urlstr)));
|
||||||
|
specificVersionDownloadJob.reset(job);
|
||||||
|
connect(specificVersionDownloadJob.get(), SIGNAL(succeeded()), SLOT(json_downloaded()));
|
||||||
|
connect(specificVersionDownloadJob.get(), SIGNAL(failed(QString)), SIGNAL(failed(QString)));
|
||||||
|
connect(specificVersionDownloadJob.get(), SIGNAL(progress(qint64, qint64)),
|
||||||
|
SIGNAL(progress(qint64, qint64)));
|
||||||
|
specificVersionDownloadJob->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCVListVersionUpdateTask::json_downloaded()
|
||||||
|
{
|
||||||
|
NetActionPtr DlJob = specificVersionDownloadJob->first();
|
||||||
|
auto data = std::dynamic_pointer_cast<ByteArrayDownload>(DlJob)->m_data;
|
||||||
|
specificVersionDownloadJob.reset();
|
||||||
|
|
||||||
|
QJsonParseError jsonError;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
||||||
|
|
||||||
|
if (jsonError.error != QJsonParseError::NoError)
|
||||||
|
{
|
||||||
|
emitFailed(tr("The download version file is not valid."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VersionFilePtr file;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file = VersionFile::fromJson(jsonDoc, "net.minecraft.json", false);
|
||||||
|
}
|
||||||
|
catch (MMCError &e)
|
||||||
|
{
|
||||||
|
emitFailed(tr("Couldn't process version file: %1").arg(e.cause()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QList<RawLibraryPtr> filteredLibs;
|
||||||
|
QList<RawLibraryPtr> lwjglLibs;
|
||||||
|
QSet<QString> lwjglFilter = {
|
||||||
|
"net.java.jinput:jinput", "net.java.jinput:jinput-platform",
|
||||||
|
"net.java.jutils:jutils", "org.lwjgl.lwjgl:lwjgl",
|
||||||
|
"org.lwjgl.lwjgl:lwjgl_util", "org.lwjgl.lwjgl:lwjgl-platform"};
|
||||||
|
for (auto lib : file->overwriteLibs)
|
||||||
|
{
|
||||||
|
if (lwjglFilter.contains(lib->fullname()))
|
||||||
|
{
|
||||||
|
lwjglLibs.append(lib);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filteredLibs.append(lib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file->overwriteLibs = filteredLibs;
|
||||||
|
|
||||||
|
// TODO: recognize and add LWJGL versions here.
|
||||||
|
|
||||||
|
file->fileId = "net.minecraft";
|
||||||
|
|
||||||
|
// now dump the file to disk
|
||||||
|
auto doc = file->toJson(false);
|
||||||
|
auto newdata = doc.toJson();
|
||||||
|
QLOG_INFO() << newdata;
|
||||||
|
QString targetPath = "versions/" + versionToUpdate + "/" + versionToUpdate + ".json";
|
||||||
|
ensureFilePathExists(targetPath);
|
||||||
|
QSaveFile vfile1(targetPath);
|
||||||
|
if (!vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly))
|
||||||
|
{
|
||||||
|
emitFailed(tr("Can't open %1 for writing.").arg(targetPath));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qint64 actual = 0;
|
||||||
|
if ((actual = vfile1.write(newdata)) != newdata.size())
|
||||||
|
{
|
||||||
|
emitFailed(tr("Failed to write into %1. Written %2 out of %3.")
|
||||||
|
.arg(targetPath)
|
||||||
|
.arg(actual)
|
||||||
|
.arg(newdata.size()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!vfile1.commit())
|
||||||
|
{
|
||||||
|
emitFailed(tr("Can't commit changes to %1").arg(targetPath));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_list->finalizeUpdate(versionToUpdate);
|
||||||
|
emitSucceeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Task> MinecraftVersionList::createUpdateTask(QString version)
|
||||||
|
{
|
||||||
|
return std::shared_ptr<Task>(new MCVListVersionUpdateTask(this, version));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MinecraftVersionList::saveCachedList()
|
||||||
|
{
|
||||||
|
// FIXME: throw.
|
||||||
|
if (!ensureFilePathExists("versions/versions.json"))
|
||||||
|
return;
|
||||||
|
QSaveFile tfile("versions/versions.json");
|
||||||
|
if (!tfile.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||||
|
return;
|
||||||
|
QJsonObject toplevel;
|
||||||
|
QJsonArray entriesArr;
|
||||||
|
for (auto version : m_vlist)
|
||||||
|
{
|
||||||
|
auto mcversion = std::dynamic_pointer_cast<MinecraftVersion>(version);
|
||||||
|
// do not save the remote versions.
|
||||||
|
if (mcversion->m_versionSource != Local)
|
||||||
|
continue;
|
||||||
|
QJsonObject entryObj;
|
||||||
|
|
||||||
|
entryObj.insert("id", mcversion->descriptor());
|
||||||
|
entryObj.insert("time", mcversion->m_updateTimeString);
|
||||||
|
entryObj.insert("releaseTime", mcversion->m_releaseTimeString);
|
||||||
|
entryObj.insert("type", mcversion->m_type);
|
||||||
|
entriesArr.append(entryObj);
|
||||||
|
}
|
||||||
|
toplevel.insert("versions", entriesArr);
|
||||||
|
QJsonDocument doc(toplevel);
|
||||||
|
QByteArray jsonData = doc.toJson();
|
||||||
|
qint64 result = tfile.write(jsonData);
|
||||||
|
if (result == -1)
|
||||||
|
return;
|
||||||
|
if (result != jsonData.size())
|
||||||
|
return;
|
||||||
|
tfile.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MinecraftVersionList::finalizeUpdate(QString version)
|
||||||
|
{
|
||||||
|
int idx = -1;
|
||||||
|
for (int i = 0; i < m_vlist.size(); i++)
|
||||||
|
{
|
||||||
|
if (version == m_vlist[i]->descriptor())
|
||||||
|
{
|
||||||
|
idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (idx == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto updatedVersion = std::dynamic_pointer_cast<MinecraftVersion>(m_vlist[idx]);
|
||||||
|
|
||||||
|
if (updatedVersion->m_versionSource == Builtin)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (updatedVersion->upstreamUpdate)
|
||||||
|
{
|
||||||
|
auto updatedWith = updatedVersion->upstreamUpdate;
|
||||||
|
updatedWith->m_versionSource = Local;
|
||||||
|
m_vlist[idx] = updatedWith;
|
||||||
|
m_lookup[version] = updatedWith;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updatedVersion->m_versionSource = Local;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataChanged(index(idx), index(idx));
|
||||||
|
|
||||||
|
saveCachedList();
|
||||||
|
}
|
||||||
|
@ -22,8 +22,10 @@
|
|||||||
#include "logic/BaseVersionList.h"
|
#include "logic/BaseVersionList.h"
|
||||||
#include "logic/tasks/Task.h"
|
#include "logic/tasks/Task.h"
|
||||||
#include "logic/minecraft/MinecraftVersion.h"
|
#include "logic/minecraft/MinecraftVersion.h"
|
||||||
|
#include <logic/net/NetJob.h>
|
||||||
|
|
||||||
class MCVListLoadTask;
|
class MCVListLoadTask;
|
||||||
|
class MCVListVersionUpdateTask;
|
||||||
class QNetworkReply;
|
class QNetworkReply;
|
||||||
|
|
||||||
class MinecraftVersionList : public BaseVersionList
|
class MinecraftVersionList : public BaseVersionList
|
||||||
@ -32,11 +34,18 @@ class MinecraftVersionList : public BaseVersionList
|
|||||||
private:
|
private:
|
||||||
void sortInternal();
|
void sortInternal();
|
||||||
void loadBuiltinList();
|
void loadBuiltinList();
|
||||||
|
void loadMojangList(QByteArray data, VersionSource source);
|
||||||
|
void loadCachedList();
|
||||||
|
void saveCachedList();
|
||||||
|
void finalizeUpdate(QString version);
|
||||||
public:
|
public:
|
||||||
friend class MCVListLoadTask;
|
friend class MCVListLoadTask;
|
||||||
|
friend class MCVListVersionUpdateTask;
|
||||||
|
|
||||||
explicit MinecraftVersionList(QObject *parent = 0);
|
explicit MinecraftVersionList(QObject *parent = 0);
|
||||||
|
|
||||||
|
std::shared_ptr<Task> createUpdateTask(QString version);
|
||||||
|
|
||||||
virtual Task *getLoadTask();
|
virtual Task *getLoadTask();
|
||||||
virtual bool isLoaded();
|
virtual bool isLoaded();
|
||||||
virtual const BaseVersionPtr at(int i) const;
|
virtual const BaseVersionPtr at(int i) const;
|
||||||
@ -47,8 +56,12 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
QList<BaseVersionPtr> m_vlist;
|
QList<BaseVersionPtr> m_vlist;
|
||||||
|
QMap<QString, BaseVersionPtr> m_lookup;
|
||||||
|
|
||||||
bool m_loaded = false;
|
bool m_loaded = false;
|
||||||
|
bool m_hasLocalIndex = false;
|
||||||
|
QString m_latestReleaseID = "INVALID";
|
||||||
|
QString m_latestSnapshotID = "INVALID";
|
||||||
|
|
||||||
protected
|
protected
|
||||||
slots:
|
slots:
|
||||||
@ -61,9 +74,9 @@ class MCVListLoadTask : public Task
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MCVListLoadTask(MinecraftVersionList *vlist);
|
explicit MCVListLoadTask(MinecraftVersionList *vlist);
|
||||||
~MCVListLoadTask();
|
virtual ~MCVListLoadTask() override{};
|
||||||
|
|
||||||
virtual void executeTask();
|
virtual void executeTask() override;
|
||||||
|
|
||||||
protected
|
protected
|
||||||
slots:
|
slots:
|
||||||
@ -74,3 +87,22 @@ protected:
|
|||||||
MinecraftVersionList *m_list;
|
MinecraftVersionList *m_list;
|
||||||
MinecraftVersion *m_currentStable;
|
MinecraftVersion *m_currentStable;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MCVListVersionUpdateTask : public Task
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MCVListVersionUpdateTask(MinecraftVersionList *vlist, QString updatedVersion);
|
||||||
|
virtual ~MCVListVersionUpdateTask() override{};
|
||||||
|
virtual void executeTask() override;
|
||||||
|
|
||||||
|
protected
|
||||||
|
slots:
|
||||||
|
void json_downloaded();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
NetJobPtr specificVersionDownloadJob;
|
||||||
|
QString versionToUpdate;
|
||||||
|
MinecraftVersionList *m_list;
|
||||||
|
};
|
||||||
|
@ -23,6 +23,23 @@
|
|||||||
#include <JlCompress.h>
|
#include <JlCompress.h>
|
||||||
#include "logger/QsLog.h"
|
#include "logger/QsLog.h"
|
||||||
|
|
||||||
|
OneSixLibrary::OneSixLibrary(RawLibraryPtr base)
|
||||||
|
{
|
||||||
|
m_name = base->m_name;
|
||||||
|
m_base_url = base->m_base_url;
|
||||||
|
m_hint = base->m_hint;
|
||||||
|
m_absolute_url = base->m_absolute_url;
|
||||||
|
extract_excludes = base->extract_excludes;
|
||||||
|
m_native_suffixes = base->m_native_suffixes;
|
||||||
|
m_rules = base->m_rules;
|
||||||
|
finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
OneSixLibraryPtr OneSixLibrary::fromRawLibrary(RawLibraryPtr lib)
|
||||||
|
{
|
||||||
|
return OneSixLibraryPtr(new OneSixLibrary(lib));
|
||||||
|
}
|
||||||
|
|
||||||
void OneSixLibrary::finalize()
|
void OneSixLibrary::finalize()
|
||||||
{
|
{
|
||||||
QStringList parts = m_name.split(':');
|
QStringList parts = m_name.split(':');
|
||||||
@ -30,7 +47,7 @@ void OneSixLibrary::finalize()
|
|||||||
relative.replace('.', '/');
|
relative.replace('.', '/');
|
||||||
relative += '/' + parts[1] + '/' + parts[2] + '/' + parts[1] + '-' + parts[2];
|
relative += '/' + parts[1] + '/' + parts[2] + '/' + parts[1] + '-' + parts[2];
|
||||||
|
|
||||||
if (!m_is_native)
|
if (!isNative())
|
||||||
relative += ".jar";
|
relative += ".jar";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -65,7 +82,7 @@ void OneSixLibrary::finalize()
|
|||||||
}
|
}
|
||||||
m_is_active = (result == Allow);
|
m_is_active = (result == Allow);
|
||||||
}
|
}
|
||||||
if (m_is_native)
|
if (isNative())
|
||||||
{
|
{
|
||||||
m_is_active = m_is_active && m_native_suffixes.contains(currentSystem);
|
m_is_active = m_is_active && m_native_suffixes.contains(currentSystem);
|
||||||
m_decenttype = "Native";
|
m_decenttype = "Native";
|
||||||
@ -84,13 +101,8 @@ void OneSixLibrary::setBaseUrl(const QString &base_url)
|
|||||||
{
|
{
|
||||||
m_base_url = base_url;
|
m_base_url = base_url;
|
||||||
}
|
}
|
||||||
void OneSixLibrary::setIsNative()
|
|
||||||
{
|
|
||||||
m_is_native = true;
|
|
||||||
}
|
|
||||||
void OneSixLibrary::addNative(OpSys os, const QString &suffix)
|
void OneSixLibrary::addNative(OpSys os, const QString &suffix)
|
||||||
{
|
{
|
||||||
m_is_native = true;
|
|
||||||
m_native_suffixes[os] = suffix;
|
m_native_suffixes[os] = suffix;
|
||||||
}
|
}
|
||||||
void OneSixLibrary::clearSuffixes()
|
void OneSixLibrary::clearSuffixes()
|
||||||
@ -105,10 +117,6 @@ bool OneSixLibrary::isActive() const
|
|||||||
{
|
{
|
||||||
return m_is_active;
|
return m_is_active;
|
||||||
}
|
}
|
||||||
bool OneSixLibrary::isNative() const
|
|
||||||
{
|
|
||||||
return m_is_native;
|
|
||||||
}
|
|
||||||
QString OneSixLibrary::downloadUrl() const
|
QString OneSixLibrary::downloadUrl() const
|
||||||
{
|
{
|
||||||
if (m_absolute_url.size())
|
if (m_absolute_url.size())
|
||||||
@ -223,52 +231,3 @@ bool OneSixLibrary::extractTo(QString target_dir)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject OneSixLibrary::toJson()
|
|
||||||
{
|
|
||||||
QJsonObject libRoot;
|
|
||||||
libRoot.insert("name", m_name);
|
|
||||||
if (m_absolute_url.size())
|
|
||||||
libRoot.insert("MMC-absoluteUrl", m_absolute_url);
|
|
||||||
if (m_hint.size())
|
|
||||||
libRoot.insert("MMC-hint", m_hint);
|
|
||||||
if (m_base_url != "http://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
|
|
||||||
m_base_url != "https://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
|
|
||||||
m_base_url != "https://" + URLConstants::LIBRARY_BASE && !m_base_url.isEmpty())
|
|
||||||
{
|
|
||||||
libRoot.insert("url", m_base_url);
|
|
||||||
}
|
|
||||||
if (isNative() && m_native_suffixes.size())
|
|
||||||
{
|
|
||||||
QJsonObject nativeList;
|
|
||||||
auto iter = m_native_suffixes.begin();
|
|
||||||
while (iter != m_native_suffixes.end())
|
|
||||||
{
|
|
||||||
nativeList.insert(OpSys_toString(iter.key()), iter.value());
|
|
||||||
iter++;
|
|
||||||
}
|
|
||||||
libRoot.insert("natives", nativeList);
|
|
||||||
}
|
|
||||||
if (isNative() && extract_excludes.size())
|
|
||||||
{
|
|
||||||
QJsonArray excludes;
|
|
||||||
QJsonObject extract;
|
|
||||||
for (auto exclude : extract_excludes)
|
|
||||||
{
|
|
||||||
excludes.append(exclude);
|
|
||||||
}
|
|
||||||
extract.insert("exclude", excludes);
|
|
||||||
libRoot.insert("extract", extract);
|
|
||||||
}
|
|
||||||
if (m_rules.size())
|
|
||||||
{
|
|
||||||
QJsonArray allRules;
|
|
||||||
for (auto &rule : m_rules)
|
|
||||||
{
|
|
||||||
QJsonObject ruleObj = rule->toJson();
|
|
||||||
allRules.append(ruleObj);
|
|
||||||
}
|
|
||||||
libRoot.insert("rules", allRules);
|
|
||||||
}
|
|
||||||
return libRoot;
|
|
||||||
}
|
|
||||||
|
@ -24,27 +24,16 @@
|
|||||||
|
|
||||||
#include "logic/net/URLConstants.h"
|
#include "logic/net/URLConstants.h"
|
||||||
#include "logic/minecraft/OpSys.h"
|
#include "logic/minecraft/OpSys.h"
|
||||||
|
#include "logic/minecraft/RawLibrary.h"
|
||||||
|
|
||||||
class Rule;
|
class Rule;
|
||||||
|
|
||||||
class OneSixLibrary;
|
class OneSixLibrary;
|
||||||
typedef std::shared_ptr<OneSixLibrary> OneSixLibraryPtr;
|
typedef std::shared_ptr<OneSixLibrary> OneSixLibraryPtr;
|
||||||
|
|
||||||
class OneSixLibrary
|
class OneSixLibrary : public RawLibrary
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// basic values used internally (so far)
|
|
||||||
QString m_name;
|
|
||||||
QString m_base_url = "https://" + URLConstants::LIBRARY_BASE;
|
|
||||||
QList<std::shared_ptr<Rule>> m_rules;
|
|
||||||
|
|
||||||
// custom values
|
|
||||||
/// absolute URL. takes precedence over m_download_path, if defined
|
|
||||||
QString m_absolute_url;
|
|
||||||
/// type hint - modifies how the library is treated
|
|
||||||
QString m_hint;
|
|
||||||
|
|
||||||
// derived values used for real things
|
|
||||||
/// a decent name fit for display
|
/// a decent name fit for display
|
||||||
QString m_decentname;
|
QString m_decentname;
|
||||||
/// a decent version fit for display
|
/// a decent version fit for display
|
||||||
@ -57,13 +46,9 @@ private:
|
|||||||
QString m_download_url;
|
QString m_download_url;
|
||||||
/// is this lib actually active on the current OS?
|
/// is this lib actually active on the current OS?
|
||||||
bool m_is_active = false;
|
bool m_is_active = false;
|
||||||
/// is the library a native?
|
|
||||||
bool m_is_native = false;
|
|
||||||
/// native suffixes per OS
|
|
||||||
QMap<OpSys, QString> m_native_suffixes;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QStringList extract_excludes;
|
|
||||||
QString minVersion;
|
QString minVersion;
|
||||||
|
|
||||||
enum DependType
|
enum DependType
|
||||||
@ -80,6 +65,9 @@ public:
|
|||||||
m_name = name;
|
m_name = name;
|
||||||
dependType = type;
|
dependType = type;
|
||||||
}
|
}
|
||||||
|
/// Constructor
|
||||||
|
OneSixLibrary(RawLibraryPtr base);
|
||||||
|
static OneSixLibraryPtr fromRawLibrary(RawLibraryPtr lib);
|
||||||
|
|
||||||
/// Returns the raw name field
|
/// Returns the raw name field
|
||||||
QString rawName() const
|
QString rawName() const
|
||||||
@ -87,8 +75,6 @@ public:
|
|||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject toJson();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* finalize the library, processing the input values into derived values and state
|
* finalize the library, processing the input values into derived values and state
|
||||||
*
|
*
|
||||||
@ -116,8 +102,6 @@ public:
|
|||||||
/// Set the url base for downloads
|
/// Set the url base for downloads
|
||||||
void setBaseUrl(const QString &base_url);
|
void setBaseUrl(const QString &base_url);
|
||||||
|
|
||||||
/// Call this to mark the library as 'native' (it's a zip archive with DLLs)
|
|
||||||
void setIsNative();
|
|
||||||
/// Attach a name suffix to the specified OS native
|
/// Attach a name suffix to the specified OS native
|
||||||
void addNative(OpSys os, const QString &suffix);
|
void addNative(OpSys os, const QString &suffix);
|
||||||
/// Clears all suffixes
|
/// Clears all suffixes
|
||||||
@ -127,8 +111,6 @@ public:
|
|||||||
|
|
||||||
/// Returns true if the library should be loaded (or extracted, in case of natives)
|
/// Returns true if the library should be loaded (or extracted, in case of natives)
|
||||||
bool isActive() const;
|
bool isActive() const;
|
||||||
/// Returns true if the library is native
|
|
||||||
bool isNative() const;
|
|
||||||
/// Get the URL to download the library from
|
/// Get the URL to download the library from
|
||||||
QString downloadUrl() const;
|
QString downloadUrl() const;
|
||||||
/// Get the relative path where the library should be saved
|
/// Get the relative path where the library should be saved
|
||||||
|
@ -16,8 +16,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QList>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <memory>
|
||||||
|
#include "OpSys.h"
|
||||||
|
|
||||||
#include "logic/minecraft/OneSixLibrary.h"
|
class OneSixLibrary;
|
||||||
|
class Rule;
|
||||||
|
|
||||||
enum RuleAction
|
enum RuleAction
|
||||||
{
|
{
|
||||||
|
@ -8,16 +8,17 @@ QDateTime timeFromS3Time(QString str)
|
|||||||
return QDateTime::fromString(str, Qt::ISODate);
|
return QDateTime::fromString(str, Qt::ISODate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_timestamp (const QString & raw, QString & save_here, QDateTime & parse_here)
|
bool parse_timestamp (const QString & raw, QString & save_here, QDateTime & parse_here)
|
||||||
{
|
{
|
||||||
save_here = raw;
|
save_here = raw;
|
||||||
if (save_here.isEmpty())
|
if (save_here.isEmpty())
|
||||||
{
|
{
|
||||||
throw JSONValidationError("The timestamp is empty!");
|
return false;
|
||||||
}
|
}
|
||||||
parse_here = timeFromS3Time(save_here);
|
parse_here = timeFromS3Time(save_here);
|
||||||
if (!parse_here.isValid())
|
if (!parse_here.isValid())
|
||||||
{
|
{
|
||||||
throw JSONValidationError("The timestamp not a valid timestamp!");
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* parse the S3 timestamp in 'raw' and fill the forwarded variables.
|
* parse the S3 timestamp in 'raw' and fill the forwarded variables.
|
||||||
* return true/false for success/failure
|
* return true/false for success/failure
|
||||||
*/
|
*/
|
||||||
void parse_timestamp (const QString &raw, QString &save_here, QDateTime &parse_here);
|
bool parse_timestamp (const QString &raw, QString &save_here, QDateTime &parse_here);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* take the timestamp used by S3 and turn it into QDateTime
|
* take the timestamp used by S3 and turn it into QDateTime
|
||||||
|
@ -11,7 +11,7 @@ RawLibraryPtr RawLibrary::fromJson(const QJsonObject &libObj, const QString &fil
|
|||||||
throw JSONValidationError(filename +
|
throw JSONValidationError(filename +
|
||||||
"contains a library that doesn't have a 'name' field");
|
"contains a library that doesn't have a 'name' field");
|
||||||
}
|
}
|
||||||
out->name = libObj.value("name").toString();
|
out->m_name = libObj.value("name").toString();
|
||||||
|
|
||||||
auto readString = [libObj, filename](const QString & key, QString & variable)
|
auto readString = [libObj, filename](const QString & key, QString & variable)
|
||||||
{
|
{
|
||||||
@ -29,22 +29,21 @@ RawLibraryPtr RawLibrary::fromJson(const QJsonObject &libObj, const QString &fil
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
readString("url", out->url);
|
readString("url", out->m_base_url);
|
||||||
readString("MMC-hint", out->hint);
|
readString("MMC-hint", out->m_hint);
|
||||||
readString("MMC-absulute_url", out->absoluteUrl);
|
readString("MMC-absulute_url", out->m_absolute_url);
|
||||||
readString("MMC-absoluteUrl", out->absoluteUrl);
|
readString("MMC-absoluteUrl", out->m_absolute_url);
|
||||||
if (libObj.contains("extract"))
|
if (libObj.contains("extract"))
|
||||||
{
|
{
|
||||||
out->applyExcludes = true;
|
out->applyExcludes = true;
|
||||||
auto extractObj = ensureObject(libObj.value("extract"));
|
auto extractObj = ensureObject(libObj.value("extract"));
|
||||||
for (auto excludeVal : ensureArray(extractObj.value("exclude")))
|
for (auto excludeVal : ensureArray(extractObj.value("exclude")))
|
||||||
{
|
{
|
||||||
out->excludes.append(ensureString(excludeVal));
|
out->extract_excludes.append(ensureString(excludeVal));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (libObj.contains("natives"))
|
if (libObj.contains("natives"))
|
||||||
{
|
{
|
||||||
out->applyNatives = true;
|
|
||||||
QJsonObject nativesObj = ensureObject(libObj.value("natives"));
|
QJsonObject nativesObj = ensureObject(libObj.value("natives"));
|
||||||
for (auto it = nativesObj.begin(); it != nativesObj.end(); ++it)
|
for (auto it = nativesObj.begin(); it != nativesObj.end(); ++it)
|
||||||
{
|
{
|
||||||
@ -55,14 +54,152 @@ RawLibraryPtr RawLibrary::fromJson(const QJsonObject &libObj, const QString &fil
|
|||||||
OpSys opSys = OpSys_fromString(it.key());
|
OpSys opSys = OpSys_fromString(it.key());
|
||||||
if (opSys != Os_Other)
|
if (opSys != Os_Other)
|
||||||
{
|
{
|
||||||
out->natives.append(qMakePair(opSys, it.value().toString()));
|
out->m_native_suffixes[opSys] = it.value().toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (libObj.contains("rules"))
|
if (libObj.contains("rules"))
|
||||||
{
|
{
|
||||||
out->applyRules = true;
|
out->applyRules = true;
|
||||||
out->rules = rulesFromJsonV4(libObj);
|
out->m_rules = rulesFromJsonV4(libObj);
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RawLibraryPtr RawLibrary::fromJsonPlus(const QJsonObject &libObj, const QString &filename)
|
||||||
|
{
|
||||||
|
auto lib = RawLibrary::fromJson(libObj, filename);
|
||||||
|
if (libObj.contains("insert"))
|
||||||
|
{
|
||||||
|
QJsonValue insertVal = ensureExists(libObj.value("insert"), "library insert rule");
|
||||||
|
QString insertString;
|
||||||
|
{
|
||||||
|
if (insertVal.isString())
|
||||||
|
{
|
||||||
|
insertString = insertVal.toString();
|
||||||
|
}
|
||||||
|
else if (insertVal.isObject())
|
||||||
|
{
|
||||||
|
QJsonObject insertObj = insertVal.toObject();
|
||||||
|
if (insertObj.isEmpty())
|
||||||
|
{
|
||||||
|
throw JSONValidationError("One library has an empty insert object in " +
|
||||||
|
filename);
|
||||||
|
}
|
||||||
|
insertString = insertObj.keys().first();
|
||||||
|
lib->insertData = insertObj.value(insertString).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (insertString == "apply")
|
||||||
|
{
|
||||||
|
lib->insertType = RawLibrary::Apply;
|
||||||
|
}
|
||||||
|
else if (insertString == "prepend")
|
||||||
|
{
|
||||||
|
lib->insertType = RawLibrary::Prepend;
|
||||||
|
}
|
||||||
|
else if (insertString == "append")
|
||||||
|
{
|
||||||
|
lib->insertType = RawLibrary::Append;
|
||||||
|
}
|
||||||
|
else if (insertString == "replace")
|
||||||
|
{
|
||||||
|
lib->insertType = RawLibrary::Replace;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw JSONValidationError("A '+' library in " + filename +
|
||||||
|
" contains an invalid insert type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (libObj.contains("MMC-depend"))
|
||||||
|
{
|
||||||
|
const QString dependString = ensureString(libObj.value("MMC-depend"));
|
||||||
|
if (dependString == "hard")
|
||||||
|
{
|
||||||
|
lib->dependType = RawLibrary::Hard;
|
||||||
|
}
|
||||||
|
else if (dependString == "soft")
|
||||||
|
{
|
||||||
|
lib->dependType = RawLibrary::Soft;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw JSONValidationError("A '+' library in " + filename +
|
||||||
|
" contains an invalid depend type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RawLibrary::isNative() const
|
||||||
|
{
|
||||||
|
return m_native_suffixes.size() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject RawLibrary::toJson()
|
||||||
|
{
|
||||||
|
QJsonObject libRoot;
|
||||||
|
libRoot.insert("name", m_name);
|
||||||
|
if (m_absolute_url.size())
|
||||||
|
libRoot.insert("MMC-absoluteUrl", m_absolute_url);
|
||||||
|
if (m_hint.size())
|
||||||
|
libRoot.insert("MMC-hint", m_hint);
|
||||||
|
if (m_base_url != "http://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
|
||||||
|
m_base_url != "https://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
|
||||||
|
m_base_url != "https://" + URLConstants::LIBRARY_BASE && !m_base_url.isEmpty())
|
||||||
|
{
|
||||||
|
libRoot.insert("url", m_base_url);
|
||||||
|
}
|
||||||
|
if (isNative())
|
||||||
|
{
|
||||||
|
QJsonObject nativeList;
|
||||||
|
auto iter = m_native_suffixes.begin();
|
||||||
|
while (iter != m_native_suffixes.end())
|
||||||
|
{
|
||||||
|
nativeList.insert(OpSys_toString(iter.key()), iter.value());
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
libRoot.insert("natives", nativeList);
|
||||||
|
if (extract_excludes.size())
|
||||||
|
{
|
||||||
|
QJsonArray excludes;
|
||||||
|
QJsonObject extract;
|
||||||
|
for (auto exclude : extract_excludes)
|
||||||
|
{
|
||||||
|
excludes.append(exclude);
|
||||||
|
}
|
||||||
|
extract.insert("exclude", excludes);
|
||||||
|
libRoot.insert("extract", extract);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_rules.size())
|
||||||
|
{
|
||||||
|
QJsonArray allRules;
|
||||||
|
for (auto &rule : m_rules)
|
||||||
|
{
|
||||||
|
QJsonObject ruleObj = rule->toJson();
|
||||||
|
allRules.append(ruleObj);
|
||||||
|
}
|
||||||
|
libRoot.insert("rules", allRules);
|
||||||
|
}
|
||||||
|
return libRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RawLibrary::fullname()
|
||||||
|
{
|
||||||
|
QStringList parts = m_name.split(':');
|
||||||
|
return parts[0] + ":" + parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RawLibrary::group()
|
||||||
|
{
|
||||||
|
QStringList parts = m_name.split(':');
|
||||||
|
return parts[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RawLibrary::version()
|
||||||
|
{
|
||||||
|
QStringList parts = m_name.split(':');
|
||||||
|
return parts[2];
|
||||||
|
}
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
|
#include <QList>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QMap>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "OneSixRule.h"
|
#include "logic/minecraft/OneSixRule.h"
|
||||||
|
#include "logic/minecraft/OpSys.h"
|
||||||
|
#include "logic/net/URLConstants.h"
|
||||||
|
|
||||||
class RawLibrary;
|
class RawLibrary;
|
||||||
typedef std::shared_ptr<RawLibrary> RawLibraryPtr;
|
typedef std::shared_ptr<RawLibrary> RawLibraryPtr;
|
||||||
@ -11,24 +16,36 @@ typedef std::shared_ptr<RawLibrary> RawLibraryPtr;
|
|||||||
class RawLibrary
|
class RawLibrary
|
||||||
{
|
{
|
||||||
public: /* methods */
|
public: /* methods */
|
||||||
|
/// read and create a basic library
|
||||||
static RawLibraryPtr fromJson(const QJsonObject &libObj, const QString &filename);
|
static RawLibraryPtr fromJson(const QJsonObject &libObj, const QString &filename);
|
||||||
|
/// read and create a MultiMC '+' library. Those have some extra fields.
|
||||||
|
static RawLibraryPtr fromJsonPlus(const QJsonObject &libObj, const QString &filename);
|
||||||
|
QJsonObject toJson();
|
||||||
|
|
||||||
|
QString fullname();
|
||||||
|
QString version();
|
||||||
|
QString group();
|
||||||
|
|
||||||
public: /* data */
|
public: /* data */
|
||||||
QString name;
|
QString m_name;
|
||||||
QString url;
|
QString m_base_url = "https://" + URLConstants::LIBRARY_BASE;
|
||||||
QString hint;
|
/// type hint - modifies how the library is treated
|
||||||
QString absoluteUrl;
|
QString m_hint;
|
||||||
|
/// absolute URL. takes precedence over m_download_path, if defined
|
||||||
|
QString m_absolute_url;
|
||||||
|
|
||||||
bool applyExcludes = false;
|
bool applyExcludes = false;
|
||||||
QStringList excludes;
|
QStringList extract_excludes;
|
||||||
|
|
||||||
bool applyNatives = false;
|
/// Returns true if the library is native
|
||||||
QList<QPair<OpSys, QString>> natives;
|
bool isNative() const;
|
||||||
|
/// native suffixes per OS
|
||||||
|
QMap<OpSys, QString> m_native_suffixes;
|
||||||
|
|
||||||
bool applyRules = false;
|
bool applyRules = false;
|
||||||
QList<std::shared_ptr<Rule>> rules;
|
QList<std::shared_ptr<Rule>> m_rules;
|
||||||
|
|
||||||
// user for '+' libraries
|
// used for '+' libraries
|
||||||
enum InsertType
|
enum InsertType
|
||||||
{
|
{
|
||||||
Apply,
|
Apply,
|
||||||
|
@ -30,6 +30,7 @@ class VersionBuilder
|
|||||||
public:
|
public:
|
||||||
static void build(VersionFinal *version, OneSixInstance *instance, const QStringList &external);
|
static void build(VersionFinal *version, OneSixInstance *instance, const QStringList &external);
|
||||||
static void readJsonAndApplyToVersion(VersionFinal *version, const QJsonObject &obj);
|
static void readJsonAndApplyToVersion(VersionFinal *version, const QJsonObject &obj);
|
||||||
|
static VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder, bool isFTB = false);
|
||||||
|
|
||||||
static QMap<QString, int> readOverrideOrders(OneSixInstance *instance);
|
static QMap<QString, int> readOverrideOrders(OneSixInstance *instance);
|
||||||
static bool writeOverrideOrders(const QMap<QString, int> &order, OneSixInstance *instance);
|
static bool writeOverrideOrders(const QMap<QString, int> &order, OneSixInstance *instance);
|
||||||
@ -49,7 +50,4 @@ private:
|
|||||||
void readInstancePatches();
|
void readInstancePatches();
|
||||||
|
|
||||||
void readJsonAndApply(const QJsonObject &obj);
|
void readJsonAndApply(const QJsonObject &obj);
|
||||||
|
|
||||||
VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder,
|
|
||||||
bool isFTB = false);
|
|
||||||
};
|
};
|
||||||
|
@ -98,14 +98,10 @@ VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &fi
|
|||||||
readString("+minecraftArguments", out->addMinecraftArguments);
|
readString("+minecraftArguments", out->addMinecraftArguments);
|
||||||
readString("-minecraftArguments", out->removeMinecraftArguments);
|
readString("-minecraftArguments", out->removeMinecraftArguments);
|
||||||
readString("type", out->type);
|
readString("type", out->type);
|
||||||
if (out->isVanilla())
|
|
||||||
{
|
|
||||||
parse_timestamp(readStringRet("releaseTime"), out->m_releaseTimeString,
|
|
||||||
out->m_releaseTime);
|
|
||||||
parse_timestamp(readStringRet("time"), out->m_updateTimeString, out->m_updateTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
readStringRet("time");
|
parse_timestamp(readStringRet("releaseTime"), out->m_releaseTimeString, out->m_releaseTime);
|
||||||
|
parse_timestamp(readStringRet("time"), out->m_updateTimeString, out->m_updateTime);
|
||||||
|
|
||||||
readString("assets", out->assets);
|
readString("assets", out->assets);
|
||||||
|
|
||||||
if (root.contains("minimumLauncherVersion"))
|
if (root.contains("minimumLauncherVersion"))
|
||||||
@ -158,7 +154,7 @@ VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &fi
|
|||||||
// FIXME: This should be done when applying.
|
// FIXME: This should be done when applying.
|
||||||
if (isFTB)
|
if (isFTB)
|
||||||
{
|
{
|
||||||
lib->hint = "local";
|
lib->m_hint = "local";
|
||||||
lib->insertType = RawLibrary::Prepend;
|
lib->insertType = RawLibrary::Prepend;
|
||||||
out->addLibs.prepend(lib);
|
out->addLibs.prepend(lib);
|
||||||
}
|
}
|
||||||
@ -186,68 +182,8 @@ VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &fi
|
|||||||
for (auto libVal : ensureArray(root.value("+libraries")))
|
for (auto libVal : ensureArray(root.value("+libraries")))
|
||||||
{
|
{
|
||||||
QJsonObject libObj = ensureObject(libVal);
|
QJsonObject libObj = ensureObject(libVal);
|
||||||
QJsonValue insertVal = ensureExists(libObj.value("insert"));
|
|
||||||
|
|
||||||
// parse the library
|
// parse the library
|
||||||
auto lib = RawLibrary::fromJson(libObj, filename);
|
auto lib = RawLibrary::fromJsonPlus(libObj, filename);
|
||||||
|
|
||||||
// TODO: utility functions for handling this case. templates?
|
|
||||||
QString insertString;
|
|
||||||
{
|
|
||||||
if (insertVal.isString())
|
|
||||||
{
|
|
||||||
insertString = insertVal.toString();
|
|
||||||
}
|
|
||||||
else if (insertVal.isObject())
|
|
||||||
{
|
|
||||||
QJsonObject insertObj = insertVal.toObject();
|
|
||||||
if (insertObj.isEmpty())
|
|
||||||
{
|
|
||||||
throw JSONValidationError("One library has an empty insert object in " +
|
|
||||||
filename);
|
|
||||||
}
|
|
||||||
insertString = insertObj.keys().first();
|
|
||||||
lib->insertData = insertObj.value(insertString).toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (insertString == "apply")
|
|
||||||
{
|
|
||||||
lib->insertType = RawLibrary::Apply;
|
|
||||||
}
|
|
||||||
else if (insertString == "prepend")
|
|
||||||
{
|
|
||||||
lib->insertType = RawLibrary::Prepend;
|
|
||||||
}
|
|
||||||
else if (insertString == "append")
|
|
||||||
{
|
|
||||||
lib->insertType = RawLibrary::Prepend;
|
|
||||||
}
|
|
||||||
else if (insertString == "replace")
|
|
||||||
{
|
|
||||||
lib->insertType = RawLibrary::Replace;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw JSONValidationError("A '+' library in " + filename +
|
|
||||||
" contains an invalid insert type");
|
|
||||||
}
|
|
||||||
if (libObj.contains("MMC-depend"))
|
|
||||||
{
|
|
||||||
const QString dependString = ensureString(libObj.value("MMC-depend"));
|
|
||||||
if (dependString == "hard")
|
|
||||||
{
|
|
||||||
lib->dependType = RawLibrary::Hard;
|
|
||||||
}
|
|
||||||
else if (dependString == "soft")
|
|
||||||
{
|
|
||||||
lib->dependType = RawLibrary::Soft;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw JSONValidationError("A '+' library in " + filename +
|
|
||||||
" contains an invalid depend type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out->addLibs.append(lib);
|
out->addLibs.append(lib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,32 +199,66 @@ VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &fi
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
OneSixLibraryPtr VersionFile::createLibrary(RawLibraryPtr lib)
|
QJsonDocument VersionFile::toJson(bool saveOrder)
|
||||||
{
|
{
|
||||||
std::shared_ptr<OneSixLibrary> out(new OneSixLibrary(lib->name));
|
QJsonObject root;
|
||||||
if (!lib->url.isEmpty())
|
if (saveOrder)
|
||||||
{
|
{
|
||||||
out->setBaseUrl(lib->url);
|
root.insert("order", order);
|
||||||
}
|
}
|
||||||
out->setHint(lib->hint);
|
writeString(root, "name", name);
|
||||||
if (!lib->absoluteUrl.isEmpty())
|
writeString(root, "fileId", fileId);
|
||||||
|
writeString(root, "version", version);
|
||||||
|
writeString(root, "mcVersion", mcVersion);
|
||||||
|
writeString(root, "id", id);
|
||||||
|
writeString(root, "mainClass", mainClass);
|
||||||
|
writeString(root, "appletClass", appletClass);
|
||||||
|
writeString(root, "processArguments", processArguments);
|
||||||
|
writeString(root, "minecraftArguments", overwriteMinecraftArguments);
|
||||||
|
writeString(root, "+minecraftArguments", addMinecraftArguments);
|
||||||
|
writeString(root, "-minecraftArguments", removeMinecraftArguments);
|
||||||
|
writeString(root, "type", type);
|
||||||
|
writeString(root, "assets", assets);
|
||||||
|
if (isMinecraftVersion())
|
||||||
{
|
{
|
||||||
out->setAbsoluteUrl(lib->absoluteUrl);
|
writeString(root, "releaseTime", m_releaseTimeString);
|
||||||
|
writeString(root, "time", m_updateTimeString);
|
||||||
}
|
}
|
||||||
out->setAbsoluteUrl(lib->absoluteUrl);
|
if (minimumLauncherVersion != -1)
|
||||||
out->extract_excludes = lib->excludes;
|
|
||||||
for (auto native : lib->natives)
|
|
||||||
{
|
{
|
||||||
out->addNative(native.first, native.second);
|
root.insert("minimumLauncherVersion", minimumLauncherVersion);
|
||||||
}
|
}
|
||||||
out->setRules(lib->rules);
|
writeStringList(root, "tweakers", overwriteTweakers);
|
||||||
out->finalize();
|
writeStringList(root, "+tweakers", addTweakers);
|
||||||
|
writeStringList(root, "-tweakers", removeTweakers);
|
||||||
|
writeStringList(root, "+traits", traits.toList());
|
||||||
|
writeObjectList(root, "libraries", overwriteLibs);
|
||||||
|
writeObjectList(root, "+libraries", addLibs);
|
||||||
|
writeObjectList(root, "+jarMods", jarMods);
|
||||||
|
// FIXME: removed libs are special snowflakes.
|
||||||
|
if (removeLibs.size())
|
||||||
|
{
|
||||||
|
QJsonArray array;
|
||||||
|
for (auto lib : removeLibs)
|
||||||
|
{
|
||||||
|
QJsonObject rmlibobj;
|
||||||
|
rmlibobj.insert("name", lib);
|
||||||
|
array.append(rmlibobj);
|
||||||
|
}
|
||||||
|
root.insert("-libraries", array);
|
||||||
|
}
|
||||||
|
// write the contents to a json document.
|
||||||
|
{
|
||||||
|
QJsonDocument out;
|
||||||
|
out.setObject(root);
|
||||||
return out;
|
return out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VersionFile::isVanilla()
|
bool VersionFile::isMinecraftVersion()
|
||||||
{
|
{
|
||||||
return fileId == "org.multimc.version.json";
|
return (fileId == "org.multimc.version.json") || (fileId == "net.minecraft") ||
|
||||||
|
(fileId == "org.multimc.custom.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VersionFile::hasJarMods()
|
bool VersionFile::hasJarMods()
|
||||||
@ -330,13 +300,13 @@ void VersionFile::applyTo(VersionFinal *version)
|
|||||||
}
|
}
|
||||||
if (!processArguments.isNull())
|
if (!processArguments.isNull())
|
||||||
{
|
{
|
||||||
if (isVanilla())
|
if (isMinecraftVersion())
|
||||||
{
|
{
|
||||||
version->vanillaProcessArguments = processArguments;
|
version->vanillaProcessArguments = processArguments;
|
||||||
}
|
}
|
||||||
version->processArguments = processArguments;
|
version->processArguments = processArguments;
|
||||||
}
|
}
|
||||||
if(isVanilla())
|
if (isMinecraftVersion())
|
||||||
{
|
{
|
||||||
if (!type.isNull())
|
if (!type.isNull())
|
||||||
{
|
{
|
||||||
@ -359,12 +329,12 @@ void VersionFile::applyTo(VersionFinal *version)
|
|||||||
}
|
}
|
||||||
if (minimumLauncherVersion >= 0)
|
if (minimumLauncherVersion >= 0)
|
||||||
{
|
{
|
||||||
if(version->minimumLauncherVersion < minimumLauncherVersion)
|
if (version->minimumLauncherVersion < minimumLauncherVersion)
|
||||||
version->minimumLauncherVersion = minimumLauncherVersion;
|
version->minimumLauncherVersion = minimumLauncherVersion;
|
||||||
}
|
}
|
||||||
if (!overwriteMinecraftArguments.isNull())
|
if (!overwriteMinecraftArguments.isNull())
|
||||||
{
|
{
|
||||||
if (isVanilla())
|
if (isMinecraftVersion())
|
||||||
{
|
{
|
||||||
version->vanillaMinecraftArguments = overwriteMinecraftArguments;
|
version->vanillaMinecraftArguments = overwriteMinecraftArguments;
|
||||||
}
|
}
|
||||||
@ -397,10 +367,12 @@ void VersionFile::applyTo(VersionFinal *version)
|
|||||||
QList<OneSixLibraryPtr> libs;
|
QList<OneSixLibraryPtr> libs;
|
||||||
for (auto lib : overwriteLibs)
|
for (auto lib : overwriteLibs)
|
||||||
{
|
{
|
||||||
libs.append(createLibrary(lib));
|
libs.append(OneSixLibrary::fromRawLibrary(lib));
|
||||||
}
|
}
|
||||||
if (isVanilla())
|
if (isMinecraftVersion())
|
||||||
|
{
|
||||||
version->vanillaLibraries = libs;
|
version->vanillaLibraries = libs;
|
||||||
|
}
|
||||||
version->libraries = libs;
|
version->libraries = libs;
|
||||||
}
|
}
|
||||||
for (auto lib : addLibs)
|
for (auto lib : addLibs)
|
||||||
@ -410,43 +382,46 @@ void VersionFile::applyTo(VersionFinal *version)
|
|||||||
case RawLibrary::Apply:
|
case RawLibrary::Apply:
|
||||||
{
|
{
|
||||||
// QLOG_INFO() << "Applying lib " << lib->name;
|
// QLOG_INFO() << "Applying lib " << lib->name;
|
||||||
int index = findLibrary(version->libraries, lib->name);
|
int index = findLibrary(version->libraries, lib->m_name);
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
auto library = version->libraries[index];
|
auto library = version->libraries[index];
|
||||||
if (!lib->url.isNull())
|
if (!lib->m_base_url.isNull())
|
||||||
{
|
{
|
||||||
library->setBaseUrl(lib->url);
|
library->setBaseUrl(lib->m_base_url);
|
||||||
}
|
}
|
||||||
if (!lib->hint.isNull())
|
if (!lib->m_hint.isNull())
|
||||||
{
|
{
|
||||||
library->setHint(lib->hint);
|
library->setHint(lib->m_hint);
|
||||||
}
|
}
|
||||||
if (!lib->absoluteUrl.isNull())
|
if (!lib->m_absolute_url.isNull())
|
||||||
{
|
{
|
||||||
library->setAbsoluteUrl(lib->absoluteUrl);
|
library->setAbsoluteUrl(lib->m_absolute_url);
|
||||||
}
|
}
|
||||||
if (lib->applyExcludes)
|
if (lib->applyExcludes)
|
||||||
{
|
{
|
||||||
library->extract_excludes = lib->excludes;
|
library->extract_excludes = lib->extract_excludes;
|
||||||
}
|
}
|
||||||
if (lib->applyNatives)
|
if (lib->isNative())
|
||||||
{
|
{
|
||||||
library->clearSuffixes();
|
// library->clearSuffixes();
|
||||||
|
library->m_native_suffixes = lib->m_native_suffixes;
|
||||||
|
/*
|
||||||
for (auto native : lib->natives)
|
for (auto native : lib->natives)
|
||||||
{
|
{
|
||||||
library->addNative(native.first, native.second);
|
library->addNative(native.first, native.second);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
if (lib->applyRules)
|
if (lib->applyRules)
|
||||||
{
|
{
|
||||||
library->setRules(lib->rules);
|
library->setRules(lib->m_rules);
|
||||||
}
|
}
|
||||||
library->finalize();
|
library->finalize();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QLOG_WARN() << "Couldn't find" << lib->name << "(skipping)";
|
QLOG_WARN() << "Couldn't find" << lib->m_name << "(skipping)";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -454,24 +429,24 @@ void VersionFile::applyTo(VersionFinal *version)
|
|||||||
case RawLibrary::Prepend:
|
case RawLibrary::Prepend:
|
||||||
{
|
{
|
||||||
// QLOG_INFO() << "Adding lib " << lib->name;
|
// QLOG_INFO() << "Adding lib " << lib->name;
|
||||||
const int startOfVersion = lib->name.lastIndexOf(':') + 1;
|
const int startOfVersion = lib->m_name.lastIndexOf(':') + 1;
|
||||||
const int index = findLibrary(
|
const int index = findLibrary(
|
||||||
version->libraries, QString(lib->name).replace(startOfVersion, INT_MAX, '*'));
|
version->libraries, QString(lib->m_name).replace(startOfVersion, INT_MAX, '*'));
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
{
|
{
|
||||||
if (lib->insertType == RawLibrary::Append)
|
if (lib->insertType == RawLibrary::Append)
|
||||||
{
|
{
|
||||||
version->libraries.append(createLibrary(lib));
|
version->libraries.append(OneSixLibrary::fromRawLibrary(lib));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
version->libraries.prepend(createLibrary(lib));
|
version->libraries.prepend(OneSixLibrary::fromRawLibrary(lib));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto otherLib = version->libraries.at(index);
|
auto otherLib = version->libraries.at(index);
|
||||||
const Util::Version ourVersion = lib->name.mid(startOfVersion, INT_MAX);
|
const Util::Version ourVersion = lib->m_name.mid(startOfVersion, INT_MAX);
|
||||||
const Util::Version otherVersion = otherLib->version();
|
const Util::Version otherVersion = otherLib->version();
|
||||||
// if the existing version is a hard dependency we can either use it or
|
// if the existing version is a hard dependency we can either use it or
|
||||||
// fail, but we can't change it
|
// fail, but we can't change it
|
||||||
@ -485,7 +460,7 @@ void VersionFile::applyTo(VersionFinal *version)
|
|||||||
throw VersionBuildError(
|
throw VersionBuildError(
|
||||||
QObject::tr(
|
QObject::tr(
|
||||||
"Error resolving library dependencies between %1 and %2 in %3.")
|
"Error resolving library dependencies between %1 and %2 in %3.")
|
||||||
.arg(otherLib->rawName(), lib->name, filename));
|
.arg(otherLib->rawName(), lib->m_name, filename));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -497,7 +472,7 @@ void VersionFile::applyTo(VersionFinal *version)
|
|||||||
// if we are higher it means we should update
|
// if we are higher it means we should update
|
||||||
if (ourVersion > otherVersion)
|
if (ourVersion > otherVersion)
|
||||||
{
|
{
|
||||||
auto library = createLibrary(lib);
|
auto library = OneSixLibrary::fromRawLibrary(lib);
|
||||||
if (Util::Version(otherLib->minVersion) < ourVersion)
|
if (Util::Version(otherLib->minVersion) < ourVersion)
|
||||||
{
|
{
|
||||||
library->minVersion = ourVersion.toString();
|
library->minVersion = ourVersion.toString();
|
||||||
@ -512,7 +487,7 @@ void VersionFile::applyTo(VersionFinal *version)
|
|||||||
{
|
{
|
||||||
throw VersionBuildError(QObject::tr(
|
throw VersionBuildError(QObject::tr(
|
||||||
"Error resolving library dependencies between %1 and %2 in %3.")
|
"Error resolving library dependencies between %1 and %2 in %3.")
|
||||||
.arg(otherLib->rawName(), lib->name,
|
.arg(otherLib->rawName(), lib->m_name,
|
||||||
filename));
|
filename));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -525,8 +500,8 @@ void VersionFile::applyTo(VersionFinal *version)
|
|||||||
QString toReplace;
|
QString toReplace;
|
||||||
if (lib->insertData.isEmpty())
|
if (lib->insertData.isEmpty())
|
||||||
{
|
{
|
||||||
const int startOfVersion = lib->name.lastIndexOf(':') + 1;
|
const int startOfVersion = lib->m_name.lastIndexOf(':') + 1;
|
||||||
toReplace = QString(lib->name).replace(startOfVersion, INT_MAX, '*');
|
toReplace = QString(lib->m_name).replace(startOfVersion, INT_MAX, '*');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
toReplace = lib->insertData;
|
toReplace = lib->insertData;
|
||||||
@ -534,7 +509,7 @@ void VersionFile::applyTo(VersionFinal *version)
|
|||||||
int index = findLibrary(version->libraries, toReplace);
|
int index = findLibrary(version->libraries, toReplace);
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
version->libraries.replace(index, createLibrary(lib));
|
version->libraries.replace(index, OneSixLibrary::fromRawLibrary(lib));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "logic/minecraft/OneSixRule.h"
|
#include "logic/minecraft/OneSixRule.h"
|
||||||
#include "VersionPatch.h"
|
#include "VersionPatch.h"
|
||||||
#include "MMCError.h"
|
#include "MMCError.h"
|
||||||
#include "RawLibrary.h"
|
#include "OneSixLibrary.h"
|
||||||
#include "JarMod.h"
|
#include "JarMod.h"
|
||||||
|
|
||||||
class VersionFinal;
|
class VersionFinal;
|
||||||
@ -20,10 +20,10 @@ class VersionFile : public VersionPatch
|
|||||||
public: /* methods */
|
public: /* methods */
|
||||||
static VersionFilePtr fromJson(const QJsonDocument &doc, const QString &filename,
|
static VersionFilePtr fromJson(const QJsonDocument &doc, const QString &filename,
|
||||||
const bool requireOrder, const bool isFTB = false);
|
const bool requireOrder, const bool isFTB = false);
|
||||||
|
QJsonDocument toJson(bool saveOrder);
|
||||||
|
|
||||||
static OneSixLibraryPtr createLibrary(RawLibraryPtr lib);
|
|
||||||
virtual void applyTo(VersionFinal *version) override;
|
virtual void applyTo(VersionFinal *version) override;
|
||||||
virtual bool isVanilla() override;
|
virtual bool isMinecraftVersion() override;
|
||||||
virtual bool hasJarMods() override;
|
virtual bool hasJarMods() override;
|
||||||
virtual int getOrder() override
|
virtual int getOrder() override
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,7 @@ public:
|
|||||||
virtual ~VersionPatch(){};
|
virtual ~VersionPatch(){};
|
||||||
virtual void applyTo(VersionFinal *version) = 0;
|
virtual void applyTo(VersionFinal *version) = 0;
|
||||||
|
|
||||||
virtual bool isVanilla() = 0;
|
virtual bool isMinecraftVersion() = 0;
|
||||||
virtual bool hasJarMods() = 0;
|
virtual bool hasJarMods() = 0;
|
||||||
virtual QList<JarmodPtr> getJarMods() = 0;
|
virtual QList<JarmodPtr> getJarMods() = 0;
|
||||||
|
|
||||||
|
9
logic/minecraft/VersionSource.h
Normal file
9
logic/minecraft/VersionSource.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// where is a version from?
|
||||||
|
enum VersionSource
|
||||||
|
{
|
||||||
|
Builtin, //!< version loaded from the internal resources.
|
||||||
|
Local, //!< version loaded from a file in the cache.
|
||||||
|
Remote, //!< incomplete version on a remote server.
|
||||||
|
};
|
@ -32,6 +32,7 @@ signals:
|
|||||||
void status(QString status);
|
void status(QString status);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
virtual ~ProgressProvider() {};
|
||||||
virtual QString getStatus() const = 0;
|
virtual QString getStatus() const = 0;
|
||||||
virtual void getProgress(qint64 ¤t, qint64 &total) = 0;
|
virtual void getProgress(qint64 ¤t, qint64 &total) = 0;
|
||||||
virtual bool isRunning() const = 0;
|
virtual bool isRunning() const = 0;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"fileId": "org.lwjgl",
|
"fileId": "org.lwjgl",
|
||||||
"name": "LWJGL",
|
"name": "LWJGL",
|
||||||
"version": "2.9.0",
|
"version": "2.9.0",
|
||||||
"libraries": [
|
"+libraries": [
|
||||||
{
|
{
|
||||||
"name": "net.java.jinput:jinput:2.0.5"
|
"name": "net.java.jinput:jinput:2.0.5"
|
||||||
},
|
},
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"fileId": "org.lwjgl",
|
"fileId": "org.lwjgl",
|
||||||
"name": "LWJGL",
|
"name": "LWJGL",
|
||||||
"version": "2.9.1-nightly-20130708-debug3",
|
"version": "2.9.1-nightly-20130708-debug3",
|
||||||
"libraries": [
|
"+libraries": [
|
||||||
{
|
{
|
||||||
"name": "net.java.jinput:jinput:2.0.5"
|
"name": "net.java.jinput:jinput:2.0.5"
|
||||||
},
|
},
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"fileId": "org.lwjgl",
|
"fileId": "org.lwjgl",
|
||||||
"name": "LWJGL",
|
"name": "LWJGL",
|
||||||
"version": "2.9.1",
|
"version": "2.9.1",
|
||||||
"libraries": [
|
"+libraries": [
|
||||||
{
|
{
|
||||||
"name": "net.java.jinput:jinput:2.0.5"
|
"name": "net.java.jinput:jinput:2.0.5"
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user