NOISSUE finalize support for new mojang version format

This commit is contained in:
Petr Mrázek 2016-03-26 16:56:57 +01:00
parent d587720010
commit f032e32133
42 changed files with 805 additions and 612 deletions

View File

@ -534,7 +534,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
auto meta = Env::getInstance().metacache()->resolveEntry("skins", profile.id + ".png");
auto action = CacheDownload::make(QUrl("https://" + URLConstants::SKINS_BASE + profile.id + ".png"), meta);
skin_dls.append(action);
meta->stale = true;
meta->setStale(true);
}
}
if (!skin_dls.isEmpty())
@ -1028,7 +1028,7 @@ InstancePtr MainWindow::instanceFromZipPack(QString instName, QString instGroup,
{
const QString path = url.host() + '/' + url.path();
auto entry = ENV.metacache()->resolveEntry("general", path);
entry->stale = true;
entry->setStale(true);
CacheDownloadPtr dl = CacheDownload::make(url, entry);
NetJob job(tr("Modpack download"));
job.addNetAction(dl);

View File

@ -13,7 +13,7 @@ WebResourceHandler::WebResourceHandler(const QString &url)
: QObject(), m_url(url)
{
MetaEntryPtr entry = ENV.metacache()->resolveEntry("icons", url);
if (!entry->stale)
if (!entry->isStale())
{
setResultFromFile(entry->getFullPath());
}

View File

@ -133,7 +133,7 @@ void AccountListPage::addAccount(const QString &errMsg)
auto action = CacheDownload::make(
QUrl("https://" + URLConstants::SKINS_BASE + profile.id + ".png"), meta);
job->addNetAction(action);
meta->stale = true;
meta->setStale(true);
}
job->start();

View File

@ -31,6 +31,8 @@ public class OneSixLauncher implements Launcher
// parameters, separated from ParamBucket
private List<String> libraries;
private List<String> extlibs;
private List<String> extlibs32;
private List<String> extlibs64;
private List<String> mcparams;
private List<String> mods;
private List<String> jarmods;
@ -38,7 +40,7 @@ public class OneSixLauncher implements Launcher
private List<String> traits;
private String appletClass;
private String mainClass;
private String natives;
private String nativePath;
private String userName, sessionId;
private String windowTitle;
private String windowParams;
@ -54,7 +56,22 @@ public class OneSixLauncher implements Launcher
private void processParams(ParamBucket params) throws NotFoundException
{
libraries = params.all("cp");
extlibs = params.all("ext");
extlibs = params.allSafe("ext", new ArrayList<String>());
extlibs32 = params.allSafe("ext32", new ArrayList<String>());
extlibs64 = params.allSafe("ext64", new ArrayList<String>());
// Unify the extracted native libs according to actual system architecture
String property = System.getProperty("os.arch");
boolean is_64 = property.equalsIgnoreCase("x86_64") || property.equalsIgnoreCase("amd64");
if(is_64)
{
extlibs.addAll(extlibs64);
}
else
{
extlibs.addAll(extlibs32);
}
mcparams = params.allSafe("param", new ArrayList<String>() );
mainClass = params.firstSafe("mainClass", "net.minecraft.client.Minecraft");
appletClass = params.firstSafe("appletClass", "net.minecraft.client.MinecraftApplet");
@ -62,7 +79,7 @@ public class OneSixLauncher implements Launcher
jarmods = params.allSafe("jarmod", new ArrayList<String>());
coremods = params.allSafe("coremod", new ArrayList<String>());
traits = params.allSafe("traits", new ArrayList<String>());
natives = params.first("natives");
nativePath = params.first("natives");
userName = params.first("userName");
sessionId = params.first("sessionId");
@ -95,7 +112,7 @@ public class OneSixLauncher implements Launcher
Utils.log();
Utils.log("Native path:");
Utils.log(" " + natives);
Utils.log(" " + nativePath);
Utils.log();
Utils.log("Traits:");
@ -343,16 +360,13 @@ public class OneSixLauncher implements Launcher
// extract native libs (depending on platform here... java!)
Utils.log("Preparing native libraries...");
String property = System.getProperty("os.arch");
boolean is_64 = property.equalsIgnoreCase("x86_64") || property.equalsIgnoreCase("amd64");
for(String extlib: extlibs)
{
try
{
String cleanlib = extlib.replace("${arch}", is_64 ? "64" : "32");
File cleanlibf = new File(cleanlib);
Utils.log("Extracting " + cleanlibf.getName());
Utils.unzipNatives(cleanlibf, new File(natives));
File extlibf = new File(extlib);
Utils.log("Extracting " + extlibf.getName());
Utils.unzipNatives(extlibf, new File(nativePath));
} catch (IOException e)
{
System.err.println("Failed to extract native library:");
@ -365,9 +379,9 @@ public class OneSixLauncher implements Launcher
// set the native libs path... the brute force way
try
{
System.setProperty("java.library.path", natives);
System.setProperty("org.lwjgl.librarypath", natives);
System.setProperty("net.java.games.input.librarypath", natives);
System.setProperty("java.library.path", nativePath);
System.setProperty("org.lwjgl.librarypath", nativePath);
System.setProperty("net.java.games.input.librarypath", nativePath);
// by the power of reflection, initialize native libs again. DIRTY!
// this is SO BAD. imagine doing that to ld
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");

View File

@ -284,9 +284,6 @@ set(LOGIC_SOURCES
minecraft/forge/ForgeVersion.cpp
minecraft/forge/ForgeVersionList.h
minecraft/forge/ForgeVersionList.cpp
minecraft/forge/ForgeMirror.h
minecraft/forge/ForgeMirrors.h
minecraft/forge/ForgeMirrors.cpp
minecraft/forge/ForgeXzDownload.h
minecraft/forge/ForgeXzDownload.cpp
minecraft/forge/LegacyForge.h

View File

@ -1,57 +1,176 @@
#include "Library.h"
#include <net/CacheDownload.h>
#include <minecraft/forge/ForgeXzDownload.h>
#include <Env.h>
#include <FileSystem.h>
QStringList Library::files() const
void Library::getApplicableFiles(OpSys system, QStringList& jar, QStringList& native, QStringList& native32, QStringList& native64) const
{
QStringList retval;
QString storage = storageSuffix();
if (storage.contains("${arch}"))
auto actualPath = [&](QString relPath)
{
QString cooked_storage = storage;
cooked_storage.replace("${arch}", "32");
retval.append(cooked_storage);
cooked_storage = storage;
cooked_storage.replace("${arch}", "64");
retval.append(cooked_storage);
QFileInfo out(FS::PathCombine(storagePrefix(), relPath));
return out.absoluteFilePath();
};
if(m_mojangDownloads)
{
if(m_mojangDownloads->artifact)
{
auto artifact = m_mojangDownloads->artifact;
jar += actualPath(artifact->path);
}
if(!isNative())
return;
if(m_nativeClassifiers.contains(system))
{
auto nativeClassifier = m_nativeClassifiers[system];
if(nativeClassifier.contains("${arch}"))
{
auto nat32Classifier = nativeClassifier;
nat32Classifier.replace("${arch}", "32");
auto nat64Classifier = nativeClassifier;
nat64Classifier.replace("${arch}", "64");
auto nat32info = m_mojangDownloads->getDownloadInfo(nat32Classifier);
if(nat32info)
native32 += actualPath(nat32info->path);
auto nat64info = m_mojangDownloads->getDownloadInfo(nat64Classifier);
if(nat64info)
native64 += actualPath(nat64info->path);
}
else
retval.append(storage);
return retval;
{
native += actualPath(m_mojangDownloads->getDownloadInfo(nativeClassifier)->path);
}
}
}
else
{
QString raw_storage = storageSuffix(system);
if(isNative())
{
if (raw_storage.contains("${arch}"))
{
auto nat32Storage = raw_storage;
nat32Storage.replace("${arch}", "32");
auto nat64Storage = raw_storage;
nat64Storage.replace("${arch}", "64");
native32 += actualPath(nat32Storage);
native64 += actualPath(nat64Storage);
}
else
{
native += actualPath(raw_storage);
}
}
else
{
jar += actualPath(raw_storage);
}
}
}
bool Library::filesExist(const QDir &base) const
QList<NetActionPtr> Library::getDownloads(OpSys system, HttpMetaCache * cache, QStringList &failedFiles) const
{
auto libFiles = files();
for(auto file: libFiles)
QList<NetActionPtr> out;
bool isLocal = (hint() == "local");
bool isForge = (hint() == "forge-pack-xz");
auto add_download = [&](QString storage, QString dl)
{
QFileInfo info(base, file);
qWarning() << info.absoluteFilePath() << "doesn't exist";
if (!info.exists())
auto entry = cache->resolveEntry("libraries", storage);
if (!entry->isStale())
return true;
if(isLocal)
{
QFileInfo fileinfo(entry->getFullPath());
if(!fileinfo.exists())
{
failedFiles.append(entry->getFullPath());
return false;
}
return true;
}
QString Library::url() const
if (isForge)
{
if (!m_absolute_url.isEmpty())
{
return m_absolute_url;
}
if (m_base_url.isEmpty())
{
return QString("https://" + URLConstants::LIBRARY_BASE) + storageSuffix();
}
if(m_base_url.endsWith('/'))
{
return m_base_url + storageSuffix();
out.append(ForgeXzDownload::make(storage, entry));
}
else
{
return m_base_url + QChar('/') + storageSuffix();
out.append(CacheDownload::make(dl, entry));
}
return true;
};
if(m_mojangDownloads)
{
if(m_mojangDownloads->artifact)
{
auto artifact = m_mojangDownloads->artifact;
add_download(artifact->path, artifact->url);
}
if(m_nativeClassifiers.contains(system))
{
auto nativeClassifier = m_nativeClassifiers[system];
if(nativeClassifier.contains("${arch}"))
{
auto nat32Classifier = nativeClassifier;
nat32Classifier.replace("${arch}", "32");
auto nat64Classifier = nativeClassifier;
nat64Classifier.replace("${arch}", "64");
auto nat32info = m_mojangDownloads->getDownloadInfo(nat32Classifier);
if(nat32info)
add_download(nat32info->path, nat32info->url);
auto nat64info = m_mojangDownloads->getDownloadInfo(nat64Classifier);
if(nat64info)
add_download(nat64info->path, nat64info->url);
}
else
{
auto info = m_mojangDownloads->getDownloadInfo(nativeClassifier);
if(info)
{
add_download(info->path, info->url);
}
}
}
}
else
{
QString raw_storage = storageSuffix(system);
auto raw_dl = [&](){
if (!m_absoluteURL.isEmpty())
{
return m_absoluteURL;
}
if (m_repositoryURL.isEmpty())
{
return QString("https://" + URLConstants::LIBRARY_BASE) + raw_storage;
}
if(m_repositoryURL.endsWith('/'))
{
return m_repositoryURL + raw_storage;
}
else
{
return m_repositoryURL + QChar('/') + raw_storage;
}
}();
if (raw_storage.contains("${arch}"))
{
QString cooked_storage = raw_storage;
QString cooked_dl = raw_dl;
add_download(cooked_storage.replace("${arch}", "32"), cooked_dl.replace("${arch}", "32"));
cooked_storage = raw_storage;
cooked_dl = raw_dl;
add_download(cooked_storage.replace("${arch}", "64"), cooked_dl.replace("${arch}", "64"));
}
else
{
add_download(raw_storage, raw_dl);
}
}
return out;
}
bool Library::isActive() const
@ -74,7 +193,7 @@ bool Library::isActive() const
}
if (isNative())
{
result = result && m_native_classifiers.contains(currentSystem);
result = result && m_nativeClassifiers.contains(currentSystem);
}
return result;
}
@ -98,7 +217,7 @@ QString Library::storagePrefix() const
return m_storagePrefix;
}
QString Library::storageSuffix() const
QString Library::storageSuffix(OpSys system) const
{
// non-native? use only the gradle specifier
if (!isNative())
@ -108,9 +227,9 @@ QString Library::storageSuffix() const
// otherwise native, override classifiers. Mojang HACK!
GradleSpecifier nativeSpec = m_name;
if (m_native_classifiers.contains(currentSystem))
if (m_nativeClassifiers.contains(system))
{
nativeSpec.setClassifier(m_native_classifiers[currentSystem]);
nativeSpec.setClassifier(m_nativeClassifiers[system]);
}
else
{
@ -118,13 +237,3 @@ QString Library::storageSuffix() const
}
return nativeSpec.toPath();
}
QString Library::storagePath() const
{
return FS::PathCombine(storagePrefix(), storageSuffix());
}
bool Library::storagePathIsDefault() const
{
return m_storagePrefix.isEmpty();
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <QString>
#include <net/NetAction.h>
#include <QPair>
#include <QList>
#include <QStringList>
@ -12,16 +13,19 @@
#include "minecraft/OpSys.h"
#include "GradleSpecifier.h"
#include "net/URLConstants.h"
#include "MojangDownloadInfo.h"
#include "multimc_logic_export.h"
struct MojangLibraryDownloadInfo;
class Library;
typedef std::shared_ptr<Library> LibraryPtr;
class Library
class MULTIMC_LOGIC_EXPORT Library
{
friend class OneSixVersionFormat;
friend class MojangVersionFormat;
friend class LibraryTest;
public:
Library()
{
@ -35,13 +39,14 @@ public:
{
auto newlib = std::make_shared<Library>();
newlib->m_name = base->m_name;
newlib->m_base_url = base->m_base_url;
newlib->m_repositoryURL = base->m_repositoryURL;
newlib->m_hint = base->m_hint;
newlib->m_absolute_url = base->m_absolute_url;
newlib->extract_excludes = base->extract_excludes;
newlib->m_native_classifiers = base->m_native_classifiers;
newlib->m_absoluteURL = base->m_absoluteURL;
newlib->m_extractExcludes = base->m_extractExcludes;
newlib->m_nativeClassifiers = base->m_nativeClassifiers;
newlib->m_rules = base->m_rules;
newlib->m_storagePrefix = base->m_storagePrefix;
newlib->m_mojangDownloads = base->m_mojangDownloads;
return newlib;
}
@ -83,45 +88,27 @@ public: /* methods */
/// Returns true if the library is native
bool isNative() const
{
return m_native_classifiers.size() != 0;
return m_nativeClassifiers.size() != 0;
}
void setStoragePrefix(QString prefix = QString());
/// the default storage prefix used by MultiMC
static QString defaultStoragePrefix();
bool storagePathIsDefault() const;
/// Get the prefix - root of the storage to be used
QString storagePrefix() const;
/// Get the relative path where the library should be saved
QString storageSuffix() const;
/// Get the absolute path where the library should be saved
QString storagePath() const;
/// Set the url base for downloads
void setBaseUrl(const QString &base_url)
void setRepositoryURL(const QString &base_url)
{
m_base_url = base_url;
m_repositoryURL = base_url;
}
/// List of files this library describes. Required because of platform-specificness of native libs
QStringList files() const;
/// List Shortcut for checking if all the above files exist
bool filesExist(const QDir &base) const;
void getApplicableFiles(OpSys system, QStringList & jar, QStringList & native, QStringList & native32, QStringList & native64) const;
void setAbsoluteUrl(const QString &absolute_url)
{
m_absolute_url = absolute_url;
m_absoluteURL = absolute_url;
}
QString absoluteUrl() const
void setMojangDownloadInfo(MojangLibraryDownloadInfo::Ptr info)
{
return m_absolute_url;
m_mojangDownloads = info;
}
void setHint(const QString &hint)
@ -129,11 +116,6 @@ public: /* methods */
m_hint = hint;
}
QString hint() const
{
return m_hint;
}
/// Set the load rules
void setRules(QList<std::shared_ptr<Rule>> rules)
{
@ -143,22 +125,33 @@ public: /* methods */
/// Returns true if the library should be loaded (or extracted, in case of natives)
bool isActive() const;
/// Get the URL to download the library from
QString url() const;
// Get a list of downloads for this library
QList<NetActionPtr> getDownloads(OpSys system, class HttpMetaCache * cache, QStringList &failedFiles) const;
private: /* methods */
/// the default storage prefix used by MultiMC
static QString defaultStoragePrefix();
/// Get the prefix - root of the storage to be used
QString storagePrefix() const;
/// Get the relative path where the library should be saved
QString storageSuffix(OpSys system) const;
QString hint() const
{
return m_hint;
}
protected: /* data */
/// the basic gradle dependency specifier.
GradleSpecifier m_name;
/// where to store the lib locally
QString m_storage_path;
/// is this lib actually active on the current OS?
bool m_is_active = false;
/// DEPRECATED URL prefix of the maven repo where the file can be downloaded
QString m_base_url;
QString m_repositoryURL;
/// DEPRECATED: MultiMC-specific absolute URL. takes precedence over the implicit maven repo URL, if defined
QString m_absolute_url;
QString m_absoluteURL;
/**
* MultiMC-specific type hint - modifies how the library is treated
@ -172,13 +165,13 @@ protected: /* data */
QString m_storagePrefix;
/// true if the library had an extract/excludes section (even empty)
bool applyExcludes = false;
bool m_hasExcludes = false;
/// a list of files that shouldn't be extracted from the library
QStringList extract_excludes;
QStringList m_extractExcludes;
/// native suffixes per OS
QMap<OpSys, QString> m_native_classifiers;
QMap<OpSys, QString> m_nativeClassifiers;
/// true if the library had a rules section (even empty)
bool applyRules = false;
@ -187,5 +180,5 @@ protected: /* data */
QList<std::shared_ptr<Rule>> m_rules;
/// MOJANG: container with Mojang style download info
std::shared_ptr<MojangLibraryDownloadInfo> m_mojang_downloads;
MojangLibraryDownloadInfo::Ptr m_mojangDownloads;
};

View File

@ -14,6 +14,7 @@
*/
#include <QFile>
#include <QCryptographicHash>
#include <Version.h>
#include <QDir>
#include <QJsonDocument>
@ -68,9 +69,9 @@ void MinecraftProfile::clear()
m_mainClass.clear();
m_appletClass.clear();
m_libraries.clear();
m_nativeLibraries.clear();
m_traits.clear();
m_jarMods.clear();
mojangDownloads.clear();
m_problemSeverity = ProblemSeverity::PROBLEM_NONE;
}
@ -428,6 +429,18 @@ void MinecraftProfile::applyMinecraftAssets(MojangAssetIndexInfo::Ptr assets)
}
}
void MinecraftProfile::applyMojangDownload(const QString &key, MojangDownloadInfo::Ptr download)
{
if(download)
{
mojangDownloads[key] = download;
}
else
{
mojangDownloads.remove(key);
}
}
void MinecraftProfile::applyTraits(const QSet<QString>& traits)
{
this->m_traits.unite(traits);
@ -466,35 +479,24 @@ static int findLibraryByName(QList<LibraryPtr> haystack, const GradleSpecifier &
void MinecraftProfile::applyLibrary(LibraryPtr library)
{
auto insert = [&](QList<LibraryPtr> & into)
{
// find the library by name.
const int index = findLibraryByName(into, library->rawName());
// library not found? just add it.
if (index < 0)
{
into.append(Library::limitedCopy(library));
return;
}
auto existingLibrary = into.at(index);
// if we are higher it means we should update
if (Version(library->version()) > Version(existingLibrary->version()))
{
auto libraryCopy = Library::limitedCopy(library);
into.replace(index, libraryCopy);
}
};
if(!library->isActive())
{
return;
}
if(library->isNative())
// find the library by name.
const int index = findLibraryByName(m_libraries, library->rawName());
// library not found? just add it.
if (index < 0)
{
insert(m_nativeLibraries);
m_libraries.append(Library::limitedCopy(library));
return;
}
else
auto existingLibrary = m_libraries.at(index);
// if we are higher it means we should update
if (Version(library->version()) > Version(existingLibrary->version()))
{
insert(m_libraries);
auto libraryCopy = Library::limitedCopy(library);
m_libraries.replace(index, libraryCopy);
}
}
@ -571,11 +573,20 @@ const QList<LibraryPtr> & MinecraftProfile::getLibraries() const
return m_libraries;
}
const QList<LibraryPtr> & MinecraftProfile::getNativeLibraries() const
QString MinecraftProfile::getMainJarUrl() const
{
return m_nativeLibraries;
auto iter = mojangDownloads.find("client");
if(iter != mojangDownloads.end())
{
// current
return iter.value()->url;
}
else
{
// legacy fallback
return URLConstants::getLegacyJarUrl(getMinecraftVersion());
}
}
void MinecraftProfile::installJarMods(QStringList selectedFiles)
{

View File

@ -97,6 +97,7 @@ public: /* application of profile variables from patches */
void applyJarMods(const QList<JarmodPtr> &jarMods);
void applyLibrary(LibraryPtr library);
void applyProblemSeverity(ProblemSeverity severity);
void applyMojangDownload(const QString & key, MojangDownloadInfo::Ptr download);
public: /* getters for profile variables */
QString getMinecraftVersion() const;
@ -109,7 +110,7 @@ public: /* getters for profile variables */
const QStringList & getTweakers() const;
const QList<JarmodPtr> & getJarMods() const;
const QList<LibraryPtr> & getLibraries() const;
const QList<LibraryPtr> & getNativeLibraries() const;
QString getMainJarUrl() const;
bool hasTrait(const QString & trait) const;
ProblemSeverity getProblemSeverity() const;
@ -139,6 +140,9 @@ private: /* data */
/// Assets type - "legacy" or a version ID
MojangAssetIndexInfo::Ptr m_minecraftAssets;
// Mojang: list of 'downloads' - client jar, server jar, windows server exe, maybe more.
QMap <QString, std::shared_ptr<MojangDownloadInfo>> mojangDownloads;
/**
* arguments that should be used for launching minecraft
*
@ -159,9 +163,6 @@ private: /* data */
/// the list of libraries
QList<LibraryPtr> m_libraries;
/// the list of native libraries
QList<LibraryPtr> m_nativeLibraries;
/// traits, collected from all the version files (version files can only add)
QSet<QString> m_traits;

View File

@ -72,10 +72,12 @@ void MinecraftVersion::applyFileTo(MinecraftProfile *profile)
QString MinecraftVersion::getUrl() const
{
// legacy fallback
if(m_versionFileURL.isEmpty())
{
return QString("http://") + URLConstants::AWS_DOWNLOAD_VERSIONS + m_descriptor + "/" + m_descriptor + ".json";
}
// current
return m_versionFileURL;
}

View File

@ -470,8 +470,7 @@ void MCVListVersionUpdateTask::executeTask()
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)));
connect(specificVersionDownloadJob.get(), SIGNAL(progress(qint64, qint64)), SIGNAL(progress(qint64, qint64)));
specificVersionDownloadJob->start();
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <QString>
#include <QMap>
#include <memory>
struct MojangDownloadInfo
@ -22,6 +23,9 @@ struct MojangDownloadInfo
struct MojangLibraryDownloadInfo
{
MojangLibraryDownloadInfo(MojangDownloadInfo::Ptr artifact): artifact(artifact) {};
MojangLibraryDownloadInfo() {};
// types
typedef std::shared_ptr<MojangLibraryDownloadInfo> Ptr;

View File

@ -8,7 +8,7 @@
using namespace Json;
#include "ParseUtils.h"
static const int CURRENT_MINIMUM_LAUNCHER_VERSION = 14;
static const int CURRENT_MINIMUM_LAUNCHER_VERSION = 18;
static MojangAssetIndexInfo::Ptr assetIndexFromJson (const QJsonObject &obj);
static MojangDownloadInfo::Ptr downloadInfoFromJson (const QJsonObject &obj);
@ -130,7 +130,7 @@ QJsonObject assetIndexToJson(MojangAssetIndexInfo::Ptr info)
void MojangVersionFormat::readVersionProperties(const QJsonObject &in, VersionFile *out)
{
Bits::readString(in, "id", out->id);
Bits::readString(in, "id", out->minecraftVersion);
Bits::readString(in, "mainClass", out->mainClass);
Bits::readString(in, "minecraftArguments", out->minecraftArguments);
if(out->minecraftArguments.isEmpty())
@ -212,7 +212,7 @@ VersionFilePtr MojangVersionFormat::versionFileFromJson(const QJsonDocument &doc
out->name = "Minecraft";
out->fileId = "net.minecraft";
out->version = out->id;
out->version = out->minecraftVersion;
out->filename = filename;
@ -231,7 +231,7 @@ VersionFilePtr MojangVersionFormat::versionFileFromJson(const QJsonDocument &doc
void MojangVersionFormat::writeVersionProperties(const VersionFile* in, QJsonObject& out)
{
writeString(out, "id", in->id);
writeString(out, "id", in->minecraftVersion);
writeString(out, "mainClass", in->mainClass);
writeString(out, "minecraftArguments", in->minecraftArguments);
writeString(out, "type", in->type);
@ -294,14 +294,14 @@ LibraryPtr MojangVersionFormat::libraryFromJson(const QJsonObject &libObj, const
}
out->m_name = libObj.value("name").toString();
Bits::readString(libObj, "url", out->m_base_url);
Bits::readString(libObj, "url", out->m_repositoryURL);
if (libObj.contains("extract"))
{
out->applyExcludes = true;
out->m_hasExcludes = true;
auto extractObj = requireObject(libObj.value("extract"));
for (auto excludeVal : requireArray(extractObj.value("exclude")))
{
out->extract_excludes.append(requireString(excludeVal));
out->m_extractExcludes.append(requireString(excludeVal));
}
}
if (libObj.contains("natives"))
@ -316,7 +316,7 @@ LibraryPtr MojangVersionFormat::libraryFromJson(const QJsonObject &libObj, const
OpSys opSys = OpSys_fromString(it.key());
if (opSys != Os_Other)
{
out->m_native_classifiers[opSys] = it.value().toString();
out->m_nativeClassifiers[opSys] = it.value().toString();
}
}
}
@ -327,7 +327,7 @@ LibraryPtr MojangVersionFormat::libraryFromJson(const QJsonObject &libObj, const
}
if (libObj.contains("downloads"))
{
out->m_mojang_downloads = libDownloadInfoFromJson(libObj);
out->m_mojangDownloads = libDownloadInfoFromJson(libObj);
}
return out;
}
@ -336,27 +336,25 @@ QJsonObject MojangVersionFormat::libraryToJson(Library *library)
{
QJsonObject libRoot;
libRoot.insert("name", (QString)library->m_name);
if (library->m_base_url != "http://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
library->m_base_url != "https://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
library->m_base_url != "https://" + URLConstants::LIBRARY_BASE && !library->m_base_url.isEmpty())
if (!library->m_repositoryURL.isEmpty())
{
libRoot.insert("url", library->m_base_url);
libRoot.insert("url", library->m_repositoryURL);
}
if (library->isNative())
{
QJsonObject nativeList;
auto iter = library->m_native_classifiers.begin();
while (iter != library->m_native_classifiers.end())
auto iter = library->m_nativeClassifiers.begin();
while (iter != library->m_nativeClassifiers.end())
{
nativeList.insert(OpSys_toString(iter.key()), iter.value());
iter++;
}
libRoot.insert("natives", nativeList);
if (library->extract_excludes.size())
if (library->m_extractExcludes.size())
{
QJsonArray excludes;
QJsonObject extract;
for (auto exclude : library->extract_excludes)
for (auto exclude : library->m_extractExcludes)
{
excludes.append(exclude);
}
@ -374,9 +372,9 @@ QJsonObject MojangVersionFormat::libraryToJson(Library *library)
}
libRoot.insert("rules", allRules);
}
if(library->m_mojang_downloads)
if(library->m_mojangDownloads)
{
auto downloadsObj = libDownloadInfoToJson(library->m_mojang_downloads);
auto downloadsObj = libDownloadInfoToJson(library->m_mojangDownloads);
libRoot.insert("downloads", downloadsObj);
}
return libRoot;

View File

@ -25,14 +25,14 @@ bool VersionFile::hasJarMods()
void VersionFile::applyTo(MinecraftProfile *profile)
{
auto theirVersion = profile->getMinecraftVersion();
if (!theirVersion.isNull() && !mcVersion.isNull())
if (!theirVersion.isNull() && !dependsOnMinecraftVersion.isNull())
{
if (QRegExp(mcVersion, Qt::CaseInsensitive, QRegExp::Wildcard).indexIn(theirVersion) == -1)
if (QRegExp(dependsOnMinecraftVersion, Qt::CaseInsensitive, QRegExp::Wildcard).indexIn(theirVersion) == -1)
{
throw MinecraftVersionMismatch(fileId, mcVersion, theirVersion);
throw MinecraftVersionMismatch(fileId, dependsOnMinecraftVersion, theirVersion);
}
}
profile->applyMinecraftVersion(id);
profile->applyMinecraftVersion(minecraftVersion);
profile->applyMainClass(mainClass);
profile->applyAppletClass(appletClass);
profile->applyMinecraftArguments(minecraftArguments);
@ -51,4 +51,10 @@ void VersionFile::applyTo(MinecraftProfile *profile)
profile->applyLibrary(library);
}
profile->applyProblemSeverity(getProblemSeverity());
auto iter = mojangDownloads.begin();
while(iter != mojangDownloads.end())
{
profile->applyMojangDownload(iter.key(), iter.value());
iter++;
}
}

View File

@ -143,13 +143,13 @@ public: /* data */
QString version;
/// MultiMC: dependency on a Minecraft version
QString mcVersion;
QString dependsOnMinecraftVersion;
/// Mojang: used to version the Mojang version format
int minimumLauncherVersion = -1;
/// Mojang: version of Minecraft this is
QString id;
QString minecraftVersion;
/// Mojang: class to launch Minecraft with
QString mainClass;

View File

@ -126,8 +126,8 @@ void ForgeInstaller::prepare(const QString &filename, const QString &universalUr
QCryptographicHash md5sum(QCryptographicHash::Md5);
md5sum.addData(data);
cacheentry->stale = false;
cacheentry->md5sum = md5sum.result().toHex().constData();
cacheentry->setStale(false);
cacheentry->setMD5Sum(md5sum.result().toHex().constData());
ENV.metacache()->updateEntry(cacheentry);
}
file.close();
@ -264,8 +264,8 @@ bool ForgeInstaller::add(OneSixInstance *to)
m_forge_json->name = "Forge";
m_forge_json->fileId = id();
m_forge_json->version = m_forgeVersionString;
m_forge_json->mcVersion = to->intendedVersionId();
m_forge_json->id.clear();
m_forge_json->dependsOnMinecraftVersion = to->intendedVersionId();
m_forge_json->minecraftVersion.clear();
m_forge_json->order = 5;
QSaveFile file(filename(to->instanceRoot()));
@ -378,16 +378,16 @@ protected:
* This fixes some problems with bad files acquired because of unhandled HTTP redirects
* in old versions of MultiMC.
*/
if (!entry->stale)
if (!entry->isStale())
{
QFileInfo localFile(entry->getFullPath());
if (localFile.size() <= 0x4000)
{
entry->stale = true;
entry->setStale(true);
}
}
if (entry->stale)
if (entry->isStale())
{
NetJob *fjob = new NetJob("Forge download");
fjob->addNetAction(CacheDownload::make(forgeVersion->url(), entry));

View File

@ -1,10 +0,0 @@
#pragma once
#include <QString>
struct ForgeMirror
{
QString name;
QString logo_url;
QString website_url;
QString mirror_url;
};

View File

@ -1,118 +0,0 @@
#include "Env.h"
#include "ForgeMirrors.h"
#include <QDebug>
#include <algorithm>
#include <random>
ForgeMirrors::ForgeMirrors(QList<ForgeXzDownloadPtr> &libs, NetJobPtr parent_job,
QString mirrorlist)
{
m_libs = libs;
m_parent_job = parent_job;
m_url = QUrl(mirrorlist);
m_status = Job_NotStarted;
}
void ForgeMirrors::start()
{
qDebug() << "Downloading " << m_url.toString();
QNetworkRequest request(m_url);
request.setHeader(QNetworkRequest::UserAgentHeader, "MultiMC/5.0 (Uncached)");
auto worker = ENV.qnam();
QNetworkReply *rep = worker->get(request);
m_reply.reset(rep);
connect(rep, SIGNAL(downloadProgress(qint64, qint64)),
SLOT(downloadProgress(qint64, qint64)));
connect(rep, SIGNAL(finished()), SLOT(downloadFinished()));
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)),
SLOT(downloadError(QNetworkReply::NetworkError)));
connect(rep, SIGNAL(readyRead()), SLOT(downloadReadyRead()));
}
void ForgeMirrors::downloadError(QNetworkReply::NetworkError error)
{
// error happened during download.
qCritical() << "Error getting URL:" << m_url.toString().toLocal8Bit()
<< "Network error: " << error;
m_status = Job_Failed;
}
void ForgeMirrors::downloadFinished()
{
// if the download succeeded
if (m_status != Job_Failed)
{
// nothing went wrong... ?
parseMirrorList();
return;
}
// else the download failed, we use a fixed list
else
{
m_status = Job_Finished;
m_reply.reset();
deferToFixedList();
return;
}
}
void ForgeMirrors::deferToFixedList()
{
m_mirrors.clear();
m_mirrors.append(
{"Minecraft Forge", "http://files.minecraftforge.net/forge_logo.png",
"http://files.minecraftforge.net/", "http://files.minecraftforge.net/maven/"});
m_mirrors.append({"Creeper Host",
"http://files.minecraftforge.net/forge_logo.png",
"https://www.creeperhost.net/link.php?id=1",
"http://new.creeperrepo.net/forge/maven/"});
injectDownloads();
emit succeeded(m_index_within_job);
}
void ForgeMirrors::parseMirrorList()
{
m_status = Job_Finished;
auto data = m_reply->readAll();
m_reply.reset();
auto dataLines = data.split('\n');
for(auto line: dataLines)
{
auto elements = line.split('!');
if (elements.size() == 4)
{
m_mirrors.append({elements[0],elements[1],elements[2],elements[3]});
}
}
if(!m_mirrors.size())
deferToFixedList();
injectDownloads();
emit succeeded(m_index_within_job);
}
void ForgeMirrors::injectDownloads()
{
// shuffle the mirrors randomly
std::random_device rd;
std::mt19937 rng(rd());
std::shuffle(m_mirrors.begin(), m_mirrors.end(), rng);
// tell parent to download the libs
for(auto lib: m_libs)
{
lib->setMirrors(m_mirrors);
m_parent_job->addNetAction(lib);
}
}
void ForgeMirrors::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
m_total_progress = bytesTotal;
m_progress = bytesReceived;
emit netActionProgress(m_index_within_job, bytesReceived, bytesTotal);
}
void ForgeMirrors::downloadReadyRead()
{
}

View File

@ -1,61 +0,0 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "ForgeXzDownload.h"
#include "net/NetAction.h"
#include "net/HttpMetaCache.h"
#include "net/NetJob.h"
#include <QFile>
#include <QTemporaryFile>
typedef std::shared_ptr<class ForgeMirrors> ForgeMirrorsPtr;
class ForgeMirrors : public NetAction
{
Q_OBJECT
public:
QList<ForgeXzDownloadPtr> m_libs;
NetJobPtr m_parent_job;
QList<ForgeMirror> m_mirrors;
public:
explicit ForgeMirrors(QList<ForgeXzDownloadPtr> &libs, NetJobPtr parent_job,
QString mirrorlist);
static ForgeMirrorsPtr make(QList<ForgeXzDownloadPtr> &libs, NetJobPtr parent_job,
QString mirrorlist)
{
return ForgeMirrorsPtr(new ForgeMirrors(libs, parent_job, mirrorlist));
}
virtual ~ForgeMirrors(){};
protected
slots:
virtual void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
virtual void downloadError(QNetworkReply::NetworkError error);
virtual void downloadFinished();
virtual void downloadReadyRead();
private:
void parseMirrorList();
void deferToFixedList();
void injectDownloads();
public
slots:
virtual void start();
};

View File

@ -128,8 +128,8 @@ void ForgeListLoadTask::executeTask()
auto gradleForgeListEntry = ENV.metacache()->resolveEntry("minecraftforge", "json");
// verify by poking the server.
forgeListEntry->stale = true;
gradleForgeListEntry->stale = true;
forgeListEntry->setStale(true);
gradleForgeListEntry->setStale(true);
job->addNetAction(listDownload = CacheDownload::make(QUrl(URLConstants::FORGE_LEGACY_URL),
forgeListEntry));

View File

@ -30,19 +30,13 @@ ForgeXzDownload::ForgeXzDownload(QString relative_path, MetaEntryPtr entry) : Ne
m_pack200_xz_file.setFileTemplate("./dl_temp.XXXXXX");
m_status = Job_NotStarted;
m_url_path = relative_path;
}
void ForgeXzDownload::setMirrors(QList<ForgeMirror> &mirrors)
{
m_mirror_index = 0;
m_mirrors = mirrors;
updateUrl();
m_url = "http://files.minecraftforge.net/maven/" + m_url_path + ".pack.xz";
}
void ForgeXzDownload::start()
{
m_status = Job_InProgress;
if (!m_entry->stale)
if (!m_entry->isStale())
{
m_status = Job_Finished;
emit succeeded(m_index_within_job);
@ -55,16 +49,10 @@ void ForgeXzDownload::start()
emit failed(m_index_within_job);
return;
}
if (m_mirrors.empty())
{
m_status = Job_Failed;
emit failed(m_index_within_job);
return;
}
qDebug() << "Downloading " << m_url.toString();
QNetworkRequest request(m_url);
request.setRawHeader(QString("If-None-Match").toLatin1(), m_entry->etag.toLatin1());
request.setRawHeader(QString("If-None-Match").toLatin1(), m_entry->getETag().toLatin1());
request.setHeader(QNetworkRequest::UserAgentHeader, "MultiMC/5.0 (Cached)");
auto worker = ENV.qnam();
@ -96,44 +84,11 @@ void ForgeXzDownload::downloadError(QNetworkReply::NetworkError error)
void ForgeXzDownload::failAndTryNextMirror()
{
m_status = Job_Failed;
int next = m_mirror_index + 1;
if(m_mirrors.size() == next)
m_mirror_index = 0;
else
m_mirror_index = next;
updateUrl();
emit failed(m_index_within_job);
}
void ForgeXzDownload::updateUrl()
{
qDebug() << "Updating URL for " << m_url_path;
for (auto possible : m_mirrors)
{
qDebug() << "Possible: " << possible.name << " : " << possible.mirror_url;
}
QString aggregate = m_mirrors[m_mirror_index].mirror_url + m_url_path + ".pack.xz";
m_url = QUrl(aggregate);
}
void ForgeXzDownload::downloadFinished()
{
//TEST: defer to other possible mirrors (autofail the first one)
/*
qDebug() <<"dl " << index_within_job << " mirror " << m_mirror_index;
if( m_mirror_index == 0)
{
qDebug() <<"dl " << index_within_job << " AUTOFAIL";
m_status = Job_Failed;
m_pack200_xz_file.close();
m_pack200_xz_file.remove();
m_reply.reset();
failAndTryNextMirror();
return;
}
*/
// if the download succeeded
if (m_status != Job_Failed)
{
@ -372,16 +327,14 @@ void ForgeXzDownload::decompressAndInstall()
failAndTryNextMirror();
return;
}
m_entry->md5sum = QCryptographicHash::hash(jar_file.readAll(), QCryptographicHash::Md5)
.toHex()
.constData();
auto hash = QCryptographicHash::hash(jar_file.readAll(), QCryptographicHash::Md5);
m_entry->setMD5Sum(hash.toHex().constData());
jar_file.close();
QFileInfo output_file_info(m_target_path);
m_entry->etag = m_reply->rawHeader("ETag").constData();
m_entry->local_changed_timestamp =
output_file_info.lastModified().toUTC().toMSecsSinceEpoch();
m_entry->stale = false;
m_entry->setETag(m_reply->rawHeader("ETag").constData());
m_entry->setLocalChangedTimestamp(output_file_info.lastModified().toUTC().toMSecsSinceEpoch());
m_entry->setStale(false);
ENV.metacache()->updateEntry(m_entry);
m_reply.reset();

View File

@ -19,7 +19,6 @@
#include "net/HttpMetaCache.h"
#include <QFile>
#include <QTemporaryFile>
#include "ForgeMirror.h"
typedef std::shared_ptr<class ForgeXzDownload> ForgeXzDownloadPtr;
@ -32,10 +31,6 @@ public:
QString m_target_path;
/// this is the output file, if any
QTemporaryFile m_pack200_xz_file;
/// mirror index (NOT OPTICS, I SWEAR)
int m_mirror_index = 0;
/// list of mirrors to use. Mirror has the url base
QList<ForgeMirror> m_mirrors;
/// path relative to the mirror base
QString m_url_path;
@ -46,7 +41,6 @@ public:
return ForgeXzDownloadPtr(new ForgeXzDownload(relative_path, entry));
}
virtual ~ForgeXzDownload(){};
void setMirrors(QList<ForgeMirror> & mirrors);
protected
slots:
@ -62,5 +56,4 @@ slots:
private:
void decompressAndInstall();
void failAndTryNextMirror();
void updateUrl();
};

View File

@ -59,7 +59,7 @@ void FTBProfileStrategy::loadDefaultBuiltinPatches()
auto file = ProfileUtils::parseJsonFile(QFileInfo(mcJson), false);
// adapt the loaded file - the FTB patch file format is different than ours.
file->id.clear();
file->minecraftVersion.clear();
for(auto addLib: file->libraries)
{
addLib->setHint("local");

View File

@ -367,14 +367,12 @@ void LegacyUpdate::jarStart()
setStatus(tr("Downloading new minecraft.jar ..."));
QString version_id = inst->intendedVersionId();
QString localPath = version_id + "/" + version_id + ".jar";
QString urlstr = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + localPath;
auto dljob = new NetJob("Minecraft.jar for version " + version_id);
auto metacache = ENV.metacache();
auto entry = metacache->resolveEntry("versions", localPath);
dljob->addNetAction(CacheDownload::make(QUrl(urlstr), entry));
auto entry = metacache->resolveEntry("versions", URLConstants::getJarPath(version_id));
dljob->addNetAction(CacheDownload::make(QUrl(URLConstants::getLegacyJarUrl(version_id)), entry));
connect(dljob, SIGNAL(succeeded()), SLOT(jarFinished()));
connect(dljob, SIGNAL(failed(QString)), SLOT(jarFailed(QString)));
connect(dljob, SIGNAL(progress(qint64, qint64)), SIGNAL(progress(qint64, qint64)));

View File

@ -144,7 +144,7 @@ void LLListLoadTask::executeTask()
auto liteloaderEntry = ENV.metacache()->resolveEntry("liteloader", "versions.json");
// verify by poking the server.
liteloaderEntry->stale = true;
liteloaderEntry->setStale(true);
job->addNetAction(listDownload = CacheDownload::make(QUrl(URLConstants::LITELOADER_URL),
liteloaderEntry));
@ -251,7 +251,7 @@ void LLListLoadTask::listDownloaded()
// hack to make liteloader 1.7.10_00 work
if(lib->rawName() == GradleSpecifier("org.ow2.asm:asm-all:5.0.3"))
{
lib->setBaseUrl("http://repo.maven.apache.org/maven2/");
lib->setRepositoryURL("http://repo.maven.apache.org/maven2/");
}
version->libraries.append(lib);
}

View File

@ -180,24 +180,6 @@ QString OneSixInstance::createLaunchScript(AuthSessionPtr session)
launchScript += "jarmod " + jarmod->originalName + " (" + jarmod->name + ")\n";
}
// libraries and class path.
{
auto libs = m_profile->getLibraries();
for (auto lib : libs)
{
launchScript += "cp " + QFileInfo(lib->storagePath()).absoluteFilePath() + "\n";
}
auto jarMods = getJarMods();
if (!jarMods.isEmpty())
{
launchScript += "cp " + QDir(instanceRoot()).absoluteFilePath("minecraft.jar") + "\n";
}
else
{
QString relpath = m_profile->getMinecraftVersion() + "/" + m_profile->getMinecraftVersion() + ".jar";
launchScript += "cp " + versionsPath().absoluteFilePath(relpath) + "\n";
}
}
auto mainClass = m_profile->getMainClass();
if (!mainClass.isEmpty())
{
@ -234,15 +216,43 @@ QString OneSixInstance::createLaunchScript(AuthSessionPtr session)
launchScript += "sessionId " + session->session + "\n";
}
// native libraries (mostly LWJGL)
// libraries and class path.
{
QDir natives_dir(FS::PathCombine(instanceRoot(), "natives/"));
for (auto native : m_profile->getNativeLibraries())
auto libs = m_profile->getLibraries();
QStringList jar, native, native32, native64;
for (auto lib : libs)
{
QFileInfo finfo(native->storagePath());
launchScript += "ext " + finfo.absoluteFilePath() + "\n";
lib->getApplicableFiles(currentSystem, jar, native, native32, native64);
}
for(auto file: jar)
{
launchScript += "cp " + file + "\n";
}
for(auto file: native)
{
launchScript += "ext " + file + "\n";
}
for(auto file: native32)
{
launchScript += "ext32 " + file + "\n";
}
for(auto file: native64)
{
launchScript += "ext64 " + file + "\n";
}
QDir natives_dir(FS::PathCombine(instanceRoot(), "natives/"));
launchScript += "natives " + natives_dir.absolutePath() + "\n";
auto jarMods = getJarMods();
if (!jarMods.isEmpty())
{
launchScript += "cp " + QDir(instanceRoot()).absoluteFilePath("minecraft.jar") + "\n";
}
else
{
QString relpath = m_profile->getMinecraftVersion() + "/" + m_profile->getMinecraftVersion() + ".jar";
launchScript += "cp " + versionsPath().absoluteFilePath(relpath) + "\n";
}
}
// traits. including legacyLaunch and others ;)

View File

@ -54,7 +54,7 @@ void OneSixProfileStrategy::upgradeDeprecatedFiles()
auto file = ProfileUtils::parseJsonFile(QFileInfo(sourceFile), false);
ProfileUtils::removeLwjglFromPatch(file);
file->fileId = "net.minecraft";
file->version = file->id;
file->version = file->minecraftVersion;
file->name = "Minecraft";
auto data = OneSixVersionFormat::versionFileToJson(file, false).toJson();
QSaveFile newPatchFile(mcJson);

View File

@ -14,6 +14,7 @@
*/
#include "Env.h"
#include <minecraft/forge/ForgeXzDownload.h>
#include "OneSixUpdate.h"
#include "OneSixInstance.h"
@ -29,7 +30,6 @@
#include "minecraft/MinecraftVersionList.h"
#include "minecraft/MinecraftProfile.h"
#include "minecraft/Library.h"
#include "minecraft/forge/ForgeMirrors.h"
#include "net/URLConstants.h"
#include "minecraft/AssetsUtils.h"
#include "Exception.h"
@ -95,7 +95,7 @@ void OneSixUpdate::assetIndexStart()
auto metacache = ENV.metacache();
auto entry = metacache->resolveEntry("asset_indexes", localPath);
entry->stale = true;
entry->setStale(true);
job->addNetAction(CacheDownload::make(indexUrl, entry));
jarlibDownloadJob.reset(job);
@ -174,88 +174,41 @@ void OneSixUpdate::jarlibStart()
{
QString version_id = profile->getMinecraftVersion();
QString localPath = version_id + "/" + version_id + ".jar";
QString urlstr = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + localPath;
QString urlstr = profile->getMainJarUrl();
auto job = new NetJob(tr("Libraries for instance %1").arg(inst->name()));
auto metacache = ENV.metacache();
auto entry = metacache->resolveEntry("versions", localPath);
job->addNetAction(CacheDownload::make(QUrl(urlstr), entry));
jarHashOnEntry = entry->md5sum;
jarlibDownloadJob.reset(job);
}
auto libs = profile->getNativeLibraries();
libs.append(profile->getLibraries());
auto libs = profile->getLibraries();
auto metacache = ENV.metacache();
QList<ForgeXzDownloadPtr> ForgeLibs;
QList<LibraryPtr> brokenLocalLibs;
QStringList failedFiles;
for (auto lib : libs)
{
if (lib->hint() == "local")
auto dls = lib->getDownloads(currentSystem, metacache.get(), failedFiles);
for(auto dl : dls)
{
if (!lib->filesExist(m_inst->librariesPath()))
brokenLocalLibs.append(lib);
continue;
}
QString raw_storage = lib->storageSuffix();
QString raw_dl = lib->url();
auto f = [&](QString storage, QString dl)
{
auto entry = metacache->resolveEntry("libraries", storage);
if (entry->stale)
{
if (lib->hint() == "forge-pack-xz")
{
ForgeLibs.append(ForgeXzDownload::make(storage, entry));
}
else
{
jarlibDownloadJob->addNetAction(CacheDownload::make(dl, entry));
}
}
};
if (raw_storage.contains("${arch}"))
{
QString cooked_storage = raw_storage;
QString cooked_dl = raw_dl;
f(cooked_storage.replace("${arch}", "32"), cooked_dl.replace("${arch}", "32"));
cooked_storage = raw_storage;
cooked_dl = raw_dl;
f(cooked_storage.replace("${arch}", "64"), cooked_dl.replace("${arch}", "64"));
}
else
{
f(raw_storage, raw_dl);
jarlibDownloadJob->addNetAction(dl);
}
}
if (!brokenLocalLibs.empty())
{
jarlibDownloadJob.reset();
QStringList failed;
for (auto brokenLib : brokenLocalLibs)
{
failed.append(brokenLib->files());
}
QString failed_all = failed.join("\n");
QString failed_all = failedFiles.join("\n");
emitFailed(tr("Some libraries marked as 'local' are missing their jar "
"files:\n%1\n\nYou'll have to correct this problem manually. If this is "
"an externally tracked instance, make sure to run it at least once "
"outside of MultiMC.").arg(failed_all));
return;
}
// TODO: think about how to propagate this from the original json file... or IF AT ALL
QString forgeMirrorList = "http://files.minecraftforge.net/mirror-brand.list";
if (!ForgeLibs.empty())
{
jarlibDownloadJob->addNetAction(
ForgeMirrors::make(ForgeLibs, jarlibDownloadJob, forgeMirrorList));
}
connect(jarlibDownloadJob.get(), SIGNAL(succeeded()), SLOT(jarlibFinished()));
connect(jarlibDownloadJob.get(), &NetJob::failed, this, &OneSixUpdate::jarlibFailed);

View File

@ -63,6 +63,5 @@ private:
std::shared_ptr<Task> versionUpdateTask;
OneSixInstance *m_inst = nullptr;
QString jarHashOnEntry;
QList<FMLlib> fmlLibsToProcess;
};

