NOISSUE finalize support for new mojang version format
This commit is contained in:
parent
d587720010
commit
f032e32133
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include <QString>
|
||||
|
||||
struct ForgeMirror
|
||||
{
|
||||
QString name;
|
||||
QString logo_url;
|
||||
QString website_url;
|
||||
QString mirror_url;
|
||||
};
|
@ -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()
|
||||
{
|
||||
}
|
@ -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();
|
||||
};
|
@ -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));
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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");
|
||||
|
@ -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)));
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 ;)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -63,6 +63,5 @@ private:
|
||||
std::shared_ptr<Task> versionUpdateTask;
|
||||
|
||||
OneSixInstance *m_inst = nullptr;
|
||||
QString jarHashOnEntry;
|
||||
QList<FMLlib> fmlLibsToProcess;
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
46
tests/data/lib-native-arch.json
Normal file
46
tests/data/lib-native-arch.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
52
tests/data/lib-native.json
Normal file
52
tests/data/lib-native.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
11
tests/data/lib-simple.json
Normal file
11
tests/data/lib-simple.json
Normal 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
195
tests/tst_Library.cpp
Normal 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"
|
Loading…
Reference in New Issue
Block a user