View File

@ -19,16 +19,16 @@ LibraryPtr OneSixVersionFormat::libraryFromJson(const QJsonObject &libObj, const
{
LibraryPtr out = MojangVersionFormat::libraryFromJson(libObj, filename);
readString(libObj, "MMC-hint", out->m_hint);
readString(libObj, "MMC-absulute_url", out->m_absolute_url);
readString(libObj, "MMC-absoluteUrl", out->m_absolute_url);
readString(libObj, "MMC-absulute_url", out->m_absoluteURL);
readString(libObj, "MMC-absoluteUrl", out->m_absoluteURL);
return out;
}
QJsonObject OneSixVersionFormat::libraryToJson(Library *library)
{
QJsonObject libRoot = MojangVersionFormat::libraryToJson(library);
if (library->m_absolute_url.size())
libRoot.insert("MMC-absoluteUrl", library->m_absolute_url);
if (library->m_absoluteURL.size())
libRoot.insert("MMC-absoluteUrl", library->m_absoluteURL);
if (library->m_hint.size())
libRoot.insert("MMC-hint", library->m_hint);
return libRoot;
@ -64,7 +64,7 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
out->name = root.value("name").toString();
out->fileId = root.value("fileId").toString();
out->version = root.value("version").toString();
out->mcVersion = root.value("mcVersion").toString();
out->dependsOnMinecraftVersion = root.value("mcVersion").toString();
out->filename = filename;
MojangVersionFormat::readVersionProperties(root, out.get());
@ -167,7 +167,7 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch
writeString(root, "name", patch->name);
writeString(root, "fileId", patch->fileId);
writeString(root, "version", patch->version);
writeString(root, "mcVersion", patch->mcVersion);
writeString(root, "mcVersion", patch->dependsOnMinecraftVersion);
MojangVersionFormat::writeVersionProperties(patch.get(), root);

View File

@ -34,7 +34,7 @@ CacheDownload::CacheDownload(QUrl url, MetaEntryPtr entry)
void CacheDownload::start()
{
m_status = Job_InProgress;
if (!m_entry->stale)
if (!m_entry->isStale())
{
m_status = Job_Finished;
emit succeeded(m_index_within_job);
@ -65,11 +65,11 @@ void CacheDownload::start()
QFile current(m_target_path);
if(current.exists() && current.size() != 0)
{
if (m_entry->remote_changed_timestamp.size())
if (m_entry->getRemoteChangedTimestamp().size())
request.setRawHeader(QString("If-Modified-Since").toLatin1(),
m_entry->remote_changed_timestamp.toLatin1());
if (m_entry->etag.size())
request.setRawHeader(QString("If-None-Match").toLatin1(), m_entry->etag.toLatin1());
m_entry->getRemoteChangedTimestamp().toLatin1());
if (m_entry->getETag().size())
request.setRawHeader(QString("If-None-Match").toLatin1(), m_entry->getETag().toLatin1());
}
request.setHeader(QNetworkRequest::UserAgentHeader, "MultiMC/5.0 (Cached)");
@ -138,7 +138,7 @@ void CacheDownload::downloadFinished()
if (m_output_file->commit())
{
m_status = Job_Finished;
m_entry->md5sum = md5sum.result().toHex().constData();
m_entry->setMD5Sum(md5sum.result().toHex().constData());
}
else
{
@ -160,14 +160,13 @@ void CacheDownload::downloadFinished()
QFileInfo output_file_info(m_target_path);
m_entry->etag = m_reply->rawHeader("ETag").constData();
m_entry->setETag(m_reply->rawHeader("ETag").constData());
if (m_reply->hasRawHeader("Last-Modified"))
{
m_entry->remote_changed_timestamp = m_reply->rawHeader("Last-Modified").constData();
m_entry->setRemoteChangedTimestamp(m_reply->rawHeader("Last-Modified").constData());
}
m_entry->local_changed_timestamp =
output_file_info.lastModified().toUTC().toMSecsSinceEpoch();
m_entry->stale = false;
m_entry->setLocalChangedTimestamp(output_file_info.lastModified().toUTC().toMSecsSinceEpoch());
m_entry->setStale(false);
ENV.metacache()->updateEntry(m_entry);
m_reply.reset();

View File

@ -32,7 +32,7 @@
QString MetaEntry::getFullPath()
{
// FIXME: make local?
return FS::PathCombine(ENV.metacache()->getBasePath(base), path);
return FS::PathCombine(basePath, relativePath);
}
HttpMetaCache::HttpMetaCache(QString path) : QObject()
@ -65,8 +65,7 @@ MetaEntryPtr HttpMetaCache::getEntry(QString base, QString resource_path)
return MetaEntryPtr();
}
MetaEntryPtr HttpMetaCache::resolveEntry(QString base, QString resource_path,
QString expected_etag)
MetaEntryPtr HttpMetaCache::resolveEntry(QString base, QString resource_path, QString expected_etag)
{
auto entry = getEntry(base, resource_path);
// it's not present? generate a default stale entry
@ -114,15 +113,16 @@ MetaEntryPtr HttpMetaCache::resolveEntry(QString base, QString resource_path,
}
// entry passed all the checks we cared about.
entry->basePath = getBasePath(base);
return entry;
}
bool HttpMetaCache::updateEntry(MetaEntryPtr stale_entry)
{
if (!m_entries.contains(stale_entry->base))
if (!m_entries.contains(stale_entry->baseId))
{
qCritical() << "Cannot add entry with unknown base: "
<< stale_entry->base.toLocal8Bit();
<< stale_entry->baseId.toLocal8Bit();
return false;
}
if (stale_entry->stale)
@ -130,7 +130,7 @@ bool HttpMetaCache::updateEntry(MetaEntryPtr stale_entry)
qCritical() << "Cannot add stale entry: " << stale_entry->getFullPath().toLocal8Bit();
return false;
}
m_entries[stale_entry->base].entry_list[stale_entry->path] = stale_entry;
m_entries[stale_entry->baseId].entry_list[stale_entry->relativePath] = stale_entry;
SaveEventually();
return true;
}
@ -148,9 +148,10 @@ bool HttpMetaCache::evictEntry(MetaEntryPtr entry)
MetaEntryPtr HttpMetaCache::staleEntry(QString base, QString resource_path)
{
auto foo = new MetaEntry;
foo->base = base;
foo->path = resource_path;
auto foo = new MetaEntry();
foo->baseId = base;
foo->basePath = getBasePath(base);
foo->relativePath = resource_path;
foo->stale = true;
return MetaEntryPtr(foo);
}
@ -177,6 +178,9 @@ QString HttpMetaCache::getBasePath(QString base)
void HttpMetaCache::Load()
{
if(m_index_file.isNull())
return;
QFile index(m_index_file);
if (!index.open(QIODevice::ReadOnly))
return;
@ -206,9 +210,9 @@ void HttpMetaCache::Load()
if (!m_entries.contains(base))
continue;
auto &entrymap = m_entries[base];
auto foo = new MetaEntry;
foo->base = base;
QString path = foo->path = element_obj.value("path").toString();
auto foo = new MetaEntry();
foo->baseId = base;
QString path = foo->relativePath = element_obj.value("path").toString();
foo->md5sum = element_obj.value("md5sum").toString();
foo->etag = element_obj.value("etag").toString();
foo->local_changed_timestamp = element_obj.value("last_changed_timestamp").toDouble();
@ -229,6 +233,8 @@ void HttpMetaCache::SaveEventually()
void HttpMetaCache::SaveNow()
{
if(m_index_file.isNull())
return;
QJsonObject toplevel;
toplevel.insert("version", QJsonValue(QString("1")));
QJsonArray entriesArr;
@ -242,8 +248,8 @@ void HttpMetaCache::SaveNow()
continue;
}
QJsonObject entryObj;
entryObj.insert("base", QJsonValue(entry->base));
entryObj.insert("path", QJsonValue(entry->path));
entryObj.insert("base", QJsonValue(entry->baseId));
entryObj.insert("path", QJsonValue(entry->relativePath));
entryObj.insert("md5sum", QJsonValue(entry->md5sum));
entryObj.insert("etag", QJsonValue(entry->etag));
entryObj.insert("last_changed_timestamp",

View File

@ -23,16 +23,58 @@
class HttpMetaCache;
struct MULTIMC_LOGIC_EXPORT MetaEntry
class MULTIMC_LOGIC_EXPORT MetaEntry
{
QString base;
QString path;
friend class HttpMetaCache;
protected:
MetaEntry() {}
public:
bool isStale()
{
return stale;
}
void setStale(bool stale)
{
this->stale = stale;
}
QString getFullPath();
QString getRemoteChangedTimestamp()
{
return remote_changed_timestamp;
}
void setRemoteChangedTimestamp(QString remote_changed_timestamp)
{
this->remote_changed_timestamp = remote_changed_timestamp;
}
void setLocalChangedTimestamp(qint64 timestamp)
{
local_changed_timestamp = timestamp;
}
QString getETag()
{
return etag;
}
void setETag(QString etag)
{
this->etag = etag;
}
QString getMD5Sum()
{
return md5sum;
}
void setMD5Sum(QString md5sum)
{
this->md5sum = md5sum;
}
protected:
QString baseId;
QString basePath;
QString relativePath;
QString md5sum;
QString etag;
qint64 local_changed_timestamp = 0;
QString remote_changed_timestamp; // QString for now, RFC 2822 encoded time
bool stale = true;
QString getFullPath();
};
typedef std::shared_ptr<MetaEntry> MetaEntryPtr;
@ -42,7 +84,7 @@ class MULTIMC_LOGIC_EXPORT HttpMetaCache : public QObject
Q_OBJECT
public:
// supply path to the cache index file
HttpMetaCache(QString path);
HttpMetaCache(QString path = QString());
~HttpMetaCache();
// get the entry solely from the cache

View File

@ -1,24 +1,16 @@
#include "URLConstants.h"
namespace URLConstants
namespace URLConstants {
QString getLegacyJarUrl(QString version)
{
const QString AWS_DOWNLOAD_BASE("s3.amazonaws.com/Minecraft.Download/");
const QString AWS_DOWNLOAD_VERSIONS(AWS_DOWNLOAD_BASE + "versions/");
const QString AWS_DOWNLOAD_LIBRARIES(AWS_DOWNLOAD_BASE + "libraries/");
const QString AWS_DOWNLOAD_INDEXES(AWS_DOWNLOAD_BASE + "indexes/");
const QString ASSETS_BASE("assets.minecraft.net/");
const QString RESOURCE_BASE("resources.download.minecraft.net/");
const QString LIBRARY_BASE("libraries.minecraft.net/");
//const QString SKINS_BASE("skins.minecraft.net/MinecraftSkins/");
const QString SKINS_BASE("crafatar.com/skins/");
const QString AUTH_BASE("authserver.mojang.com/");
const QString FORGE_LEGACY_URL("http://files.minecraftforge.net/minecraftforge/json");
const QString
FORGE_GRADLE_URL("http://files.minecraftforge.net/maven/net/minecraftforge/forge/json");
const QString MOJANG_STATUS_URL("http://status.mojang.com/check");
const QString MOJANG_STATUS_NEWS_URL("http://status.mojang.com/news");
const QString LITELOADER_URL("http://dl.liteloader.com/versions/versions.json");
const QString IMGUR_BASE_URL("https://api.imgur.com/3/");
const QString FMLLIBS_OUR_BASE_URL("http://files.multimc.org/fmllibs/");
const QString FMLLIBS_FORGE_BASE_URL("http://files.minecraftforge.net/fmllibs/");
const QString TRANSLATIONS_BASE_URL("http://files.multimc.org/translations/");
return "http://" + AWS_DOWNLOAD_VERSIONS + getJarPath(version);
}
QString getJarPath(QString version)
{
return version + "/" + version + ".jar";
}
}

View File

@ -17,26 +17,24 @@
#include <QString>
#include "multimc_logic_export.h"
namespace URLConstants
{
extern const QString AWS_DOWNLOAD_BASE;
extern const QString AWS_DOWNLOAD_VERSIONS;
extern const QString AWS_DOWNLOAD_LIBRARIES;
extern const QString AWS_DOWNLOAD_INDEXES;
extern const QString ASSETS_BASE;
extern const QString RESOURCE_BASE;
extern const QString LIBRARY_BASE;
MULTIMC_LOGIC_EXPORT extern const QString SKINS_BASE;
extern const QString AUTH_BASE;
extern const QString FORGE_LEGACY_URL;
extern const QString FORGE_GRADLE_URL;
extern const QString MOJANG_STATUS_URL;
extern const QString MOJANG_STATUS_NEWS_URL;
extern const QString LITELOADER_URL;
extern const QString IMGUR_BASE_URL;
extern const QString FMLLIBS_OUR_BASE_URL;
extern const QString FMLLIBS_FORGE_BASE_URL;
extern const QString TRANSLATIONS_BASE_URL;
const QString AWS_DOWNLOAD_VERSIONS("s3.amazonaws.com/Minecraft.Download/versions/");
const QString RESOURCE_BASE("resources.download.minecraft.net/");
const QString LIBRARY_BASE("libraries.minecraft.net/");
//const QString SKINS_BASE("skins.minecraft.net/MinecraftSkins/");
const QString SKINS_BASE("crafatar.com/skins/");
const QString AUTH_BASE("authserver.mojang.com/");
const QString FORGE_LEGACY_URL("http://files.minecraftforge.net/minecraftforge/json");
const QString FORGE_GRADLE_URL("http://files.minecraftforge.net/maven/net/minecraftforge/forge/json");
const QString MOJANG_STATUS_URL("http://status.mojang.com/check");
const QString MOJANG_STATUS_NEWS_URL("http://status.mojang.com/news");
const QString LITELOADER_URL("http://dl.liteloader.com/versions/versions.json");
const QString IMGUR_BASE_URL("https://api.imgur.com/3/");
const QString FMLLIBS_OUR_BASE_URL("http://files.multimc.org/fmllibs/");
const QString FMLLIBS_FORGE_BASE_URL("http://files.minecraftforge.net/fmllibs/");
const QString TRANSLATIONS_BASE_URL("http://files.multimc.org/translations/");
QString getJarPath(QString version);
QString getLegacyJarUrl(QString version);
}

View File

@ -54,7 +54,7 @@ void NotificationChecker::checkForNotifications()
}
m_checkJob.reset(new NetJob("Checking for notifications"));
auto entry = ENV.metacache()->resolveEntry("root", "notifications.json");
entry->stale = true;
entry->setStale(true);
m_checkJob->addNetAction(m_download = CacheDownload::make(m_notificationsUrl, entry));
connect(m_download.get(), &CacheDownload::succeeded, this,
&NotificationChecker::downloadSucceeded);

View File

@ -28,7 +28,7 @@ void TranslationDownloader::indexRecieved()
if (!line.isEmpty())
{
MetaEntryPtr entry = ENV.metacache()->resolveEntry("translations", "mmc_" + line);
entry->stale = true;
entry->setStale(true);
CacheDownloadPtr dl = CacheDownload::make(
QUrl(URLConstants::TRANSLATIONS_BASE_URL + line),
entry);

View File

@ -27,6 +27,7 @@ add_unit_test(userutils tst_userutils.cpp)
add_unit_test(modutils tst_modutils.cpp)
add_unit_test(inifile tst_inifile.cpp)
add_unit_test(FileSystem tst_FileSystem.cpp)
add_unit_test(Library tst_Library.cpp)
add_unit_test(UpdateChecker tst_UpdateChecker.cpp)
add_unit_test(DownloadTask tst_DownloadTask.cpp)
add_unit_test(filematchers tst_filematchers.cpp)

View File

@ -0,0 +1,46 @@
{
"downloads": {
"classifiers": {
"natives-osx": {
"path": "tv/twitch/twitch-platform/5.16/twitch-platform-5.16-natives-osx.jar",
"sha1": "62503ee712766cf77f97252e5902786fd834b8c5",
"size": 418331,
"url": "https://libraries.minecraft.net/tv/twitch/twitch-platform/5.16/twitch-platform-5.16-natives-osx.jar"
},
"natives-windows-32": {
"path": "tv/twitch/twitch-platform/5.16/twitch-platform-5.16-natives-windows-32.jar",
"sha1": "7c6affe439099806a4f552da14c42f9d643d8b23",
"size": 386792,
"url": "https://libraries.minecraft.net/tv/twitch/twitch-platform/5.16/twitch-platform-5.16-natives-windows-32.jar"
},
"natives-windows-64": {
"path": "tv/twitch/twitch-platform/5.16/twitch-platform-5.16-natives-windows-64.jar",
"sha1": "39d0c3d363735b4785598e0e7fbf8297c706a9f9",
"size": 463390,
"url": "https://libraries.minecraft.net/tv/twitch/twitch-platform/5.16/twitch-platform-5.16-natives-windows-64.jar"
}
}
},
"extract": {
"exclude": [
"META-INF/"
]
},
"name": "tv.twitch:twitch-platform:5.16",
"natives": {
"linux": "natives-linux",
"osx": "natives-osx",
"windows": "natives-windows-${arch}"
},
"rules": [
{
"action": "allow"
},
{
"action": "disallow",
"os": {
"name": "linux"
}
}
]
}

View File

@ -0,0 +1,52 @@
{
"downloads": {
"artifact": {
"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar",
"sha1": "b04f3ee8f5e43fa3b162981b50bb72fe1acabb33",
"size": 22,
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar"
},
"classifiers": {
"natives-linux": {
"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-linux.jar",
"sha1": "931074f46c795d2f7b30ed6395df5715cfd7675b",
"size": 578680,
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-linux.jar"
},
"natives-osx": {
"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-osx.jar",
"sha1": "bcab850f8f487c3f4c4dbabde778bb82bd1a40ed",
"size": 426822,
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-osx.jar"
},
"natives-windows": {
"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-windows.jar",
"sha1": "b84d5102b9dbfabfeb5e43c7e2828d98a7fc80e0",
"size": 613748,
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-windows.jar"
}
}
},
"extract": {
"exclude": [
"META-INF/"
]
},
"name": "org.lwjgl.lwjgl:lwjgl-platform:2.9.4-nightly-20150209",
"natives": {
"linux": "natives-linux",
"osx": "natives-osx",
"windows": "natives-windows"
},
"rules": [
{
"action": "allow"
},
{
"action": "disallow",
"os": {
"name": "osx"
}
}
]
}

View File

@ -0,0 +1,11 @@
{
"downloads": {
"artifact": {
"path": "com/paulscode/codecwav/20101023/codecwav-20101023.jar",
"sha1": "12f031cfe88fef5c1dd36c563c0a3a69bd7261da",
"size": 5618,
"url": "https://libraries.minecraft.net/com/paulscode/codecwav/20101023/codecwav-20101023.jar"
}
},
"name": "com.paulscode:codecwav:20101023"
}

195
tests/tst_Library.cpp Normal file
View File

@ -0,0 +1,195 @@
#include <QTest>
#include "TestUtil.h"
#include "minecraft/MojangVersionFormat.h"
#include "minecraft/onesix/OneSixVersionFormat.h"
#include "minecraft/Library.h"
#include "net/HttpMetaCache.h"
#include "FileSystem.h"
class LibraryTest : public QObject
{
Q_OBJECT
private:
LibraryPtr readMojangJson(const char *file)
{
auto path = QFINDTESTDATA(file);
QFile jsonFile(path);
jsonFile.open(QIODevice::ReadOnly);
auto data = jsonFile.readAll();
jsonFile.close();
return MojangVersionFormat::libraryFromJson(QJsonDocument::fromJson(data).object(), file);
}
// get absolute path to expected storage, assuming default cache prefix
QStringList getStorage(QString relative)
{
return {FS::PathCombine(cache->getBasePath("libraries"), relative)};
}
private
slots:
void initTestCase()
{
cache.reset(new HttpMetaCache());
cache->addBase("libraries", QDir("libraries").absolutePath());
}
void test_legacy()
{
Library test("test.package:testname:testversion");
QCOMPARE(test.artifactPrefix(), QString("test.package:testname"));
QCOMPARE(test.isNative(), false);
QStringList jar, native, native32, native64;
test.getApplicableFiles(currentSystem, jar, native, native32, native64);
QCOMPARE(jar, getStorage("test/package/testname/testversion/testname-testversion.jar"));
QCOMPARE(native, {});
QCOMPARE(native32, {});
QCOMPARE(native64, {});
}
void test_legacy_url()
{
QStringList failedFiles;
Library test("test.package:testname:testversion");
test.setRepositoryURL("file://foo/bar");
auto downloads = test.getDownloads(currentSystem, cache.get(), failedFiles);
QCOMPARE(downloads.size(), 1);
QCOMPARE(failedFiles, {});
NetActionPtr dl = downloads[0];
QCOMPARE(dl->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion.jar"));
}
void test_legacy_url_local_broken()
{
Library test("test.package:testname:testversion");
QCOMPARE(test.isNative(), false);
QStringList failedFiles;
test.setHint("local");
auto downloads = test.getDownloads(currentSystem, cache.get(), failedFiles);
QCOMPARE(downloads.size(), 0);
QCOMPARE(failedFiles, getStorage("test/package/testname/testversion/testname-testversion.jar"));
}
void test_legacy_native()
{
Library test("test.package:testname:testversion");
test.m_nativeClassifiers[OpSys::Os_Linux]="linux";
QCOMPARE(test.isNative(), true);
test.setRepositoryURL("file://foo/bar");
{
QStringList jar, native, native32, native64;
test.getApplicableFiles(Os_Linux, jar, native, native32, native64);
QCOMPARE(jar, {});
QCOMPARE(native, getStorage("test/package/testname/testversion/testname-testversion-linux.jar"));
QCOMPARE(native32, {});
QCOMPARE(native64, {});
QStringList failedFiles;
auto dls = test.getDownloads(Os_Linux, cache.get(), failedFiles);
QCOMPARE(dls.size(), 1);
QCOMPARE(failedFiles, {});
auto dl = dls[0];
QCOMPARE(dl->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-linux.jar"));
}
}
void test_legacy_native_arch()
{
Library test("test.package:testname:testversion");
test.m_nativeClassifiers[OpSys::Os_Linux]="linux-${arch}";
test.m_nativeClassifiers[OpSys::Os_OSX]="osx-${arch}";
test.m_nativeClassifiers[OpSys::Os_Windows]="windows-${arch}";
QCOMPARE(test.isNative(), true);
test.setRepositoryURL("file://foo/bar");
{
QStringList jar, native, native32, native64;
test.getApplicableFiles(Os_Linux, jar, native, native32, native64);
QCOMPARE(jar, {});
QCOMPARE(native, {});
QCOMPARE(native32, getStorage("test/package/testname/testversion/testname-testversion-linux-32.jar"));
QCOMPARE(native64, getStorage("test/package/testname/testversion/testname-testversion-linux-64.jar"));
QStringList failedFiles;
auto dls = test.getDownloads(Os_Linux, cache.get(), failedFiles);
QCOMPARE(dls.size(), 2);
QCOMPARE(failedFiles, {});
QCOMPARE(dls[0]->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-linux-32.jar"));
QCOMPARE(dls[1]->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-linux-64.jar"));
}
{
QStringList jar, native, native32, native64;
test.getApplicableFiles(Os_Windows, jar, native, native32, native64);
QCOMPARE(jar, {});
QCOMPARE(native, {});
QCOMPARE(native32, getStorage("test/package/testname/testversion/testname-testversion-windows-32.jar"));
QCOMPARE(native64, getStorage("test/package/testname/testversion/testname-testversion-windows-64.jar"));
QStringList failedFiles;
auto dls = test.getDownloads(Os_Windows, cache.get(), failedFiles);
QCOMPARE(dls.size(), 2);
QCOMPARE(failedFiles, {});
QCOMPARE(dls[0]->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-windows-32.jar"));
QCOMPARE(dls[1]->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-windows-64.jar"));
}
{
QStringList jar, native, native32, native64;
test.getApplicableFiles(Os_OSX, jar, native, native32, native64);
QCOMPARE(jar, {});
QCOMPARE(native, {});
QCOMPARE(native32, getStorage("test/package/testname/testversion/testname-testversion-osx-32.jar"));
QCOMPARE(native64, getStorage("test/package/testname/testversion/testname-testversion-osx-64.jar"));
QStringList failedFiles;
auto dls = test.getDownloads(Os_OSX, cache.get(), failedFiles);
QCOMPARE(dls.size(), 2);
QCOMPARE(failedFiles, {});
QCOMPARE(dls[0]->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-osx-32.jar"));
QCOMPARE(dls[1]->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-osx-64.jar"));
}
}
void test_onenine()
{
auto test = readMojangJson("data/lib-simple.json");
QStringList jar, native, native32, native64;
test->getApplicableFiles(Os_OSX, jar, native, native32, native64);
QCOMPARE(jar, getStorage("com/paulscode/codecwav/20101023/codecwav-20101023.jar"));
QCOMPARE(native, {});
QCOMPARE(native32, {});
QCOMPARE(native64, {});
QStringList failedFiles;
auto dls = test->getDownloads(Os_Linux, cache.get(), failedFiles);
QCOMPARE(dls.size(), 1);
QCOMPARE(failedFiles, {});
QCOMPARE(dls[0]->m_url, QUrl("https://libraries.minecraft.net/com/paulscode/codecwav/20101023/codecwav-20101023.jar"));
}
void test_onenine_native()
{
auto test = readMojangJson("data/lib-native.json");
QStringList jar, native, native32, native64;
test->getApplicableFiles(Os_OSX, jar, native, native32, native64);
QCOMPARE(jar, getStorage("org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar"));
QCOMPARE(native, getStorage("org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-osx.jar"));
QCOMPARE(native32, {});
QCOMPARE(native64, {});
QStringList failedFiles;
auto dls = test->getDownloads(Os_OSX, cache.get(), failedFiles);
QCOMPARE(dls.size(), 2);
QCOMPARE(failedFiles, {});
QCOMPARE(dls[0]->m_url, QUrl("https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar"));
QCOMPARE(dls[1]->m_url, QUrl("https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-osx.jar"));
}
void test_onenine_native_arch()
{
auto test = readMojangJson("data/lib-native-arch.json");
QStringList jar, native, native32, native64;
test->getApplicableFiles(Os_Windows, jar, native, native32, native64);
QCOMPARE(jar, {});
QCOMPARE(native, {});
QCOMPARE(native32, getStorage("tv/twitch/twitch-platform/5.16/twitch-platform-5.16-natives-windows-32.jar"));
QCOMPARE(native64, getStorage("tv/twitch/twitch-platform/5.16/twitch-platform-5.16-natives-windows-64.jar"));
QStringList failedFiles;
auto dls = test->getDownloads(Os_Windows, cache.get(), failedFiles);
QCOMPARE(dls.size(), 2);
QCOMPARE(failedFiles, {});
QCOMPARE(dls[0]->m_url, QUrl("https://libraries.minecraft.net/tv/twitch/twitch-platform/5.16/twitch-platform-5.16-natives-windows-32.jar"));
QCOMPARE(dls[1]->m_url, QUrl("https://libraries.minecraft.net/tv/twitch/twitch-platform/5.16/twitch-platform-5.16-natives-windows-64.jar"));
}
private:
std::unique_ptr<HttpMetaCache> cache;
QString workDir;
};
QTEST_GUILESS_MAIN(LibraryTest)
#include "tst_Library.moc"